summaryrefslogtreecommitdiff
path: root/songdbj/org/tritonus/share
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/org/tritonus/share')
-rw-r--r--songdbj/org/tritonus/share/ArraySet.java87
-rw-r--r--songdbj/org/tritonus/share/GlobalInfo.java60
-rw-r--r--songdbj/org/tritonus/share/StringHashedSet.java112
-rw-r--r--songdbj/org/tritonus/share/TCircularBuffer.java268
-rw-r--r--songdbj/org/tritonus/share/TDebug.java192
-rw-r--r--songdbj/org/tritonus/share/TNotifier.java140
-rw-r--r--songdbj/org/tritonus/share/TSettings.java75
-rw-r--r--songdbj/org/tritonus/share/package.html10
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFileTypes.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormatSet.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormats.java131
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioSystemShadow.java115
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioUtils.java181
-rw-r--r--songdbj/org/tritonus/share/sampled/Encodings.java183
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java734
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleTools.java696
-rw-r--r--songdbj/org/tritonus/share/sampled/TAudioFormat.java110
-rw-r--r--songdbj/org/tritonus/share/sampled/TConversionTool.java1224
-rw-r--r--songdbj/org/tritonus/share/sampled/TVolumeUtils.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java256
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java120
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java129
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java170
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java182
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java367
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java271
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/package.html17
-rw-r--r--songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java58
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java510
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java484
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java197
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java79
-rw-r--r--songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java84
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java109
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java86
-rw-r--r--songdbj/org/tritonus/share/sampled/file/package.html18
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java107
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java128
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TClip.java340
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java90
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControlController.java98
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControllable.java62
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TDataLine.java304
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java92
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java134
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TLine.java362
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixer.java506
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java56
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java240
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TPort.java77
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java318
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/package.html14
-rw-r--r--songdbj/org/tritonus/share/sampled/package.html10
56 files changed, 0 insertions, 11039 deletions
diff --git a/songdbj/org/tritonus/share/ArraySet.java b/songdbj/org/tritonus/share/ArraySet.java
deleted file mode 100644
index 5aa677364f..0000000000
--- a/songdbj/org/tritonus/share/ArraySet.java
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 * ArraySet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 -2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Set;
36
37
38
39public class ArraySet<E>
40extends ArrayList<E>
41implements Set<E>
42{
43 public ArraySet()
44 {
45 super();
46 }
47
48
49
50 public ArraySet(Collection<E> c)
51 {
52 this();
53 addAll(c);
54 }
55
56
57
58 public boolean add(E element)
59 {
60 if (!contains(element))
61 {
62 super.add(element);
63 return true;
64 }
65 else
66 {
67 return false;
68 }
69 }
70
71
72
73 public void add(int index, E element)
74 {
75 throw new UnsupportedOperationException("ArraySet.add(int index, Object element) unsupported");
76 }
77
78 public E set(int index, E element)
79 {
80 throw new UnsupportedOperationException("ArraySet.set(int index, Object element) unsupported");
81 }
82
83}
84
85
86
87/*** ArraySet.java ***/
diff --git a/songdbj/org/tritonus/share/GlobalInfo.java b/songdbj/org/tritonus/share/GlobalInfo.java
deleted file mode 100644
index 9a44c9c870..0000000000
--- a/songdbj/org/tritonus/share/GlobalInfo.java
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * GlobalInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class GlobalInfo
38{
39 private static final String VENDOR = "Tritonus is free software. See http://www.tritonus.org/";
40 private static final String VERSION = "0.3.1";
41
42
43
44 public static String getVendor()
45 {
46 return VENDOR;
47 }
48
49
50
51 public static String getVersion()
52 {
53 return VERSION;
54 }
55}
56
57
58
59/*** GlobalInfo.java ***/
60
diff --git a/songdbj/org/tritonus/share/StringHashedSet.java b/songdbj/org/tritonus/share/StringHashedSet.java
deleted file mode 100644
index 8e244665fb..0000000000
--- a/songdbj/org/tritonus/share/StringHashedSet.java
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 * StringHashedSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import org.tritonus.share.ArraySet;
38
39
40/**
41 * A set where the elements are uniquely referenced by their
42 * string representation as given by the objects toString()
43 * method. No 2 objects with the same toString() can
44 * be in the set.
45 * <p>
46 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
47 * methods can be called with Strings as <code>elem</code> parameter.
48 * For <code>get(Object elem)</code>, the object that has been added
49 * is returned, and not its String representation.
50 * <p>
51 * Though it's possible to store
52 * Strings as objects in this class, it doesn't make sense
53 * as you could use ArraySet for that equally well.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 */
60
61public class StringHashedSet<E> extends ArraySet<E>
62{
63 public StringHashedSet()
64 {
65 super();
66 }
67
68 public StringHashedSet(Collection<E> c)
69 {
70 super(c);
71 }
72
73 public boolean add(E elem)
74 {
75 if (elem==null) {
76 return false;
77 }
78 return super.add(elem);
79 }
80
81 public boolean contains(Object elem)
82 {
83 if (elem==null) {
84 return false;
85 }
86 String comp=elem.toString();
87 Iterator<E> it=iterator();
88 while (it.hasNext()) {
89 if (comp.equals(it.next().toString())) {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 public E get(E elem) {
97 if (elem==null) {
98 return null;
99 }
100 String comp=elem.toString();
101 Iterator<E> it=iterator();
102 while (it.hasNext()) {
103 E thisElem=it.next();
104 if (comp.equals(thisElem.toString())) {
105 return thisElem;
106 }
107 }
108 return null;
109 }
110}
111
112/*** StringHashedSet.java ***/
diff --git a/songdbj/org/tritonus/share/TCircularBuffer.java b/songdbj/org/tritonus/share/TCircularBuffer.java
deleted file mode 100644
index 11ebc0af01..0000000000
--- a/songdbj/org/tritonus/share/TCircularBuffer.java
+++ /dev/null
@@ -1,268 +0,0 @@
1/*
2 * TCircularBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class TCircularBuffer
38{
39 private boolean m_bBlockingRead;
40 private boolean m_bBlockingWrite;
41 private byte[] m_abData;
42 private int m_nSize;
43 private long m_lReadPos;
44 private long m_lWritePos;
45 private Trigger m_trigger;
46 private boolean m_bOpen;
47
48
49
50 public TCircularBuffer(int nSize, boolean bBlockingRead, boolean bBlockingWrite, Trigger trigger)
51 {
52 m_bBlockingRead = bBlockingRead;
53 m_bBlockingWrite = bBlockingWrite;
54 m_nSize = nSize;
55 m_abData = new byte[m_nSize];
56 m_lReadPos = 0;
57 m_lWritePos = 0;
58 m_trigger = trigger;
59 m_bOpen = true;
60 }
61
62
63
64 public void close()
65 {
66 m_bOpen = false;
67 // TODO: call notify() ?
68 }
69
70
71
72 private boolean isOpen()
73 {
74 return m_bOpen;
75 }
76
77
78 public int availableRead()
79 {
80 return (int) (m_lWritePos - m_lReadPos);
81 }
82
83
84
85 public int availableWrite()
86 {
87 return m_nSize - availableRead();
88 }
89
90
91
92 private int getReadPos()
93 {
94 return (int) (m_lReadPos % m_nSize);
95 }
96
97
98
99 private int getWritePos()
100 {
101 return (int) (m_lWritePos % m_nSize);
102 }
103
104
105
106 public int read(byte[] abData)
107 {
108 return read(abData, 0, abData.length);
109 }
110
111
112
113 public int read(byte[] abData, int nOffset, int nLength)
114 {
115 if (TDebug.TraceCircularBuffer)
116 {
117 TDebug.out(">TCircularBuffer.read(): called.");
118 dumpInternalState();
119 }
120 if (! isOpen())
121 {
122 if (availableRead() > 0)
123 {
124 nLength = Math.min(nLength, availableRead());
125 if (TDebug.TraceCircularBuffer) { TDebug.out("reading rest in closed buffer, length: " + nLength); }
126 }
127 else
128 {
129 if (TDebug.TraceCircularBuffer) { TDebug.out("< not open. returning -1."); }
130 return -1;
131 }
132 }
133 synchronized (this)
134 {
135 if (m_trigger != null && availableRead() < nLength)
136 {
137 if (TDebug.TraceCircularBuffer) { TDebug.out("executing trigger."); }
138 m_trigger.execute();
139 }
140 if (!m_bBlockingRead)
141 {
142 nLength = Math.min(availableRead(), nLength);
143 }
144 int nRemainingBytes = nLength;
145 while (nRemainingBytes > 0)
146 {
147 while (availableRead() == 0)
148 {
149 try
150 {
151 wait();
152 }
153 catch (InterruptedException e)
154 {
155 if (TDebug.TraceAllExceptions)
156 {
157 TDebug.out(e);
158 }
159 }
160 }
161 int nAvailable = Math.min(availableRead(), nRemainingBytes);
162 while (nAvailable > 0)
163 {
164 int nToRead = Math.min(nAvailable, m_nSize - getReadPos());
165 System.arraycopy(m_abData, getReadPos(), abData, nOffset, nToRead);
166 m_lReadPos += nToRead;
167 nOffset += nToRead;
168 nAvailable -= nToRead;
169 nRemainingBytes -= nToRead;
170 }
171 notifyAll();
172 }
173 if (TDebug.TraceCircularBuffer)
174 {
175 TDebug.out("After read:");
176 dumpInternalState();
177 TDebug.out("< completed. Read " + nLength + " bytes");
178 }
179 return nLength;
180 }
181 }
182
183
184 public int write(byte[] abData)
185 {
186 return write(abData, 0, abData.length);
187 }
188
189
190
191 public int write(byte[] abData, int nOffset, int nLength)
192 {
193 if (TDebug.TraceCircularBuffer)
194 {
195 TDebug.out(">TCircularBuffer.write(): called; nLength: " + nLength);
196 dumpInternalState();
197 }
198 synchronized (this)
199 {
200 if (TDebug.TraceCircularBuffer) { TDebug.out("entered synchronized block."); }
201 if (!m_bBlockingWrite)
202 {
203 nLength = Math.min(availableWrite(), nLength);
204 }
205 int nRemainingBytes = nLength;
206 while (nRemainingBytes > 0)
207 {
208 while (availableWrite() == 0)
209 {
210 try
211 {
212 wait();
213 }
214 catch (InterruptedException e)
215 {
216 if (TDebug.TraceAllExceptions)
217 {
218 TDebug.out(e);
219 }
220 }
221 }
222 int nAvailable = Math.min(availableWrite(), nRemainingBytes);
223 while (nAvailable > 0)
224 {
225 int nToWrite = Math.min(nAvailable, m_nSize - getWritePos());
226 //TDebug.out("src buf size= " + abData.length + ", offset = " + nOffset + ", dst buf size=" + m_abData.length + " write pos=" + getWritePos() + " len=" + nToWrite);
227 System.arraycopy(abData, nOffset, m_abData, getWritePos(), nToWrite);
228 m_lWritePos += nToWrite;
229 nOffset += nToWrite;
230 nAvailable -= nToWrite;
231 nRemainingBytes -= nToWrite;
232 }
233 notifyAll();
234 }
235 if (TDebug.TraceCircularBuffer)
236 {
237 TDebug.out("After write:");
238 dumpInternalState();
239 TDebug.out("< completed. Wrote "+nLength+" bytes");
240 }
241 return nLength;
242 }
243 }
244
245
246
247 private void dumpInternalState()
248 {
249 TDebug.out("m_lReadPos = " + m_lReadPos + " ^= "+getReadPos());
250 TDebug.out("m_lWritePos = " + m_lWritePos + " ^= "+getWritePos());
251 TDebug.out("availableRead() = " + availableRead());
252 TDebug.out("availableWrite() = " + availableWrite());
253 }
254
255
256
257 public static interface Trigger
258 {
259 public void execute();
260 }
261
262
263}
264
265
266
267/*** TCircularBuffer.java ***/
268
diff --git a/songdbj/org/tritonus/share/TDebug.java b/songdbj/org/tritonus/share/TDebug.java
deleted file mode 100644
index 5969d91a72..0000000000
--- a/songdbj/org/tritonus/share/TDebug.java
+++ /dev/null
@@ -1,192 +0,0 @@
1/*
2 * TDebug.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2002 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share;
30
31import java.io.PrintStream;
32import java.util.StringTokenizer;
33import java.security.AccessControlException;
34
35
36
37public class TDebug
38{
39 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
40 private static final String PROPERTY_PREFIX = "tritonus.";
41 // The stream we output to
42 public static PrintStream m_printStream = System.out;
43
44 private static String indent="";
45
46 // meta-general
47 public static boolean TraceAllExceptions = getBooleanProperty("TraceAllExceptions");
48 public static boolean TraceAllWarnings = getBooleanProperty("TraceAllWarnings");
49
50 // general
51 public static boolean TraceInit = getBooleanProperty("TraceInit");
52 public static boolean TraceCircularBuffer = getBooleanProperty("TraceCircularBuffer");
53 public static boolean TraceService = getBooleanProperty("TraceService");
54
55 // sampled common implementation
56 public static boolean TraceAudioSystem = getBooleanProperty("TraceAudioSystem");
57 public static boolean TraceAudioConfig = getBooleanProperty("TraceAudioConfig");
58 public static boolean TraceAudioInputStream = getBooleanProperty("TraceAudioInputStream");
59 public static boolean TraceMixerProvider = getBooleanProperty("TraceMixerProvider");
60 public static boolean TraceControl = getBooleanProperty("TraceControl");
61 public static boolean TraceLine = getBooleanProperty("TraceLine");
62 public static boolean TraceDataLine = getBooleanProperty("TraceDataLine");
63 public static boolean TraceMixer = getBooleanProperty("TraceMixer");
64 public static boolean TraceSourceDataLine = getBooleanProperty("TraceSourceDataLine");
65 public static boolean TraceTargetDataLine = getBooleanProperty("TraceTargetDataLine");
66 public static boolean TraceClip = getBooleanProperty("TraceClip");
67 public static boolean TraceAudioFileReader = getBooleanProperty("TraceAudioFileReader");
68 public static boolean TraceAudioFileWriter = getBooleanProperty("TraceAudioFileWriter");
69 public static boolean TraceAudioConverter = getBooleanProperty("TraceAudioConverter");
70 public static boolean TraceAudioOutputStream = getBooleanProperty("TraceAudioOutputStream");
71
72 // sampled specific implementation
73 public static boolean TraceEsdNative = getBooleanProperty("TraceEsdNative");
74 public static boolean TraceEsdStreamNative = getBooleanProperty("TraceEsdStreamNative");
75 public static boolean TraceEsdRecordingStreamNative = getBooleanProperty("TraceEsdRecordingStreamNative");
76 public static boolean TraceAlsaNative = getBooleanProperty("TraceAlsaNative");
77 public static boolean TraceAlsaMixerNative = getBooleanProperty("TraceAlsaMixerNative");
78 public static boolean TraceAlsaPcmNative = getBooleanProperty("TraceAlsaPcmNative");
79 public static boolean TraceMixingAudioInputStream = getBooleanProperty("TraceMixingAudioInputStream");
80 public static boolean TraceOggNative = getBooleanProperty("TraceOggNative");
81 public static boolean TraceVorbisNative = getBooleanProperty("TraceVorbisNative");
82
83 // midi common implementation
84 public static boolean TraceMidiSystem = getBooleanProperty("TraceMidiSystem");
85 public static boolean TraceMidiConfig = getBooleanProperty("TraceMidiConfig");
86 public static boolean TraceMidiDeviceProvider = getBooleanProperty("TraceMidiDeviceProvider");
87 public static boolean TraceSequencer = getBooleanProperty("TraceSequencer");
88 public static boolean TraceMidiDevice = getBooleanProperty("TraceMidiDevice");
89
90 // midi specific implementation
91 public static boolean TraceAlsaSeq = getBooleanProperty("TraceAlsaSeq");
92 public static boolean TraceAlsaSeqDetails = getBooleanProperty("TraceAlsaSeqDetails");
93 public static boolean TraceAlsaSeqNative = getBooleanProperty("TraceAlsaSeqNative");
94 public static boolean TracePortScan = getBooleanProperty("TracePortScan");
95 public static boolean TraceAlsaMidiIn = getBooleanProperty("TraceAlsaMidiIn");
96 public static boolean TraceAlsaMidiOut = getBooleanProperty("TraceAlsaMidiOut");
97 public static boolean TraceAlsaMidiChannel = getBooleanProperty("TraceAlsaMidiChannel");
98
99 // misc
100 public static boolean TraceAlsaCtlNative = getBooleanProperty("TraceAlsaCtlNative");
101 public static boolean TraceCdda = getBooleanProperty("TraceCdda");
102 public static boolean TraceCddaNative = getBooleanProperty("TraceCddaNative");
103
104
105
106 // make this method configurable to write to file, write to stderr,...
107 public static void out(String strMessage)
108 {
109 if (strMessage.length()>0 && strMessage.charAt(0)=='<') {
110 if (indent.length()>2) {
111 indent=indent.substring(2);
112 } else {
113 indent="";
114 }
115 }
116 String newMsg=null;
117 if (indent!="" && strMessage.indexOf("\n")>=0) {
118 newMsg="";
119 StringTokenizer tokenizer=new StringTokenizer(strMessage, "\n");
120 while (tokenizer.hasMoreTokens()) {
121 newMsg+=indent+tokenizer.nextToken()+"\n";
122 }
123 } else {
124 newMsg=indent+strMessage;
125 }
126 m_printStream.println(newMsg);
127 if (strMessage.length()>0 && strMessage.charAt(0)=='>') {
128 indent+=" ";
129 }
130 }
131
132
133
134 public static void out(Throwable throwable)
135 {
136 throwable.printStackTrace(m_printStream);
137 }
138
139
140
141 public static void assertion(boolean bAssertion)
142 {
143 if (!bAssertion)
144 {
145 throw new AssertException();
146 }
147 }
148
149
150 public static class AssertException
151 extends RuntimeException
152 {
153 public AssertException()
154 {
155 }
156
157
158
159 public AssertException(String sMessage)
160 {
161 super(sMessage);
162 }
163 }
164
165
166
167 private static boolean getBooleanProperty(String strName)
168 {
169 String strPropertyName = PROPERTY_PREFIX + strName;
170 String strValue = "false";
171 try
172 {
173 strValue = System.getProperty(strPropertyName, "false");
174 }
175 catch (AccessControlException e)
176 {
177 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
178 {
179 out(e);
180 }
181 }
182 // TDebug.out("property: " + strPropertyName + "=" + strValue);
183 boolean bValue = strValue.toLowerCase().equals("true");
184 // TDebug.out("bValue: " + bValue);
185 return bValue;
186 }
187}
188
189
190
191/*** TDebug.java ***/
192
diff --git a/songdbj/org/tritonus/share/TNotifier.java b/songdbj/org/tritonus/share/TNotifier.java
deleted file mode 100644
index 822b30c305..0000000000
--- a/songdbj/org/tritonus/share/TNotifier.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*
2 * TNotifier.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.EventObject;
34import java.util.Collection;
35import java.util.ArrayList;
36import java.util.List;
37import java.util.Iterator;
38
39import javax.sound.sampled.LineListener;
40import javax.sound.sampled.LineEvent;
41
42
43
44public class TNotifier
45extends Thread
46{
47 public static class NotifyEntry
48 {
49 private EventObject m_event;
50 private List<LineListener> m_listeners;
51
52
53
54 public NotifyEntry(EventObject event, Collection<LineListener> listeners)
55 {
56 m_event = event;
57 m_listeners = new ArrayList<LineListener>(listeners);
58 }
59
60
61 public void deliver()
62 {
63 // TDebug.out("%% TNotifier.NotifyEntry.deliver(): called.");
64 Iterator<LineListener> iterator = m_listeners.iterator();
65 while (iterator.hasNext())
66 {
67 LineListener listener = iterator.next();
68 listener.update((LineEvent) m_event);
69 }
70 }
71 }
72
73
74 public static TNotifier notifier = null;
75
76 static
77 {
78 notifier = new TNotifier();
79 notifier.setDaemon(true);
80 notifier.start();
81 }
82
83
84
85 /** The queue of events to deliver.
86 * The entries are of class NotifyEntry.
87 */
88 private List<NotifyEntry> m_entries;
89
90
91 public TNotifier()
92 {
93 super("Tritonus Notifier");
94 m_entries = new ArrayList<NotifyEntry>();
95 }
96
97
98
99 public void addEntry(EventObject event, Collection<LineListener> listeners)
100 {
101 // TDebug.out("%% TNotifier.addEntry(): called.");
102 synchronized (m_entries)
103 {
104 m_entries.add(new NotifyEntry(event, listeners));
105 m_entries.notifyAll();
106 }
107 // TDebug.out("%% TNotifier.addEntry(): completed.");
108 }
109
110
111 public void run()
112 {
113 while (true)
114 {
115 NotifyEntry entry = null;
116 synchronized (m_entries)
117 {
118 while (m_entries.size() == 0)
119 {
120 try
121 {
122 m_entries.wait();
123 }
124 catch (InterruptedException e)
125 {
126 if (TDebug.TraceAllExceptions)
127 {
128 TDebug.out(e);
129 }
130 }
131 }
132 entry = m_entries.remove(0);
133 }
134 entry.deliver();
135 }
136 }
137}
138
139
140/*** TNotifier.java ***/
diff --git a/songdbj/org/tritonus/share/TSettings.java b/songdbj/org/tritonus/share/TSettings.java
deleted file mode 100644
index ae1a315e0e..0000000000
--- a/songdbj/org/tritonus/share/TSettings.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * TSettings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.io.PrintStream;
34import java.util.StringTokenizer;
35import java.security.AccessControlException;
36
37import org.tritonus.share.TDebug;
38
39
40public class TSettings
41{
42 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
43 private static final String PROPERTY_PREFIX = "tritonus.";
44
45
46 public static boolean AlsaUsePlughw = getBooleanProperty("AlsaUsePlughw");
47
48
49
50 private static boolean getBooleanProperty(String strName)
51 {
52 String strPropertyName = PROPERTY_PREFIX + strName;
53 String strValue = "false";
54 try
55 {
56 strValue = System.getProperty(strPropertyName, "false");
57 }
58 catch (AccessControlException e)
59 {
60 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
61 {
62 TDebug.out(e);
63 }
64 }
65 // TDebug.out("property: " + strPropertyName + "=" + strValue);
66 boolean bValue = strValue.toLowerCase().equals("true");
67 // TDebug.out("bValue: " + bValue);
68 return bValue;
69 }
70}
71
72
73
74/*** TSettings.java ***/
75
diff --git a/songdbj/org/tritonus/share/package.html b/songdbj/org/tritonus/share/package.html
deleted file mode 100644
index 200904dc60..0000000000
--- a/songdbj/org/tritonus/share/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Misc helper classes.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/share/sampled/AudioFileTypes.java b/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
deleted file mode 100644
index 45e4a0ffbc..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
+++ /dev/null
@@ -1,155 +0,0 @@
1/*
2 * AudioFileTypes.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import javax.sound.sampled.AudioFileFormat;
31import org.tritonus.share.StringHashedSet;
32import org.tritonus.share.TDebug;
33
34/**
35 * This class is a proposal for generic handling of audio file format types.
36 * The main purpose is to provide a standardized way of
37 * implementing audio file format types. Like this, file types
38 * are only identified by their String name, and not, as currently,
39 * by their object instance.
40 * <p>
41 * A standard registry of file type names will
42 * be maintained by the Tritonus team.
43 * <p>
44 * In a specification request to JavaSoft, these static methods
45 * could be integrated into<code>AudioFileFormat.Type</code>. The static
46 * instances of AIFF, AIFC, AU, SND, and WAVE types in class
47 * <code>AudioFileFormat.Type</code> should be retrieved
48 * using this method, too (internally).<br>
49 * At best, the protected constructor of that class
50 * should also be replaced to be a private constructor.
51 * Like this it will be prevented that developers create
52 * instances of Type, which causes problems with the
53 * equals method. In fact, the equals method should be redefined anyway
54 * so that it compares the names and not the objects.
55 * <p>
56 * Also, the file name extension should be deprecated and moved
57 * to <code>AudioFileFormat</code>. There are some file formats
58 * which have varying extensions depending, e.g. on the encoding.
59 * An example for this is MPEG: the special encoding Mpeg 1, layer 3
60 * has the extension mp3, whereas other Mpeg files use mpeg or mpg.<br>
61 * This could be implemented with 2 methods in <code>AudioFileFormat</code>:
62 * <ol><li>String[] getFileExtensions(): returns all usable extensions
63 * for this file.
64 * <li>String getDefaultFileExtension(): returns the preferred extension.
65 * </ol>
66 *
67 * @author Florian Bomers
68 */
69public class AudioFileTypes extends AudioFileFormat.Type {
70
71 /** contains all known types */
72 private static StringHashedSet types = new StringHashedSet();
73
74 // initially add the standard types
75 static {
76 types.add(AudioFileFormat.Type.AIFF);
77 types.add(AudioFileFormat.Type.AIFC);
78 types.add(AudioFileFormat.Type.AU);
79 types.add(AudioFileFormat.Type.SND);
80 types.add(AudioFileFormat.Type.WAVE);
81 }
82
83 AudioFileTypes(String name, String ext) {
84 super(name, ext);
85 }
86
87 /**
88 * Use this method to retrieve an instance of
89 * <code>AudioFileFormat.Type</code> of the specified
90 * name. If no type of this name is in the internally
91 * maintained list, <code>null</code> is returned.
92 * <p>
93 * This method is supposed to be used by user programs.
94 * <p>
95 * In order to assure a well-filled internal list,
96 * call <code>AudioSystem.getAudioFileTypes()</code>
97 * at initialization time.
98 *
99 * @see #getType(String, String)
100 */
101 public static AudioFileFormat.Type getType(String name) {
102 return getType(name, null);
103 }
104
105 /**
106 * Use this method to retrieve an instance of
107 * <code>AudioFileFormat.Type</code> of the specified
108 * name. If it does not exist in the internal list
109 * of types, a new type is created and returned.
110 * If it a type of that name already exists (regardless
111 * of extension), it is returned. In this case it can
112 * not be guaranteed that the extension is the same as
113 * passed as parameter.<br>
114 * If <code>extension</code> is <code>null</code>,
115 * this method returns <code>null</code> if the
116 * type of the specified name does not exist in the
117 * internal list.
118 * <p>
119 * This method is supposed to be used by file providers.
120 * Every file reader and file writer provider should
121 * exclusively use this method for retrieving instances
122 * of <code>AudioFileFormat.Type</code>.
123 */
124 public static AudioFileFormat.Type getType(String name, String extension) {
125 AudioFileFormat.Type res=(AudioFileFormat.Type) types.get(name);
126 if (res==null) {
127 // it is not already in the string set.
128 if (extension==null) {
129 return null;
130 }
131 // Create a new type instance.
132 res=new AudioFileTypes(name, extension);
133 // and save it for the future
134 types.add(res);
135 }
136 return res;
137 }
138
139 /**
140 * Tests for equality of 2 file types. They are equal when their names match.
141 * <p>
142 * This function should be AudioFileFormat.Type.equals and must
143 * be considered as a temporary workaround until it flows into the
144 * JavaSound API.
145 */
146 // IDEA: create a special "NOT_SPECIFIED" file type
147 // and a AudioFileFormat.Type.matches method.
148 public static boolean equals(AudioFileFormat.Type t1, AudioFileFormat.Type t2) {
149 return t2.toString().equals(t1.toString());
150 }
151
152}
153
154/*** AudioFileTypes.java ***/
155
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormatSet.java b/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
deleted file mode 100644
index 8d89541d77..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
+++ /dev/null
@@ -1,155 +0,0 @@
1/*
2 * AudioFormatSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.sampled.AudioFormats;
41
42
43/**
44 * A set where the elements are uniquely referenced by
45 * AudioFormats.equals rather than their object reference.
46 * No 2 equal AudioFormats can exist in the set.
47 * <p>
48 * This class provide convenience methods like
49 * <code>getAudioFormat(AudioFormat)</code> and
50 * <code>matches(AudioFormat)</code>.
51 * <p>
52 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
53 * fail, if elem is not an instance of AudioFormat.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 * <p>
60 * Currently, the methods equals(.,.) and matches(.,.) of
61 * class AudioFormats are used. Let's hope that they will
62 * be integrated into AudioFormat.
63 */
64
65public class AudioFormatSet extends ArraySet<AudioFormat>
66{
67 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
68
69 public AudioFormatSet() {
70 super();
71 }
72
73 public AudioFormatSet(Collection<AudioFormat> c) {
74 super(c);
75 }
76
77 public boolean add(AudioFormat elem) {
78 if (elem==null || !(elem instanceof AudioFormat)) {
79 return false;
80 }
81 return super.add(elem);
82 }
83
84 public boolean contains(AudioFormat elem) {
85 if (elem==null || !(elem instanceof AudioFormat)) {
86 return false;
87 }
88 AudioFormat comp=(AudioFormat) elem;
89 Iterator it=iterator();
90 while (it.hasNext()) {
91 if (AudioFormats.equals(comp, (AudioFormat) it.next())) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 public AudioFormat get(AudioFormat elem) {
99 if (elem==null || !(elem instanceof AudioFormat)) {
100 return null;
101 }
102 AudioFormat comp=(AudioFormat) elem;
103 Iterator it=iterator();
104 while (it.hasNext()) {
105 AudioFormat thisElem=(AudioFormat) it.next();
106 if (AudioFormats.equals(comp, thisElem)) {
107 return thisElem;
108 }
109 }
110 return null;
111 }
112
113 public AudioFormat getAudioFormat(AudioFormat elem) {
114 return (AudioFormat) get(elem);
115 }
116
117 /**
118 * Checks whether this Set contains an AudioFormat
119 * that matches <code>elem</code>.
120 * The first matching format is returned. If no element
121 * matches <code>elem</code>, <code>null</code> is returned.
122 * <p>
123 * @see AudioFormats#matches(AudioFormat, AudioFormat)
124 */
125 public AudioFormat matches(AudioFormat elem) {
126 if (elem==null) {
127 return null;
128 }
129 Iterator it=iterator();
130 while (it.hasNext()) {
131 AudioFormat thisElem=(AudioFormat) it.next();
132 if (AudioFormats.matches(elem, thisElem)) {
133 return thisElem;
134 }
135 }
136 return null;
137 }
138
139
140 // $$mp: TODO: remove; should be obsolete
141 public AudioFormat[] toAudioFormatArray() {
142 return (AudioFormat[]) toArray(EMPTY_FORMAT_ARRAY);
143 }
144
145
146 public void add(int index, AudioFormat element) {
147 throw new UnsupportedOperationException("unsupported");
148 }
149
150 public AudioFormat set(int index, AudioFormat element) {
151 throw new UnsupportedOperationException("unsupported");
152 }
153}
154
155/*** AudioFormatSet.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormats.java b/songdbj/org/tritonus/share/sampled/AudioFormats.java
deleted file mode 100644
index 41ac3f37c7..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFormats.java
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * AudioFormats.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Matthias Pfisterer
9 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38
39public class AudioFormats
40{
41 private static boolean doMatch(int i1, int i2)
42 {
43 return i1 == AudioSystem.NOT_SPECIFIED
44 || i2 == AudioSystem.NOT_SPECIFIED
45 || i1 == i2;
46 }
47
48
49
50 private static boolean doMatch(float f1, float f2)
51 {
52 return f1 == AudioSystem.NOT_SPECIFIED
53 || f2 == AudioSystem.NOT_SPECIFIED
54 || Math.abs(f1 - f2) < 1.0e-9;
55 }
56
57
58
59 /**
60 * Tests whether 2 AudioFormats have matching formats.
61 * A field matches when it is AudioSystem.NOT_SPECIFIED in
62 * at least one of the formats or the field is the same
63 * in both formats.<br>
64 * Exceptions:
65 * <ul>
66 * <li>Encoding must always be equal for a match.
67 * <li> For a match, endianness must be equal if SampleSizeInBits is not
68 * AudioSystem.NOT_SPECIFIED and greater than 8bit in both formats.<br>
69 * In other words: If SampleSizeInBits is AudioSystem.NOT_SPECIFIED
70 * in either format or both formats have a SampleSizeInBits<8,
71 * endianness does not matter.
72 * </ul>
73 * This is a proposition to be used as AudioFormat.matches.
74 * It can therefore be considered as a temporary workaround.
75 */
76 // IDEA: create a special "NOT_SPECIFIED" encoding
77 // and a AudioFormat.Encoding.matches method.
78 public static boolean matches(AudioFormat format1,
79 AudioFormat format2)
80 {
81 //$$fb 19 Dec 99: endian must be checked, too.
82 //
83 // we do have a problem with redundant elements:
84 // e.g.
85 // encoding=ALAW || ULAW -> bigEndian and samplesizeinbits don't matter
86 // sample size in bits == 8 -> bigEndian doesn't matter
87 // sample size in bits > 8 -> PCM is always signed.
88 // This is an overall issue in JavaSound, I think.
89 // At present, it is not consistently implemented to support these
90 // redundancies and implicit definitions
91 //
92 // As a workaround of this issue I return in the converters
93 // all combinations, e.g. for ULAW I return bigEndian and !bigEndian formats.
94/* old version
95*/
96 // as proposed by florian
97 return format1.getEncoding().equals(format2.getEncoding())
98 && (format2.getSampleSizeInBits()<=8
99 || format1.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
100 || format2.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
101 || format1.isBigEndian()==format2.isBigEndian())
102 && doMatch(format1.getChannels(),format2.getChannels())
103 && doMatch(format1.getSampleSizeInBits(), format2.getSampleSizeInBits())
104 && doMatch(format1.getFrameSize(), format2.getFrameSize())
105 && doMatch(format1.getSampleRate(), format2.getSampleRate())
106 && doMatch(format1.getFrameRate(),format2.getFrameRate());
107 }
108
109 /**
110 * Tests for exact equality of 2 AudioFormats.
111 * This is the behaviour of AudioFormat.matches in JavaSound 1.0.
112 * <p>
113 * This is a proposition to be used as AudioFormat.equals.
114 * It can therefore be considered as a temporary workaround.
115 */
116 public static boolean equals(AudioFormat format1,
117 AudioFormat format2)
118 {
119 return format1.getEncoding().equals(format2.getEncoding())
120 && format1.getChannels() == format2.getChannels()
121 && format1.getSampleSizeInBits() == format2.getSampleSizeInBits()
122 && format1.getFrameSize() == format2.getFrameSize()
123 && (Math.abs(format1.getSampleRate() - format2.getSampleRate()) < 1.0e-9)
124 && (Math.abs(format1.getFrameRate() - format2.getFrameRate()) < 1.0e-9);
125 }
126
127}
128
129
130
131/*** AudioFormats.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java b/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
deleted file mode 100644
index 70b4e9ebd7..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
+++ /dev/null
@@ -1,115 +0,0 @@
1/*
2 * AudioSystemShadow.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.io.File;
34import java.io.OutputStream;
35import java.io.IOException;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40import org.tritonus.share.sampled.file.AudioOutputStream;
41import org.tritonus.share.sampled.file.TDataOutputStream;
42import org.tritonus.share.sampled.file.TSeekableDataOutputStream;
43import org.tritonus.share.sampled.file.TNonSeekableDataOutputStream;
44import org.tritonus.sampled.file.AiffAudioOutputStream;
45import org.tritonus.sampled.file.AuAudioOutputStream;
46import org.tritonus.sampled.file.WaveAudioOutputStream;
47
48
49
50/** Experminatal area for AudioSystem.
51 * This class is used to host features that may become part of the
52 * Java Sound API (In which case they will be moved to AudioSystem).
53 */
54public class AudioSystemShadow
55{
56 public static TDataOutputStream getDataOutputStream(File file)
57 throws IOException
58 {
59 return new TSeekableDataOutputStream(file);
60 }
61
62
63
64 public static TDataOutputStream getDataOutputStream(OutputStream stream)
65 throws IOException
66 {
67 return new TNonSeekableDataOutputStream(stream);
68 }
69
70
71
72 // TODO: lLengthInBytes actually should be lLengthInFrames (design problem of A.O.S.)
73 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, TDataOutputStream dataOutputStream)
74 {
75 AudioOutputStream audioOutputStream = null;
76
77 if (type.equals(AudioFileFormat.Type.AIFF) ||
78 type.equals(AudioFileFormat.Type.AIFF))
79 {
80 audioOutputStream = new AiffAudioOutputStream(audioFormat, type, lLengthInBytes, dataOutputStream);
81 }
82 else if (type.equals(AudioFileFormat.Type.AU))
83 {
84 audioOutputStream = new AuAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
85 }
86 else if (type.equals(AudioFileFormat.Type.WAVE))
87 {
88 audioOutputStream = new WaveAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
89 }
90 return audioOutputStream;
91 }
92
93
94
95 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, File file)
96 throws IOException
97 {
98 TDataOutputStream dataOutputStream = getDataOutputStream(file);
99 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
100 return audioOutputStream;
101 }
102
103
104
105 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, OutputStream outputStream)
106 throws IOException
107 {
108 TDataOutputStream dataOutputStream = getDataOutputStream(outputStream);
109 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
110 return audioOutputStream;
111 }
112}
113
114
115/*** AudioSystemShadow.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioUtils.java b/songdbj/org/tritonus/share/sampled/AudioUtils.java
deleted file mode 100644
index 21c838b032..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioUtils.java
+++ /dev/null
@@ -1,181 +0,0 @@
1/*
2 * AudioUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled;
31
32import java.io.File;
33import java.io.FileOutputStream;
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.OutputStream;
37import java.util.Collection;
38import java.util.Iterator;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.spi.AudioFileWriter;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.TConversionTool;
48
49
50
51public class AudioUtils
52{
53 public static long getLengthInBytes(AudioInputStream audioInputStream)
54 {
55 return getLengthInBytes(audioInputStream.getFormat(),
56 audioInputStream.getFrameLength());
57/*
58 long lLengthInFrames = audioInputStream.getFrameLength();
59 int nFrameSize = audioInputStream.getFormat().getFrameSize();
60 if (lLengthInFrames >= 0 && nFrameSize >= 1)
61 {
62 return lLengthInFrames * nFrameSize;
63 }
64 else
65 {
66 return AudioSystem.NOT_SPECIFIED;
67 }
68*/
69 }
70
71
72
73 /**
74 * if the passed value for lLength is
75 * AudioSystem.NOT_SPECIFIED (unknown
76 * length), the length in bytes becomes
77 * AudioSystem.NOT_SPECIFIED, too.
78 */
79 public static long getLengthInBytes(AudioFormat audioFormat,
80 long lLengthInFrames)
81 {
82 int nFrameSize = audioFormat.getFrameSize();
83 if (lLengthInFrames >= 0 && nFrameSize >= 1)
84 {
85 return lLengthInFrames * nFrameSize;
86 }
87 else
88 {
89 return AudioSystem.NOT_SPECIFIED;
90 }
91 }
92
93
94
95 public static boolean containsFormat(AudioFormat sourceFormat,
96 Iterator possibleFormats)
97 {
98 while (possibleFormats.hasNext())
99 {
100 AudioFormat format = (AudioFormat) possibleFormats.next();
101 if (AudioFormats.matches(format, sourceFormat))
102 {
103 return true;
104 }
105 }
106 return false;
107 }
108
109 /**
110 * Conversion milliseconds -> bytes
111 */
112
113 public static long millis2Bytes(long ms, AudioFormat format) {
114 return millis2Bytes(ms, format.getFrameRate(), format.getFrameSize());
115 }
116
117 public static long millis2Bytes(long ms, float frameRate, int frameSize) {
118 return (long) (ms*frameRate/1000*frameSize);
119 }
120
121 /**
122 * Conversion milliseconds -> bytes (bytes will be frame-aligned)
123 */
124 public static long millis2BytesFrameAligned(long ms, AudioFormat format) {
125 return millis2BytesFrameAligned(ms, format.getFrameRate(), format.getFrameSize());
126 }
127
128 public static long millis2BytesFrameAligned(long ms, float frameRate, int frameSize) {
129 return ((long) (ms*frameRate/1000))*frameSize;
130 }
131
132 /**
133 * Conversion milliseconds -> frames
134 */
135 public static long millis2Frames(long ms, AudioFormat format) {
136 return millis2Frames(ms, format.getFrameRate());
137 }
138
139 public static long millis2Frames(long ms, float frameRate) {
140 return (long) (ms*frameRate/1000);
141 }
142
143 /**
144 * Conversion bytes -> milliseconds
145 */
146 public static long bytes2Millis(long bytes, AudioFormat format) {
147 return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize());
148 }
149
150 /**
151 * Conversion frames -> milliseconds
152 */
153 public static long frames2Millis(long frames, AudioFormat format) {
154 return (long) (frames/format.getFrameRate()*1000);
155 }
156
157
158 //$$fb 2000-07-18: added these debugging functions
159 public static String NS_or_number(int number) {
160 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
161 }
162 public static String NS_or_number(float number) {
163 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
164 }
165
166 /**
167 * For debugging purposes.
168 */
169 public static String format2ShortStr(AudioFormat format) {
170 return format.getEncoding() + "-" +
171 NS_or_number(format.getChannels()) + "ch-" +
172 NS_or_number(format.getSampleSizeInBits()) + "bit-" +
173 NS_or_number(((int)format.getSampleRate())) + "Hz-"+
174 (format.isBigEndian() ? "be" : "le");
175 }
176
177}
178
179
180
181/*** AudioUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/Encodings.java b/songdbj/org/tritonus/share/sampled/Encodings.java
deleted file mode 100644
index 6b880d24d9..0000000000
--- a/songdbj/org/tritonus/share/sampled/Encodings.java
+++ /dev/null
@@ -1,183 +0,0 @@
1/*
2 * Encodings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import java.util.Iterator;
31import javax.sound.sampled.AudioSystem;
32import javax.sound.sampled.AudioFormat;
33import org.tritonus.share.StringHashedSet;
34import org.tritonus.share.TDebug;
35
36/**
37 * This class is a proposal for generic handling of encodings.
38 * The main purpose is to provide a standardized way of
39 * implementing encoding types. Like this, encodings
40 * are only identified by their String name, and not, as currently,
41 * by their object instance.
42 * <p>
43 * A registry of standard encoding names will
44 * be maintained by the Tritonus team.
45 * <p>
46 * In a specification request to JavaSoft, the static method
47 * <code>getEncoding</code> should be integrated into
48 * <code>AudioFormat.Encoding(String name)</code> (possibly
49 * renamed to <code>getInstance(String name)</code>.<br>
50 * The static instances of ULAW, ALAW PCM_UNSIGNED and PCM_SIGNED
51 * encodings in that class should be retrieved using that function,
52 * too (internally).<br>
53 * At best, the protected constructor of that class
54 * should also be replaced to be a private constructor.
55 * Like this it will be prevented that developers create their own
56 * instances of Encoding, which causes problems with the
57 * equals method. In fact, the equals method should be redefined anyway
58 * so that it compares the names and not the objects.
59 * <p>
60 * Also, a specification request should be made to integrate
61 * <code>getEncodings()</code> into AudioSystem (this is
62 * especially annoying as the relevant methods already exist
63 * in the provider interfaces of file readers, file writers and
64 * converters).
65 *
66 * @author Florian Bomers
67 */
68public class Encodings extends AudioFormat.Encoding {
69
70 /** contains all known encodings */
71 private static StringHashedSet encodings = new StringHashedSet();
72
73 // initially add the standard encodings
74 static {
75 encodings.add(AudioFormat.Encoding.PCM_SIGNED);
76 encodings.add(AudioFormat.Encoding.PCM_UNSIGNED);
77 encodings.add(AudioFormat.Encoding.ULAW);
78 encodings.add(AudioFormat.Encoding.ALAW);
79 }
80
81 Encodings(String name) {
82 super(name);
83 }
84
85 /**
86 * Use this method for retrieving an instance of
87 * <code>AudioFormat.Encoding</code> of the specified
88 * name. A standard registry of encoding names will
89 * be maintained by the Tritonus team.
90 * <p>
91 * Every file reader, file writer, and format converter
92 * provider should exclusively use this method for
93 * retrieving instances of <code>AudioFormat.Encoding</code>.
94 */
95 /*
96 MP2000/09/11:
97 perhaps it is not a good idea to allow user programs the creation of new
98 encodings. The problem with it is that a plain typo will produce an encoding
99 object that is not supported. Instead, some indication of an error should be
100 signaled to the user program. And, there should be a second interface for
101 service providers allowing them to register encodings supported by themselves.
102
103 $$fb2000/09/26:
104 The problem is what you see as second issue: it can never be assured
105 that this class knows all available encodings. So at the moment, there
106 is no choice than to allow users to create any Encoding they wish.
107 The encodings database will simplify things.
108 A problem with an interface to retrieve supported encodings (or API
109 function in spi.FormatConversionProvider) is that this requires
110 loading of all providers very early. Hmmm, maybe this is necessary in any
111 case when the user issues something like AudioSystem.isConversionSupported.
112 */
113 public static AudioFormat.Encoding getEncoding(String name) {
114 AudioFormat.Encoding res=(AudioFormat.Encoding) encodings.get(name);
115 if (res==null) {
116 // it is not already in the string set. Create a new encoding instance.
117 res=new Encodings(name);
118 // and save it for the future
119 encodings.add(res);
120 }
121 return res;
122 }
123
124 /**
125 * Tests for equality of 2 encodings. They are equal when their strings match.
126 * <p>
127 * This function should be AudioFormat.Encoding.equals and must
128 * be considered as a temporary work around until it flows into the
129 * JavaSound API.
130 */
131 // IDEA: create a special "NOT_SPECIFIED" encoding
132 // and a AudioFormat.Encoding.matches method.
133 public static boolean equals(AudioFormat.Encoding e1, AudioFormat.Encoding e2) {
134 return e2.toString().equals(e1.toString());
135 }
136
137
138 /**
139 * Returns all &quot;supported&quot; encodings.
140 * Supported means that it is possible to read or
141 * write files with this encoding, or that a converter
142 * accepts this encoding as source or target format.
143 * <p>
144 * Currently, this method returns a best guess and
145 * the search algorithm is far from complete: with standard
146 * methods of AudioSystem, only the target encodings
147 * of the converters can be retrieved - neither
148 * the source encodings of converters nor the encodings
149 * of file readers and file writers cannot be retrieved.
150 */
151 public static AudioFormat.Encoding[] getEncodings() {
152 StringHashedSet iteratedSources=new StringHashedSet();
153 StringHashedSet retrievedTargets=new StringHashedSet();
154 Iterator sourceFormats=encodings.iterator();
155 while (sourceFormats.hasNext()) {
156 AudioFormat.Encoding source=(AudioFormat.Encoding) sourceFormats.next();
157 iterateEncodings(source, iteratedSources, retrievedTargets);
158 }
159 return (AudioFormat.Encoding[]) retrievedTargets.toArray(
160 new AudioFormat.Encoding[retrievedTargets.size()]);
161 }
162
163
164 private static void iterateEncodings(AudioFormat.Encoding source,
165 StringHashedSet iteratedSources,
166 StringHashedSet retrievedTargets) {
167 if (!iteratedSources.contains(source)) {
168 iteratedSources.add(source);
169 AudioFormat.Encoding[] targets=AudioSystem.getTargetEncodings(source);
170 for (int i=0; i<targets.length; i++) {
171 AudioFormat.Encoding target=targets[i];
172 if (retrievedTargets.add(target.toString())) {
173 iterateEncodings(target, iteratedSources,retrievedTargets);
174 }
175 }
176 }
177 }
178}
179
180
181
182/*** Encodings.java ***/
183
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java b/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
deleted file mode 100644
index d1fe534613..0000000000
--- a/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
+++ /dev/null
@@ -1,734 +0,0 @@
1/*
2 * FloatSampleBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.ArrayList;
32import java.util.Iterator;
33import java.util.Random;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.AudioFileWriter;
40
41import org.tritonus.share.TDebug;
42
43/**
44 * A class for small buffers of samples in linear, 32-bit
45 * floating point format.
46 * <p>
47 * It is supposed to be a replacement of the byte[] stream
48 * architecture of JavaSound, especially for chains of
49 * AudioInputStreams. Ideally, all involved AudioInputStreams
50 * handle reading into a FloatSampleBuffer.
51 * <p>
52 * Specifications:
53 * <ol>
54 * <li>Channels are separated, i.e. for stereo there are 2 float arrays
55 * with the samples for the left and right channel
56 * <li>All data is handled in samples, where one sample means
57 * one float value in each channel
58 * <li>All samples are normalized to the interval [-1.0...1.0]
59 * </ol>
60 * <p>
61 * When a cascade of AudioInputStreams use FloatSampleBuffer for
62 * processing, they may implement the interface FloatSampleInput.
63 * This signals that this stream may provide float buffers
64 * for reading. The data is <i>not</i> converted back to bytes,
65 * but stays in a single buffer that is passed from stream to stream.
66 * For that serves the read(FloatSampleBuffer) method, which is
67 * then used as replacement for the byte-based read functions of
68 * AudioInputStream.<br>
69 * However, backwards compatibility must always be retained, so
70 * even when an AudioInputStream implements FloatSampleInput,
71 * it must work the same way when any of the byte-based read methods
72 * is called.<br>
73 * As an example, consider the following set-up:<br>
74 * <ul>
75 * <li>auAIS is an AudioInputStream (AIS) that reads from an AU file
76 * in 8bit pcm at 8000Hz. It does not implement FloatSampleInput.
77 * <li>pcmAIS1 is an AIS that reads from auAIS and converts the data
78 * to PCM 16bit. This stream implements FloatSampleInput, i.e. it
79 * can generate float audio data from the ulaw samples.
80 * <li>pcmAIS2 reads from pcmAIS1 and adds a reverb.
81 * It operates entirely on floating point samples.
82 * <li>The method that reads from pcmAIS2 (i.e. AudioSystem.write) does
83 * not handle floating point samples.
84 * </ul>
85 * So, what happens when a block of samples is read from pcmAIS2 ?
86 * <ol>
87 * <li>the read(byte[]) method of pcmAIS2 is called
88 * <li>pcmAIS2 always operates on floating point samples, so
89 * it uses an own instance of FloatSampleBuffer and initializes
90 * it with the number of samples requested in the read(byte[])
91 * method.
92 * <li>It queries pcmAIS1 for the FloatSampleInput interface. As it
93 * implements it, pcmAIS2 calls the read(FloatSampleBuffer) method
94 * of pcmAIS1.
95 * <li>pcmAIS1 notes that its underlying stream does not support floats,
96 * so it instantiates a byte buffer which can hold the number of
97 * samples of the FloatSampleBuffer passed to it. It calls the
98 * read(byte[]) method of auAIS.
99 * <li>auAIS fills the buffer with the bytes.
100 * <li>pcmAIS1 calls the <code>initFromByteArray</code> method of
101 * the float buffer to initialize it with the 8 bit data.
102 * <li>Then pcmAIS1 processes the data: as the float buffer is
103 * normalized, it does nothing with the buffer - and returns
104 * control to pcmAIS2. The SampleSizeInBits field of the
105 * AudioFormat of pcmAIS1 defines that it should be 16 bits.
106 * <li>pcmAIS2 receives the filled buffer from pcmAIS1 and does
107 * its processing on the buffer - it adds the reverb.
108 * <li>As pcmAIS2's read(byte[]) method had been called, pcmAIS2
109 * calls the <code>convertToByteArray</code> method of
110 * the float buffer to fill the byte buffer with the
111 * resulting samples.
112 * </ol>
113 * <p>
114 * To summarize, here are some advantages when using a FloatSampleBuffer
115 * for streaming:
116 * <ul>
117 * <li>no conversions from/to bytes need to be done during processing
118 * <li>the sample size in bits is irrelevant - normalized range
119 * <li>higher quality for processing
120 * <li>separated channels (easy process/remove/add channels)
121 * <li>potentially less copying of audio data, as processing
122 * the float samples is generally done in-place. The same
123 * instance of a FloatSampleBuffer may be used from the original data source
124 * to the final data sink.
125 * </ul>
126 * <p>
127 * Simple benchmarks showed that the processing requirements
128 * for the conversion to and from float is about the same as
129 * when converting it to shorts or ints without dithering,
130 * and significantly higher with dithering. An own implementation
131 * of a random number generator may improve this.
132 * <p>
133 * &quot;Lazy&quot; deletion of samples and channels:<br>
134 * <ul>
135 * <li>When the sample count is reduced, the arrays are not resized, but
136 * only the member variable <code>sampleCount</code> is reduced. A subsequent
137 * increase of the sample count (which will occur frequently), will check
138 * that and eventually reuse the existing array.
139 * <li>When a channel is deleted, it is not removed from memory but only
140 * hidden. Subsequent insertions of a channel will check whether a hidden channel
141 * can be reused.
142 * </ul>
143 * The lazy mechanism can save many array instantiation (and copy-) operations
144 * for the sake of performance. All relevant methods exist in a second
145 * version which allows explicitely to disable lazy deletion.
146 * <p>
147 * Use the <code>reset</code> functions to clear the memory and remove
148 * hidden samples and channels.
149 * <p>
150 * Note that the lazy mechanism implies that the arrays returned
151 * from <code>getChannel(int)</code> may have a greater size
152 * than getSampleCount(). Consequently, be sure to never rely on the
153 * length field of the sample arrays.
154 * <p>
155 * As an example, consider a chain of converters that all act
156 * on the same instance of FloatSampleBuffer. Some converters
157 * may decrease the sample count (e.g. sample rate converter) and
158 * delete channels (e.g. PCM2PCM converter). So, processing of one
159 * block will decrease both. For the next block, all starts
160 * from the beginning. With the lazy mechanism, all float arrays
161 * are only created once for processing all blocks.<br>
162 * Having lazy disabled would require for each chunk that is processed
163 * <ol>
164 * <li>new instantiation of all channel arrays
165 * at the converter chain beginning as they have been
166 * either deleted or decreased in size during processing of the
167 * previous chunk, and
168 * <li>re-instantiation of all channel arrays for
169 * the reduction of the sample count.
170 * </ol>
171 * <p>
172 * Dithering:<br>
173 * By default, this class uses dithering for reduction
174 * of sample width (e.g. original data was 16bit, target
175 * data is 8bit). As dithering may be needed in other cases
176 * (especially when the float samples are processed using DSP
177 * algorithms), or it is preferred to switch it off,
178 * dithering can be explicitely switched on or off with
179 * the method setDitherMode(int).<br>
180 * For a discussion about dithering, see
181 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering.htm">
182 * here</a> and
183 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering2.htm">
184 * here</a>.
185 *
186 * @author Florian Bomers
187 */
188
189public class FloatSampleBuffer {
190
191 /** Whether the functions without lazy parameter are lazy or not. */
192 private static final boolean LAZY_DEFAULT=true;
193
194 private ArrayList<float[]> channels = new ArrayList<float[]>(); // contains for each channel a float array
195 private int sampleCount=0;
196 private int channelCount=0;
197 private float sampleRate=0;
198 private int originalFormatType=0;
199
200 /** Constant for setDitherMode: dithering will be enabled if sample size is decreased */
201 public static final int DITHER_MODE_AUTOMATIC=0;
202 /** Constant for setDitherMode: dithering will be done */
203 public static final int DITHER_MODE_ON=1;
204 /** Constant for setDitherMode: dithering will not be done */
205 public static final int DITHER_MODE_OFF=2;
206
207 private float ditherBits = FloatSampleTools.DEFAULT_DITHER_BITS;
208
209 // e.g. the sample rate converter may want to force dithering
210 private int ditherMode = DITHER_MODE_AUTOMATIC;
211
212 //////////////////////////////// initialization /////////////////////////////////
213
214 /**
215 * Create an instance with initially no channels.
216 */
217 public FloatSampleBuffer() {
218 this(0,0,1);
219 }
220
221 /**
222 * Create an empty FloatSampleBuffer with the specified number of channels,
223 * samples, and the specified sample rate.
224 */
225 public FloatSampleBuffer(int channelCount, int sampleCount, float sampleRate) {
226 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
227 }
228
229 /**
230 * Creates a new instance of FloatSampleBuffer and initializes
231 * it with audio data given in the interleaved byte array <code>buffer</code>.
232 */
233 public FloatSampleBuffer(byte[] buffer, int offset, int byteCount,
234 AudioFormat format) {
235 this(format.getChannels(),
236 byteCount/(format.getSampleSizeInBits()/8*format.getChannels()),
237 format.getSampleRate());
238 initFromByteArray(buffer, offset, byteCount, format);
239 }
240
241 protected void init(int channelCount, int sampleCount, float sampleRate) {
242 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
243 }
244
245 protected void init(int channelCount, int sampleCount, float sampleRate, boolean lazy) {
246 if (channelCount<0 || sampleCount<0) {
247 throw new IllegalArgumentException(
248 "invalid parameters in initialization of FloatSampleBuffer.");
249 }
250 setSampleRate(sampleRate);
251 if (getSampleCount()!=sampleCount || getChannelCount()!=channelCount) {
252 createChannels(channelCount, sampleCount, lazy);
253 }
254 }
255
256 private void createChannels(int channelCount, int sampleCount, boolean lazy) {
257 this.sampleCount=sampleCount;
258 // lazy delete of all channels. Intentionally lazy !
259 this.channelCount=0;
260 for (int ch=0; ch<channelCount; ch++) {
261 insertChannel(ch, false, lazy);
262 }
263 if (!lazy) {
264 // remove hidden channels
265 while (channels.size()>channelCount) {
266 channels.remove(channels.size()-1);
267 }
268 }
269 }
270
271
272 /**
273 * Resets this buffer with the audio data specified
274 * in the arguments. This FloatSampleBuffer's sample count
275 * will be set to <code>byteCount / format.getFrameSize()</code>.
276 * If LAZY_DEFAULT is true, it will use lazy deletion.
277 *
278 * @throws IllegalArgumentException
279 */
280 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
281 AudioFormat format) {
282 initFromByteArray(buffer, offset, byteCount, format, LAZY_DEFAULT);
283 }
284
285
286 /**
287 * Resets this buffer with the audio data specified
288 * in the arguments. This FloatSampleBuffer's sample count
289 * will be set to <code>byteCount / format.getFrameSize()</code>.
290 *
291 * @param lazy if true, then existing channels will be tried to be re-used
292 * to minimize garbage collection.
293 * @throws IllegalArgumentException
294 */
295 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
296 AudioFormat format, boolean lazy) {
297 if (offset+byteCount>buffer.length) {
298 throw new IllegalArgumentException
299 ("FloatSampleBuffer.initFromByteArray: buffer too small.");
300 }
301
302 int thisSampleCount = byteCount/format.getFrameSize();
303 init(format.getChannels(), thisSampleCount, format.getSampleRate(), lazy);
304
305 // save format for automatic dithering mode
306 originalFormatType = FloatSampleTools.getFormatType(format);
307
308 FloatSampleTools.byte2float(buffer, offset,
309 channels, 0, sampleCount, format);
310 }
311
312 /**
313 * Resets this sample buffer with the data in <code>source</code>.
314 */
315 public void initFromFloatSampleBuffer(FloatSampleBuffer source) {
316 init(source.getChannelCount(), source.getSampleCount(), source.getSampleRate());
317 for (int ch=0; ch<getChannelCount(); ch++) {
318 System.arraycopy(source.getChannel(ch), 0, getChannel(ch), 0, sampleCount);
319 }
320 }
321
322 /**
323 * Deletes all channels, frees memory...
324 * This also removes hidden channels by lazy remove.
325 */
326 public void reset() {
327 init(0,0,1, false);
328 }
329
330 /**
331 * Destroys any existing data and creates new channels.
332 * It also destroys lazy removed channels and samples.
333 */
334 public void reset(int channels, int sampleCount, float sampleRate) {
335 init(channels, sampleCount, sampleRate, false);
336 }
337
338 //////////////////////////////// conversion back to bytes /////////////////////////////////
339
340 /**
341 * @return the required size of the buffer
342 * for calling convertToByteArray(..) is called
343 */
344 public int getByteArrayBufferSize(AudioFormat format) {
345 // make sure this format is supported
346 FloatSampleTools.getFormatType(format);
347 return format.getFrameSize() * getSampleCount();
348 }
349
350 /**
351 * Writes this sample buffer's audio data to <code>buffer</code>
352 * as an interleaved byte array.
353 * <code>buffer</code> must be large enough to hold all data.
354 *
355 * @throws IllegalArgumentException when buffer is too small or <code>format</code> doesn't match
356 * @return number of bytes written to <code>buffer</code>
357 */
358 public int convertToByteArray(byte[] buffer, int offset, AudioFormat format) {
359 int byteCount = getByteArrayBufferSize(format);
360 if (offset + byteCount > buffer.length) {
361 throw new IllegalArgumentException
362 ("FloatSampleBuffer.convertToByteArray: buffer too small.");
363 }
364 if (format.getSampleRate()!=getSampleRate()) {
365 throw new IllegalArgumentException
366 ("FloatSampleBuffer.convertToByteArray: different samplerates.");
367 }
368 if (format.getChannels()!=getChannelCount()) {
369 throw new IllegalArgumentException
370 ("FloatSampleBuffer.convertToByteArray: different channel count.");
371 }
372 FloatSampleTools.float2byte(channels, 0, buffer, offset, getSampleCount(),
373 format, getConvertDitherBits(FloatSampleTools.getFormatType(format)));
374
375 return byteCount;
376 }
377
378
379 /**
380 * Creates a new byte[] buffer, fills it with the audio data, and returns it.
381 * @throws IllegalArgumentException when sample rate or channels do not match
382 * @see #convertToByteArray(byte[], int, AudioFormat)
383 */
384 public byte[] convertToByteArray(AudioFormat format) {
385 // throws exception when sampleRate doesn't match
386 // creates a new byte[] buffer and returns it
387 byte[] res = new byte[getByteArrayBufferSize(format)];
388 convertToByteArray(res, 0, format);
389 return res;
390 }
391
392 //////////////////////////////// actions /////////////////////////////////
393
394 /**
395 * Resizes this buffer.
396 * <p>If <code>keepOldSamples</code> is true, as much as possible samples are
397 * retained. If the buffer is enlarged, silence is added at the end.
398 * If <code>keepOldSamples</code> is false, existing samples are discarded
399 * and the buffer contains random samples.
400 */
401 public void changeSampleCount(int newSampleCount, boolean keepOldSamples) {
402 int oldSampleCount=getSampleCount();
403 if (oldSampleCount==newSampleCount) {
404 return;
405 }
406 Object[] oldChannels=null;
407 if (keepOldSamples) {
408 oldChannels=getAllChannels();
409 }
410 init(getChannelCount(), newSampleCount, getSampleRate());
411 if (keepOldSamples) {
412 // copy old channels and eventually silence out new samples
413 int copyCount=newSampleCount<oldSampleCount?
414 newSampleCount:oldSampleCount;
415 for (int ch=0; ch<getChannelCount(); ch++) {
416 float[] oldSamples=(float[]) oldChannels[ch];
417 float[] newSamples=(float[]) getChannel(ch);
418 if (oldSamples!=newSamples) {
419 // if this sample array was not object of lazy delete
420 System.arraycopy(oldSamples, 0, newSamples, 0, copyCount);
421 }
422 if (oldSampleCount<newSampleCount) {
423 // silence out new samples
424 for (int i=oldSampleCount; i<newSampleCount; i++) {
425 newSamples[i]=0.0f;
426 }
427 }
428 }
429 }
430 }
431
432 public void makeSilence() {
433 // silence all channels
434 if (getChannelCount()>0) {
435 makeSilence(0);
436 for (int ch=1; ch<getChannelCount(); ch++) {
437 copyChannel(0, ch);
438 }
439 }
440 }
441
442 public void makeSilence(int channel) {
443 float[] samples=getChannel(channel);
444 for (int i=0; i<getSampleCount(); i++) {
445 samples[i]=0.0f;
446 }
447 }
448
449 public void addChannel(boolean silent) {
450 // creates new, silent channel
451 insertChannel(getChannelCount(), silent);
452 }
453
454 /**
455 * Insert a (silent) channel at position <code>index</code>.
456 * If LAZY_DEFAULT is true, this is done lazily.
457 */
458 public void insertChannel(int index, boolean silent) {
459 insertChannel(index, silent, LAZY_DEFAULT);
460 }
461
462 /**
463 * Inserts a channel at position <code>index</code>.
464 * <p>If <code>silent</code> is true, the new channel will be silent.
465 * Otherwise it will contain random data.
466 * <p>If <code>lazy</code> is true, hidden channels which have at least getSampleCount()
467 * elements will be examined for reusage as inserted channel.<br>
468 * If <code>lazy</code> is false, still hidden channels are reused,
469 * but it is assured that the inserted channel has exactly getSampleCount() elements,
470 * thus not wasting memory.
471 */
472 public void insertChannel(int index, boolean silent, boolean lazy) {
473 int physSize=channels.size();
474 int virtSize=getChannelCount();
475 float[] newChannel=null;
476 if (physSize>virtSize) {
477 // there are hidden channels. Try to use one.
478 for (int ch=virtSize; ch<physSize; ch++) {
479 float[] thisChannel=(float[]) channels.get(ch);
480 if ((lazy && thisChannel.length>=getSampleCount())
481 || (!lazy && thisChannel.length==getSampleCount())) {
482 // we found a matching channel. Use it !
483 newChannel=thisChannel;
484 channels.remove(ch);
485 break;
486 }
487 }
488 }
489 if (newChannel==null) {
490 newChannel=new float[getSampleCount()];
491 }
492 channels.add(index, newChannel);
493 this.channelCount++;
494 if (silent) {
495 makeSilence(index);
496 }
497 }
498
499 /** performs a lazy remove of the channel */
500 public void removeChannel(int channel) {
501 removeChannel(channel, LAZY_DEFAULT);
502 }
503
504
505 /**
506 * Removes a channel.
507 * If lazy is true, the channel is not physically removed, but only hidden.
508 * These hidden channels are reused by subsequent calls to addChannel
509 * or insertChannel.
510 */
511 public void removeChannel(int channel, boolean lazy) {
512 if (!lazy) {
513 channels.remove(channel);
514 } else if (channel<getChannelCount()-1) {
515 // if not already, move this channel at the end
516 channels.add(channels.remove(channel));
517 }
518 channelCount--;
519 }
520
521 /**
522 * both source and target channel have to exist. targetChannel
523 * will be overwritten
524 */
525 public void copyChannel(int sourceChannel, int targetChannel) {
526 float[] source=getChannel(sourceChannel);
527 float[] target=getChannel(targetChannel);
528 System.arraycopy(source, 0, target, 0, getSampleCount());
529 }
530
531 /**
532 * Copies data inside all channel. When the 2 regions
533 * overlap, the behavior is not specified.
534 */
535 public void copy(int sourceIndex, int destIndex, int length) {
536 for (int i=0; i<getChannelCount(); i++) {
537 copy(i, sourceIndex, destIndex, length);
538 }
539 }
540
541 /**
542 * Copies data inside a channel. When the 2 regions
543 * overlap, the behavior is not specified.
544 */
545 public void copy(int channel, int sourceIndex, int destIndex, int length) {
546 float[] data=getChannel(channel);
547 int bufferCount=getSampleCount();
548 if (sourceIndex+length>bufferCount || destIndex+length>bufferCount
549 || sourceIndex<0 || destIndex<0 || length<0) {
550 throw new IndexOutOfBoundsException("parameters exceed buffer size");
551 }
552 System.arraycopy(data, sourceIndex, data, destIndex, length);
553 }
554
555 /**
556 * Mix up of 1 channel to n channels.<br>
557 * It copies the first channel to all newly created channels.
558 * @param targetChannelCount the number of channels that this sample buffer
559 * will have after expanding. NOT the number of
560 * channels to add !
561 * @exception IllegalArgumentException if this buffer does not have one
562 * channel before calling this method.
563 */
564 public void expandChannel(int targetChannelCount) {
565 // even more sanity...
566 if (getChannelCount()!=1) {
567 throw new IllegalArgumentException(
568 "FloatSampleBuffer: can only expand channels for mono signals.");
569 }
570 for (int ch=1; ch<targetChannelCount; ch++) {
571 addChannel(false);
572 copyChannel(0, ch);
573 }
574 }
575
576 /**
577 * Mix down of n channels to one channel.<br>
578 * It uses a simple mixdown: all other channels are added to first channel.<br>
579 * The volume is NOT lowered !
580 * Be aware, this might cause clipping when converting back
581 * to integer samples.
582 */
583 public void mixDownChannels() {
584 float[] firstChannel=getChannel(0);
585 int sampleCount=getSampleCount();
586 int channelCount=getChannelCount();
587 for (int ch=channelCount-1; ch>0; ch--) {
588 float[] thisChannel=getChannel(ch);
589 for (int i=0; i<sampleCount; i++) {
590 firstChannel[i]+=thisChannel[i];
591 }
592 removeChannel(ch);
593 }
594 }
595
596 /**
597 * Initializes audio data from the provided byte array.
598 * The float samples are written at <code>destOffset</code>.
599 * This FloatSampleBuffer must be big enough to accomodate the samples.
600 * <p>
601 * <code>srcBuffer</code> is read from index <code>srcOffset</code>
602 * to <code>(srcOffset + (lengthInSamples * format.getFrameSize()))</code.
603 *
604 * @param input the input buffer in interleaved audio data
605 * @param inByteOffset the offset in <code>input</code>
606 * @param format input buffer's audio format
607 * @param floatOffset the offset where to write the float samples
608 * @param frameCount number of samples to write to this sample buffer
609 */
610 public void setSamplesFromBytes(byte[] input, int inByteOffset, AudioFormat format,
611 int floatOffset, int frameCount) {
612 if (floatOffset < 0 || frameCount < 0 || inByteOffset < 0) {
613 throw new IllegalArgumentException
614 ("FloatSampleBuffer.setSamplesFromBytes: negative inByteOffset, floatOffset, or frameCount");
615 }
616 if (inByteOffset + (frameCount * format.getFrameSize()) > input.length) {
617 throw new IllegalArgumentException
618 ("FloatSampleBuffer.setSamplesFromBytes: input buffer too small.");
619 }
620 if (floatOffset + frameCount > getSampleCount()) {
621 throw new IllegalArgumentException
622 ("FloatSampleBuffer.setSamplesFromBytes: frameCount too large");
623 }
624
625 FloatSampleTools.byte2float(input, inByteOffset, channels, floatOffset, frameCount, format);
626 }
627
628 //////////////////////////////// properties /////////////////////////////////
629
630 public int getChannelCount() {
631 return channelCount;
632 }
633
634 public int getSampleCount() {
635 return sampleCount;
636 }
637
638 public float getSampleRate() {
639 return sampleRate;
640 }
641
642 /**
643 * Sets the sample rate of this buffer.
644 * NOTE: no conversion is done. The samples are only re-interpreted.
645 */
646 public void setSampleRate(float sampleRate) {
647 if (sampleRate<=0) {
648 throw new IllegalArgumentException
649 ("Invalid samplerate for FloatSampleBuffer.");
650 }
651 this.sampleRate=sampleRate;
652 }
653
654 /**
655 * NOTE: the returned array may be larger than sampleCount. So in any case,
656 * sampleCount is to be respected.
657 */
658 public float[] getChannel(int channel) {
659 if (channel<0 || channel>=getChannelCount()) {
660 throw new IllegalArgumentException(
661 "FloatSampleBuffer: invalid channel number.");
662 }
663 return (float[]) channels.get(channel);
664 }
665
666 public Object[] getAllChannels() {
667 Object[] res=new Object[getChannelCount()];
668 for (int ch=0; ch<getChannelCount(); ch++) {
669 res[ch]=getChannel(ch);
670 }
671 return res;
672 }
673
674 /**
675 * Set the number of bits for dithering.
676 * Typically, a value between 0.2 and 0.9 gives best results.
677 * <p>Note: this value is only used, when dithering is actually performed.
678 */
679 public void setDitherBits(float ditherBits) {
680 if (ditherBits<=0) {
681 throw new IllegalArgumentException("DitherBits must be greater than 0");
682 }
683 this.ditherBits=ditherBits;
684 }
685
686 public float getDitherBits() {
687 return ditherBits;
688 }
689
690 /**
691 * Sets the mode for dithering.
692 * This can be one of:
693 * <ul><li>DITHER_MODE_AUTOMATIC: it is decided automatically,
694 * whether dithering is necessary - in general when sample size is
695 * decreased.
696 * <li>DITHER_MODE_ON: dithering will be forced
697 * <li>DITHER_MODE_OFF: dithering will not be done.
698 * </ul>
699 */
700 public void setDitherMode(int mode) {
701 if (mode!=DITHER_MODE_AUTOMATIC
702 && mode!=DITHER_MODE_ON
703 && mode!=DITHER_MODE_OFF) {
704 throw new IllegalArgumentException("Illegal DitherMode");
705 }
706 this.ditherMode=mode;
707 }
708
709 public int getDitherMode() {
710 return ditherMode;
711 }
712
713
714 /**
715 * @return the ditherBits parameter for the float2byte functions
716 */
717 protected float getConvertDitherBits(int newFormatType) {
718 // let's see whether dithering is necessary
719 boolean doDither = false;
720 switch (ditherMode) {
721 case DITHER_MODE_AUTOMATIC:
722 doDither=(originalFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK)>
723 (newFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK);
724 break;
725 case DITHER_MODE_ON:
726 doDither=true;
727 break;
728 case DITHER_MODE_OFF:
729 doDither=false;
730 break;
731 }
732 return doDither?ditherBits:0.0f;
733 }
734}
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
deleted file mode 100644
index 76913ba39e..0000000000
--- a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
+++ /dev/null
@@ -1,696 +0,0 @@
1/*
2 * FloatSampleTools.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.*;
32import javax.sound.sampled.*;
33import org.tritonus.share.TDebug;
34
35/**
36 * Utility functions for handling data in normalized float arrays.
37 * Each sample is linear in the range of [-1.0f, +1.0f].
38 * <p>
39 * Currently, the following bit sizes are supported:
40 * <ul>
41 * <li>8-bit
42 * <li>16-bit
43 * <li>packed 24-bit (stored in 3 bytes)
44 * <li>32-bit
45 * </ul>
46 * 8-bit data can be unsigned or signed. All other data is only
47 * supported in signed encoding.
48 *
49 * @see FloatSampleBuffer
50 * @author Florian Bomers
51 */
52
53public class FloatSampleTools {
54
55 /** default number of bits to be dithered: 0.7f */
56 public static final float DEFAULT_DITHER_BITS = 0.7f;
57
58 private static Random random = null;
59
60 // sample width (must be in order !)
61 static final int F_8=1;
62 static final int F_16=2;
63 static final int F_24=3;
64 static final int F_32=4;
65 static final int F_SAMPLE_WIDTH_MASK=F_8 | F_16 | F_24 | F_32;
66
67 // format bit-flags
68 static final int F_SIGNED=8;
69 static final int F_BIGENDIAN=16;
70
71 // supported formats
72 static final int CT_8S=F_8 | F_SIGNED;
73 static final int CT_8U=F_8;
74 static final int CT_16SB=F_16 | F_SIGNED | F_BIGENDIAN;
75 static final int CT_16SL=F_16 | F_SIGNED;
76 static final int CT_24SB=F_24 | F_SIGNED | F_BIGENDIAN;
77 static final int CT_24SL=F_24 | F_SIGNED;
78 static final int CT_32SB=F_32 | F_SIGNED | F_BIGENDIAN;
79 static final int CT_32SL=F_32 | F_SIGNED;
80
81 // ////////////////////////////// initialization /////////////////////////////// //
82
83 /** prevent instanciation */
84 private FloatSampleTools() {
85 }
86
87
88 // /////////////////// FORMAT / FORMAT TYPE /////////////////////////////////// //
89
90 /**
91 * only allow "packed" samples -- currently no support for 18, 20, 24_32 bits.
92 * @throws IllegalArgumentException
93 */
94 static void checkSupportedSampleSize(int ssib, int channels, int frameSize) {
95 if ((ssib*channels) != frameSize * 8) {
96 throw new IllegalArgumentException("unsupported sample size: "+ssib
97 +" stored in "+(frameSize/channels)+" bytes.");
98 }
99 }
100
101
102 /**
103 * Get the formatType code from the given format.
104 * @throws IllegalArgumentException
105 */
106 static int getFormatType(AudioFormat format) {
107 boolean signed = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED);
108 if (!signed &&
109 !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
110 throw new IllegalArgumentException
111 ("unsupported encoding: only PCM encoding supported.");
112 }
113 if (!signed && format.getSampleSizeInBits() != 8) {
114 throw new IllegalArgumentException
115 ("unsupported encoding: only 8-bit can be unsigned");
116 }
117 checkSupportedSampleSize(format.getSampleSizeInBits(),
118 format.getChannels(),
119 format.getFrameSize());
120
121 int formatType = getFormatType(format.getSampleSizeInBits(),
122 signed, format.isBigEndian());
123 return formatType;
124 }
125
126 /**
127 * @throws IllegalArgumentException
128 */
129 static int getFormatType(int ssib, boolean signed, boolean bigEndian) {
130 int bytesPerSample=ssib/8;
131 int res=0;
132 if (ssib==8) {
133 res=F_8;
134 } else if (ssib==16) {
135 res=F_16;
136 } else if (ssib==24) {
137 res=F_24;
138 } else if (ssib==32) {
139 res=F_32;
140 }
141 if (res==0) {
142 throw new IllegalArgumentException
143 ("FloatSampleBuffer: unsupported sample size of "
144 +ssib+" bits per sample.");
145 }
146 if (!signed && bytesPerSample>1) {
147 throw new IllegalArgumentException
148 ("FloatSampleBuffer: unsigned samples larger than "
149 +"8 bit are not supported");
150 }
151 if (signed) {
152 res|=F_SIGNED;
153 }
154 if (bigEndian && (ssib!=8)) {
155 res|=F_BIGENDIAN;
156 }
157 return res;
158 }
159
160 static int getSampleSize(int formatType) {
161 switch (formatType & F_SAMPLE_WIDTH_MASK) {
162 case F_8: return 1;
163 case F_16: return 2;
164 case F_24: return 3;
165 case F_32: return 4;
166 }
167 return 0;
168 }
169
170 /**
171 * Return a string representation of this format
172 */
173 static String formatType2Str(int formatType) {
174 String res=""+formatType+": ";
175 switch (formatType & F_SAMPLE_WIDTH_MASK) {
176 case F_8:
177 res+="8bit";
178 break;
179 case F_16:
180 res+="16bit";
181 break;
182 case F_24:
183 res+="24bit";
184 break;
185 case F_32:
186 res+="32bit";
187 break;
188 }
189 res+=((formatType & F_SIGNED)==F_SIGNED)?" signed":" unsigned";
190 if ((formatType & F_SAMPLE_WIDTH_MASK)!=F_8) {
191 res+=((formatType & F_BIGENDIAN)==F_BIGENDIAN)?
192 " big endian":" little endian";
193 }
194 return res;
195 }
196
197
198 // /////////////////// BYTE 2 FLOAT /////////////////////////////////// //
199
200 private static final float twoPower7=128.0f;
201 private static final float twoPower15=32768.0f;
202 private static final float twoPower23=8388608.0f;
203 private static final float twoPower31=2147483648.0f;
204
205 private static final float invTwoPower7=1/twoPower7;
206 private static final float invTwoPower15=1/twoPower15;
207 private static final float invTwoPower23=1/twoPower23;
208 private static final float invTwoPower31=1/twoPower31;
209
210
211 /**
212 * Conversion function to convert an interleaved byte array to
213 * a List of interleaved float arrays. The float arrays will contain normalized
214 * samples in the range [-1.0f, +1.0f]. The input array
215 * provides bytes in the format specified in <code>format</code>.
216 * <p>
217 * Only PCM formats are accepted. The method will convert all
218 * byte values from
219 * <code>input[inByteOffset]</code> to
220 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
221 * to floats from
222 * <code>output(n)[outOffset]</code> to
223 * <code>output(n)[outOffset + frameCount - 1]</code>
224 *
225 * @param input the audio data in an byte array
226 * @param inByteOffset index in input where to start the conversion
227 * @param output list of float[] arrays which receive the converted audio data.
228 * if the list does not contain enough elements, or individual float arrays
229 * are not large enough, they are created.
230 * @param outOffset the start offset in <code>output</code>
231 * @param frameCount number of frames to be converted
232 * @param format the input format. Only packed PCM is allowed
233 * @throws IllegalArgumentException if one of the parameters is out of bounds
234 *
235 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
236 */
237 public static void byte2float(byte[] input, int inByteOffset,
238 List<float[]> output, int outOffset, int frameCount,
239 //List output, int outOffset, int frameCount,
240 AudioFormat format) {
241 for (int channel = 0; channel < format.getChannels(); channel++) {
242 float[] data;
243 if (output.size() < channel) {
244 data = new float[frameCount + outOffset];
245 output.add(data);
246 } else {
247 data = output.get(channel);
248 if (data.length < frameCount + outOffset) {
249 data = new float[frameCount + outOffset];
250 output.set(channel, data);
251 }
252 }
253
254 byte2floatGeneric(input, inByteOffset, format.getFrameSize(),
255 data, outOffset,
256 frameCount, format);
257 inByteOffset += format.getFrameSize() / format.getChannels();
258 }
259 }
260
261
262 /**
263 * Conversion function to convert an interleaved byte array to
264 * an interleaved float array. The float array will contain normalized
265 * samples in the range [-1.0f, +1.0f]. The input array
266 * provides bytes in the format specified in <code>format</code>.
267 * <p>
268 * Only PCM formats are accepted. The method will convert all
269 * byte values from
270 * <code>input[inByteOffset]</code> to
271 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
272 * to floats from
273 * <code>output[outOffset]</code> to
274 * <code>output[outOffset + (frameCount * format.getChannels()) - 1]</code>
275 *
276 * @param input the audio data in an byte array
277 * @param inByteOffset index in input where to start the conversion
278 * @param output the float array that receives the converted audio data
279 * @param outOffset the start offset in <code>output</code>
280 * @param frameCount number of frames to be converted
281 * @param format the input format. Only packed PCM is allowed
282 * @throws IllegalArgumentException if one of the parameters is out of bounds
283 *
284 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
285 */
286 public static void byte2floatInterleaved(byte[] input, int inByteOffset,
287 float[] output, int outOffset, int frameCount,
288 AudioFormat format) {
289
290 byte2floatGeneric(input, inByteOffset, format.getFrameSize() / format.getChannels(),
291 output, outOffset, frameCount * format.getChannels(),
292 format);
293 }
294
295
296
297 /**
298 * Generic conversion function to convert a byte array to
299 * a float array.
300 * <p>
301 * Only PCM formats are accepted. The method will convert all
302 * bytes from
303 * <code>input[inByteOffset]</code> to
304 * <code>input[inByteOffset + (sampleCount * (inByteStep - 1)]</code>
305 * to samples from
306 * <code>output[outOffset]</code> to
307 * <code>output[outOffset+sampleCount-1]</code>.
308 * <p>
309 * The <code>format</code>'s channel count is ignored.
310 * <p>
311 * For mono data, set <code>inByteOffset</code> to <code>format.getFrameSize()</code>.<br>
312 * For converting interleaved input data, multiply <code>sampleCount</code>
313 * by the number of channels and set inByteStep to
314 * <code>format.getFrameSize() / format.getChannels()</code>.
315 *
316 * @param sampleCount number of samples to be written to output
317 * @param inByteStep how many bytes advance for each output sample in <code>output</code>.
318 * @throws IllegalArgumentException if one of the parameters is out of bounds
319 *
320 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
321 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
322 */
323 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
324 float[] output, int outOffset, int sampleCount,
325 AudioFormat format) {
326 int formatType = getFormatType(format);
327
328 byte2floatGeneric(input, inByteOffset, inByteStep,
329 output, outOffset, sampleCount,
330 formatType);
331 }
332
333
334 /**
335 * Central conversion function from
336 * a byte array to a normalized float array. In order to accomodate
337 * interleaved and non-interleaved
338 * samples, this method takes inByteStep as parameter which
339 * can be used to flexibly convert the data.
340 * <p>
341 * E.g.:<br>
342 * mono->mono: inByteStep=format.getFrameSize()<br>
343 * interleaved_stereo->interleaved_stereo: inByteStep=format.getFrameSize()/2,
344 * sampleCount*2<br>
345 * stereo->2 mono arrays:<br>
346 * ---inByteOffset=0, outOffset=0, inByteStep=format.getFrameSize()<br>
347 * ---inByteOffset=format.getFrameSize()/2, outOffset=1, inByteStep=format.getFrameSize()<br>
348 */
349 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
350 float[] output, int outOffset, int sampleCount,
351 int formatType) {
352 //if (TDebug.TraceAudioConverter) {
353 // TDebug.out("FloatSampleTools.byte2floatGeneric, formatType="
354 // +formatType2Str(formatType));
355 //}
356 int endCount = outOffset + sampleCount;
357 int inIndex = inByteOffset;
358 for (int outIndex = outOffset; outIndex < endCount; outIndex++, inIndex+=inByteStep) {
359 // do conversion
360 switch (formatType) {
361 case CT_8S:
362 output[outIndex]=
363 ((float) input[inIndex])*invTwoPower7;
364 break;
365 case CT_8U:
366 output[outIndex]=
367 ((float) ((input[inIndex] & 0xFF)-128))*invTwoPower7;
368 break;
369 case CT_16SB:
370 output[outIndex]=
371 ((float) ((input[inIndex]<<8)
372 | (input[inIndex+1] & 0xFF)))*invTwoPower15;
373 break;
374 case CT_16SL:
375 output[outIndex]=
376 ((float) ((input[inIndex+1]<<8)
377 | (input[inIndex] & 0xFF)))*invTwoPower15;
378 break;
379 case CT_24SB:
380 output[outIndex]=
381 ((float) ((input[inIndex]<<16)
382 | ((input[inIndex+1] & 0xFF)<<8)
383 | (input[inIndex+2] & 0xFF)))*invTwoPower23;
384 break;
385 case CT_24SL:
386 output[outIndex]=
387 ((float) ((input[inIndex+2]<<16)
388 | ((input[inIndex+1] & 0xFF)<<8)
389 | (input[inIndex] & 0xFF)))*invTwoPower23;
390 break;
391 case CT_32SB:
392 output[outIndex]=
393 ((float) ((input[inIndex]<<24)
394 | ((input[inIndex+1] & 0xFF)<<16)
395 | ((input[inIndex+2] & 0xFF)<<8)
396 | (input[inIndex+3] & 0xFF)))*invTwoPower31;
397 break;
398 case CT_32SL:
399 output[outIndex]=
400 ((float) ((input[inIndex+3]<<24)
401 | ((input[inIndex+2] & 0xFF)<<16)
402 | ((input[inIndex+1] & 0xFF)<<8)
403 | (input[inIndex] & 0xFF)))*invTwoPower31;
404 break;
405 default:
406 throw new IllegalArgumentException
407 ("unsupported format="+formatType2Str(formatType));
408 }
409 }
410 }
411
412 // /////////////////// FLOAT 2 BYTE /////////////////////////////////// //
413
414 private static byte quantize8(float sample, float ditherBits) {
415 if (ditherBits!=0) {
416 sample+=random.nextFloat()*ditherBits;
417 }
418 if (sample>=127.0f) {
419 return (byte) 127;
420 } else if (sample<=-128.0f) {
421 return (byte) -128;
422 } else {
423 return (byte) (sample<0?(sample-0.5f):(sample+0.5f));
424 }
425 }
426
427 private static int quantize16(float sample, float ditherBits) {
428 if (ditherBits!=0) {
429 sample+=random.nextFloat()*ditherBits;
430 }
431 if (sample>=32767.0f) {
432 return 32767;
433 } else if (sample<=-32768.0f) {
434 return -32768;
435 } else {
436 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
437 }
438 }
439
440 private static int quantize24(float sample, float ditherBits) {
441 if (ditherBits!=0) {
442 sample+=random.nextFloat()*ditherBits;
443 }
444 if (sample>=8388607.0f) {
445 return 8388607;
446 } else if (sample<=-8388608.0f) {
447 return -8388608;
448 } else {
449 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
450 }
451 }
452
453 private static int quantize32(float sample, float ditherBits) {
454 if (ditherBits!=0) {
455 sample+=random.nextFloat()*ditherBits;
456 }
457 if (sample>=2147483647.0f) {
458 return 2147483647;
459 } else if (sample<=-2147483648.0f) {
460 return -2147483648;
461 } else {
462 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
463 }
464 }
465
466
467 /**
468 * Conversion function to convert a non-interleaved float audio data to
469 * an interleaved byte array. The float arrays contains normalized
470 * samples in the range [-1.0f, +1.0f]. The output array
471 * will receive bytes in the format specified in <code>format</code>.
472 * Exactly <code>format.getChannels()</code> channels are converted
473 * regardless of the number of elements in <code>input</code>. If <code>input</code>
474 * does not provide enough channels, an </code>IllegalArgumentException<code> is thrown.
475 * <p>
476 * Only PCM formats are accepted. The method will convert all
477 * samples from <code>input(n)[inOffset]</code> to
478 * <code>input(n)[inOffset + frameCount - 1]</code>
479 * to byte values from <code>output[outByteOffset]</code> to
480 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
481 * <p>
482 * Dithering should be used when the output resolution is significantly
483 * lower than the original resolution. This includes if the original
484 * data was 16-bit and it is now converted to 8-bit, or if the
485 * data was generated in the float domain. No dithering need to be used
486 * if the original sample data was in e.g. 8-bit and the resulting output
487 * data has a higher resolution. If dithering is used, a sensitive value
488 * is DEFAULT_DITHER_BITS.
489 *
490 * @param input a List of float arrays with the input audio data
491 * @param inOffset index in the input arrays where to start the conversion
492 * @param output the byte array that receives the converted audio data
493 * @param outByteOffset the start offset in <code>output</code>
494 * @param frameCount number of frames to be converted.
495 * @param format the output format. Only packed PCM is allowed
496 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
497 * @throws IllegalArgumentException if one of the parameters is out of bounds
498 *
499 * @see #DEFAULT_DITHER_BITS
500 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
501 */
502 //public static void float2byte(List<float[]> input, int inOffset,
503 public static void float2byte(List input, int inOffset,
504 byte[] output, int outByteOffset,
505 int frameCount,
506 AudioFormat format, float ditherBits) {
507 for (int channel = 0; channel < format.getChannels(); channel++) {
508 float[] data = (float[]) input.get(channel);
509 float2byteGeneric(data, inOffset,
510 output, outByteOffset, format.getFrameSize(),
511 frameCount, format, ditherBits);
512 outByteOffset += format.getFrameSize() / format.getChannels();
513 }
514 }
515
516 /**
517 * Conversion function to convert an interleaved float array to
518 * an interleaved byte array. The float array contains normalized
519 * samples in the range [-1.0f, +1.0f]. The output array
520 * will receive bytes in the format specified in <code>format</code>.
521 * <p>
522 * Only PCM formats are accepted. The method will convert all
523 * samples from <code>input[inOffset]</code> to
524 * <code>input[inOffset + (frameCount * format.getChannels()) - 1]</code>
525 * to byte values from <code>output[outByteOffset]</code> to
526 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
527 * <p>
528 * Dithering should be used when the output resolution is significantly
529 * lower than the original resolution. This includes if the original
530 * data was 16-bit and it is now converted to 8-bit, or if the
531 * data was generated in the float domain. No dithering need to be used
532 * if the original sample data was in e.g. 8-bit and the resulting output
533 * data has a higher resolution. If dithering is used, a sensitive value
534 * is DEFAULT_DITHER_BITS.
535 *
536 * @param input the audio data in normalized samples
537 * @param inOffset index in input where to start the conversion
538 * @param output the byte array that receives the converted audio data
539 * @param outByteOffset the start offset in <code>output</code>
540 * @param frameCount number of frames to be converted.
541 * @param format the output format. Only packed PCM is allowed
542 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
543 * @throws IllegalArgumentException if one of the parameters is out of bounds
544 *
545 * @see #DEFAULT_DITHER_BITS
546 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
547 */
548 public static void float2byteInterleaved(float[] input, int inOffset,
549 byte[] output, int outByteOffset,
550 int frameCount,
551 AudioFormat format, float ditherBits) {
552 float2byteGeneric(input, inOffset,
553 output, outByteOffset, format.getFrameSize() / format.getChannels(),
554 frameCount * format.getChannels(),
555 format, ditherBits);
556 }
557
558
559
560 /**
561 * Generic conversion function to convert a float array to
562 * a byte array.
563 * <p>
564 * Only PCM formats are accepted. The method will convert all
565 * samples from <code>input[inOffset]</code> to
566 * <code>input[inOffset+sampleCount-1]</code>
567 * to byte values from <code>output[outByteOffset]</code> to
568 * <code>output[outByteOffset + (sampleCount * (outByteStep - 1)]</code>.
569 * <p>
570 * The <code>format</code>'s channel count is ignored.
571 * <p>
572 * For mono data, set <code>outByteOffset</code> to <code>format.getFrameSize()</code>.<br>
573 * For converting interleaved input data, multiply <code>sampleCount</code>
574 * by the number of channels and set outByteStep to
575 * <code>format.getFrameSize() / format.getChannels()</code>.
576 *
577 * @param sampleCount number of samples in input to be converted.
578 * @param outByteStep how many bytes advance for each input sample in <code>input</code>.
579 * @throws IllegalArgumentException if one of the parameters is out of bounds
580 *
581 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
582 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
583 */
584 static void float2byteGeneric(float[] input, int inOffset,
585 byte[] output, int outByteOffset, int outByteStep,
586 int sampleCount,
587 AudioFormat format, float ditherBits) {
588 int formatType = getFormatType(format);
589
590 float2byteGeneric(input, inOffset,
591 output, outByteOffset, outByteStep,
592 sampleCount,
593 formatType, ditherBits);
594 }
595
596
597 /**
598 * Central conversion function from normalized float array to
599 * a byte array. In order to accomodate interleaved and non-interleaved
600 * samples, this method takes outByteStep as parameter which
601 * can be used to flexibly convert the data.
602 * <p>
603 * E.g.:<br>
604 * mono->mono: outByteStep=format.getFrameSize()<br>
605 * interleaved stereo->interleaved stereo: outByteStep=format.getFrameSize()/2, sampleCount*2<br>
606 * 2 mono arrays->stereo:<br>
607 * ---inOffset=0, outByteOffset=0, outByteStep=format.getFrameSize()<br>
608 * ---inOffset=1, outByteOffset=format.getFrameSize()/2, outByteStep=format.getFrameSize()<br>
609 */
610 static void float2byteGeneric(float[] input, int inOffset,
611 byte[] output, int outByteOffset, int outByteStep,
612 int sampleCount, int formatType, float ditherBits) {
613 //if (TDebug.TraceAudioConverter) {
614 // TDebug.out("FloatSampleBuffer.float2byteGeneric, formatType="
615 // +"formatType2Str(formatType));
616 //}
617
618 if (inOffset < 0
619 || inOffset + sampleCount > input.length
620 || sampleCount < 0) {
621 throw new IllegalArgumentException("invalid input index: "
622 +"input.length="+input.length
623 +" inOffset="+inOffset
624 +" sampleCount="+sampleCount);
625 }
626 if (outByteOffset < 0
627 || outByteOffset + (sampleCount * outByteStep) > output.length
628 || outByteStep < getSampleSize(formatType)) {
629 throw new IllegalArgumentException("invalid output index: "
630 +"output.length="+output.length
631 +" outByteOffset="+outByteOffset
632 +" sampleCount="+sampleCount
633 +" format="+formatType2Str(formatType));
634 }
635
636 if (ditherBits!=0.0f && random==null) {
637 // create the random number generator for dithering
638 random=new Random();
639 }
640 int endSample = inOffset + sampleCount;
641 int iSample;
642 int outIndex = outByteOffset;
643 for (int inIndex = inOffset;
644 inIndex < endSample;
645 inIndex++, outIndex+=outByteStep) {
646 // do conversion
647 switch (formatType) {
648 case CT_8S:
649 output[outIndex]=quantize8(input[inIndex]*twoPower7, ditherBits);
650 break;
651 case CT_8U:
652 output[outIndex]=(byte) (quantize8((input[inIndex]*twoPower7), ditherBits)+128);
653 break;
654 case CT_16SB:
655 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
656 output[outIndex]=(byte) (iSample >> 8);
657 output[outIndex+1]=(byte) (iSample & 0xFF);
658 break;
659 case CT_16SL:
660 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
661 output[outIndex+1]=(byte) (iSample >> 8);
662 output[outIndex]=(byte) (iSample & 0xFF);
663 break;
664 case CT_24SB:
665 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
666 output[outIndex]=(byte) (iSample >> 16);
667 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
668 output[outIndex+2]=(byte) (iSample & 0xFF);
669 break;
670 case CT_24SL:
671 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
672 output[outIndex+2]=(byte) (iSample >> 16);
673 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
674 output[outIndex]=(byte) (iSample & 0xFF);
675 break;
676 case CT_32SB:
677 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
678 output[outIndex]=(byte) (iSample >> 24);
679 output[outIndex+1]=(byte) ((iSample >>> 16) & 0xFF);
680 output[outIndex+2]=(byte) ((iSample >>> 8) & 0xFF);
681 output[outIndex+3]=(byte) (iSample & 0xFF);
682 break;
683 case CT_32SL:
684 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
685 output[outIndex+3]=(byte) (iSample >> 24);
686 output[outIndex+2]=(byte) ((iSample >>> 16) & 0xFF);
687 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
688 output[outIndex]=(byte) (iSample & 0xFF);
689 break;
690 default:
691 throw new IllegalArgumentException
692 ("unsupported format="+formatType2Str(formatType));
693 }
694 }
695 }
696}
diff --git a/songdbj/org/tritonus/share/sampled/TAudioFormat.java b/songdbj/org/tritonus/share/sampled/TAudioFormat.java
deleted file mode 100644
index 7911d5e005..0000000000
--- a/songdbj/org/tritonus/share/sampled/TAudioFormat.java
+++ /dev/null
@@ -1,110 +0,0 @@
1/*
2 * TAudioFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.Map;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39public class TAudioFormat
40extends AudioFormat
41{
42 private Map<String, Object> m_properties;
43 private Map<String, Object> m_unmodifiableProperties;
44
45
46 public TAudioFormat(AudioFormat.Encoding encoding,
47 float sampleRate,
48 int sampleSizeInBits,
49 int channels,
50 int frameSize,
51 float frameRate,
52 boolean bigEndian,
53 Map<String, Object> properties)
54 {
55 super(encoding,
56 sampleRate,
57 sampleSizeInBits,
58 channels,
59 frameSize,
60 frameRate,
61 bigEndian);
62 initMaps(properties);
63 }
64
65
66 public TAudioFormat(float sampleRate,
67 int sampleSizeInBits,
68 int channels,
69 boolean signed,
70 boolean bigEndian,
71 Map<String, Object> properties)
72 {
73 super(sampleRate,
74 sampleSizeInBits,
75 channels,
76 signed,
77 bigEndian);
78 initMaps(properties);
79 }
80
81
82
83 private void initMaps(Map<String, Object> properties)
84 {
85 /* Here, we make a shallow copy of the map. It's unclear if this
86 is sufficient (or if a deep copy should be made).
87 */
88 m_properties = new HashMap<String, Object>();
89 m_properties.putAll(properties);
90 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
91 }
92
93
94
95 public Map<String, Object> properties()
96 {
97 return m_unmodifiableProperties;
98 }
99
100
101
102 protected void setProperty(String key, Object value)
103 {
104 m_properties.put(key, value);
105 }
106}
107
108
109
110/*** TAudioFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TConversionTool.java b/songdbj/org/tritonus/share/sampled/TConversionTool.java
deleted file mode 100644
index 18673edf31..0000000000
--- a/songdbj/org/tritonus/share/sampled/TConversionTool.java
+++ /dev/null
@@ -1,1224 +0,0 @@
1/*
2 * TConversionTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34
35/**
36 * Useful methods for converting audio data.
37 *
38 * @author Florian Bomers
39 * @author Matthias Pfisterer
40 */
41
42/*
43For convenience, a list of available methods is maintained here.
44Some hints:
45- buffers: always byte arrays
46- offsets: always in bytes
47- sampleCount: number of SAMPLES to read/write, as opposed to FRAMES or BYTES!
48- when in buffer and out buffer are given, the data is copied,
49 otherwise it is replaced in the same buffer (buffer size is not checked!)
50- a number (except "2") gives the number of bits in which format
51 the samples have to be.
52- >8 bits per sample is always treated signed.
53- all functions are tried to be optimized - hints welcome !
54
55
56** "high level" methods **
57changeOrderOrSign(buffer, nOffset, nByteLength, nBytesPerSample)
58changeOrderOrSign(inBuffer, nInOffset, outBuffer, nOutOffset, nByteLength, nBytesPerSample)
59
60
61** PCM byte order and sign conversion **
62void convertSign8(buffer, byteOffset, sampleCount)
63void swapOrder16(buffer, byteOffset, sampleCount)
64void swapOrder24(buffer, byteOffset, sampleCount)
65void swapOrder32(buffer, byteOffset, sampleCount)
66void convertSign8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
67void swapOrder16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
68void swapOrder24(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
69void swapOrder32(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
70
71
72** conversion functions for byte arrays **
73** these are for reference to see how to implement these conversions **
74short bytesToShort16(highByte, lowByte)
75short bytesToShort16(buffer, byteOffset, bigEndian)
76short bytesToInt16(highByte, lowByte)
77short bytesToInt16(buffer, byteOffset, bigEndian)
78short bytesToInt24(buffer, byteOffset, bigEndian)
79short bytesToInt32(buffer, byteOffset, bigEndian)
80void shortToBytes16(sample, buffer, byteOffset, bigEndian)
81void intToBytes24(sample, buffer, byteOffset, bigEndian)
82void intToBytes32(sample, buffer, byteOffset, bigEndian)
83
84
85** ULAW <-> PCM **
86byte linear2ulaw(int sample)
87short ulaw2linear(int ulawbyte)
88void pcm162ulaw(buffer, byteOffset, sampleCount, bigEndian)
89void pcm162ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
90void pcm82ulaw(buffer, byteOffset, sampleCount, signed)
91void pcm82ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
92void ulaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
93void ulaw2pcm8(buffer, byteOffset, sampleCount, signed)
94void ulaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
95
96
97** ALAW <-> PCM **
98byte linear2alaw(short pcm_val)
99short alaw2linear(byte ulawbyte)
100void pcm162alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
101void pcm162alaw(buffer, byteOffset, sampleCount, bigEndian)
102void pcm82alaw(buffer, byteOffset, sampleCount, signed)
103void pcm82alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
104void alaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
105void alaw2pcm8(buffer, byteOffset, sampleCount, signed)
106void alaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
107
108
109** ULAW <-> ALAW **
110byte ulaw2alaw(byte sample)
111void ulaw2alaw(buffer, byteOffset, sampleCount)
112void ulaw2alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
113byte alaw2ulaw(byte sample)
114void alaw2ulaw(buffer, byteOffset, sampleCount)
115void alaw2ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
116
117*/
118
119public class TConversionTool {
120
121 ///////////////// sign/byte-order conversion ///////////////////////////////////
122
123 public static void convertSign8(byte[] buffer, int byteOffset, int sampleCount) {
124 sampleCount+=byteOffset;
125 for (int i=byteOffset; i<sampleCount; i++) {
126 buffer[i]+=128;
127 }
128 }
129
130 public static void swapOrder16(byte[] buffer, int byteOffset, int sampleCount) {
131 int byteMax=sampleCount*2+byteOffset-1;
132 int i=byteOffset;
133 while (i<byteMax) {
134 byte h=buffer[i];
135 buffer[i]=buffer[++i];
136 buffer[i++]=h;
137 }
138 }
139
140 public static void swapOrder24(byte[] buffer, int byteOffset, int sampleCount) {
141 int byteMax=sampleCount*3+byteOffset-2;
142 int i=byteOffset;
143 while (i<byteMax) {
144 byte h=buffer[i];
145 buffer[i]=buffer[++i+1];
146 buffer[++i]=h;
147 i++;
148 }
149 }
150
151 public static void swapOrder32(byte[] buffer, int byteOffset, int sampleCount) {
152 int byteMax=sampleCount*4+byteOffset-3;
153 int i=byteOffset;
154 while (i<byteMax) {
155 byte h=buffer[i];
156 buffer[i]=buffer[i+3];
157 buffer[i+3]=h;
158 i++;
159 h=buffer[i];
160 buffer[i]=buffer[++i];
161 buffer[i++]=h;
162 i++;
163 }
164 }
165
166 public static void convertSign8(byte[] inBuffer, int inByteOffset,
167 byte[] outBuffer, int outByteOffset, int sampleCount) {
168 while (sampleCount>0) {
169 outBuffer[outByteOffset++]=(byte)(inBuffer[inByteOffset++]+128);
170 sampleCount--;
171 }
172 }
173
174 public static void swapOrder16(byte[] inBuffer, int inByteOffset,
175 byte[] outBuffer, int outByteOffset, int sampleCount) {
176 while (sampleCount>0) {
177 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
178 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
179 inByteOffset++;
180 sampleCount--;
181 }
182 }
183
184 public static void swapOrder24(byte[] inBuffer, int inByteOffset,
185 byte[] outBuffer, int outByteOffset, int sampleCount) {
186 while (sampleCount>0) {
187 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
188 outByteOffset++;
189 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
190 inByteOffset++;
191 inByteOffset++;
192 sampleCount--;
193 }
194 }
195
196 public static void swapOrder32(byte[] inBuffer, int inByteOffset,
197 byte[] outBuffer, int outByteOffset, int sampleCount) {
198 while (sampleCount>0) {
199 outBuffer[outByteOffset++]=inBuffer[inByteOffset+3];
200 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
201 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
202 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
203 inByteOffset++;
204 inByteOffset++;
205 inByteOffset++;
206 sampleCount--;
207 }
208 }
209
210
211 ///////////////// conversion functions for byte arrays ////////////////////////////
212
213
214 /**
215 * Converts 2 bytes to a signed sample of type <code>short</code>.
216 * <p> This is a reference function.
217 */
218 public static short bytesToShort16(byte highByte, byte lowByte) {
219 return (short) ((highByte<<8) | (lowByte & 0xFF));
220 }
221
222 /**
223 * Converts 2 successive bytes starting at <code>byteOffset</code> in
224 * <code>buffer</code> to a signed sample of type <code>short</code>.
225 * <p>
226 * For little endian, buffer[byteOffset] is interpreted as low byte,
227 * whereas it is interpreted as high byte in big endian.
228 * <p> This is a reference function.
229 */
230 public static short bytesToShort16(byte[] buffer, int byteOffset, boolean bigEndian) {
231 return bigEndian?
232 ((short) ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF))):
233 ((short) ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF)));
234 }
235
236 /**
237 * Converts 2 bytes to a signed integer sample with 16bit range.
238 * <p> This is a reference function.
239 */
240 public static int bytesToInt16(byte highByte, byte lowByte) {
241 return (highByte<<8) | (lowByte & 0xFF);
242 }
243
244 /**
245 * Converts 2 successive bytes starting at <code>byteOffset</code> in
246 * <code>buffer</code> to a signed integer sample with 16bit range.
247 * <p>
248 * For little endian, buffer[byteOffset] is interpreted as low byte,
249 * whereas it is interpreted as high byte in big endian.
250 * <p> This is a reference function.
251 */
252 public static int bytesToInt16(byte[] buffer, int byteOffset, boolean bigEndian) {
253 return bigEndian?
254 ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF)):
255 ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF));
256 }
257
258 /**
259 * Converts 3 successive bytes starting at <code>byteOffset</code> in
260 * <code>buffer</code> to a signed integer sample with 24bit range.
261 * <p>
262 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
263 * whereas it is interpreted as highest byte in big endian.
264 * <p> This is a reference function.
265 */
266 public static int bytesToInt24(byte[] buffer, int byteOffset, boolean bigEndian) {
267 return bigEndian?
268 ((buffer[byteOffset]<<16) // let Java handle sign-bit
269 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
270 | (buffer[byteOffset+2] & 0xFF)):
271 ((buffer[byteOffset+2]<<16) // let Java handle sign-bit
272 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
273 | (buffer[byteOffset] & 0xFF));
274 }
275
276 /**
277 * Converts a 4 successive bytes starting at <code>byteOffset</code> in
278 * <code>buffer</code> to a signed 32bit integer sample.
279 * <p>
280 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
281 * whereas it is interpreted as highest byte in big endian.
282 * <p> This is a reference function.
283 */
284 public static int bytesToInt32(byte[] buffer, int byteOffset, boolean bigEndian) {
285 return bigEndian?
286 ((buffer[byteOffset]<<24) // let Java handle sign-bit
287 | ((buffer[byteOffset+1] & 0xFF)<<16) // inhibit sign-bit handling
288 | ((buffer[byteOffset+2] & 0xFF)<<8) // inhibit sign-bit handling
289 | (buffer[byteOffset+3] & 0xFF)):
290 ((buffer[byteOffset+3]<<24) // let Java handle sign-bit
291 | ((buffer[byteOffset+2] & 0xFF)<<16) // inhibit sign-bit handling
292 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
293 | (buffer[byteOffset] & 0xFF));
294 }
295
296
297 /**
298 * Converts a sample of type <code>short</code> to 2 bytes in an array.
299 * <code>sample</code> is interpreted as signed (as Java does).
300 * <p>
301 * For little endian, buffer[byteOffset] is filled with low byte of sample,
302 * and buffer[byteOffset+1] is filled with high byte of sample.
303 * <p> For big endian, this is reversed.
304 * <p> This is a reference function.
305 */
306 public static void shortToBytes16(short sample, byte[] buffer, int byteOffset, boolean bigEndian) {
307 intToBytes16(sample, buffer, byteOffset, bigEndian);
308 }
309
310 /**
311 * Converts a 16 bit sample of type <code>int</code> to 2 bytes in an array.
312 * <code>sample</code> is interpreted as signed (as Java does).
313 * <p>
314 * For little endian, buffer[byteOffset] is filled with low byte of sample,
315 * and buffer[byteOffset+1] is filled with high byte of sample + sign bit.
316 * <p> For big endian, this is reversed.
317 * <p> Before calling this function, it should be assured that <code>sample</code>
318 * is in the 16bit range - it will not be clipped.
319 * <p> This is a reference function.
320 */
321 public static void intToBytes16(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
322 if (bigEndian) {
323 buffer[byteOffset++]=(byte) (sample >> 8);
324 buffer[byteOffset]=(byte) (sample & 0xFF);
325 } else {
326 buffer[byteOffset++]=(byte) (sample & 0xFF);
327 buffer[byteOffset]=(byte) (sample >> 8);
328 }
329 }
330
331 /**
332 * Converts a 24 bit sample of type <code>int</code> to 3 bytes in an array.
333 * <code>sample</code> is interpreted as signed (as Java does).
334 * <p>
335 * For little endian, buffer[byteOffset] is filled with low byte of sample,
336 * and buffer[byteOffset+2] is filled with the high byte of sample + sign bit.
337 * <p> For big endian, this is reversed.
338 * <p> Before calling this function, it should be assured that <code>sample</code>
339 * is in the 24bit range - it will not be clipped.
340 * <p> This is a reference function.
341 */
342 public static void intToBytes24(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
343 if (bigEndian) {
344 buffer[byteOffset++]=(byte) (sample >> 16);
345 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
346 buffer[byteOffset]=(byte) (sample & 0xFF);
347 } else {
348 buffer[byteOffset++]=(byte) (sample & 0xFF);
349 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
350 buffer[byteOffset]=(byte) (sample >> 16);
351 }
352 }
353
354
355 /**
356 * Converts a 32 bit sample of type <code>int</code> to 4 bytes in an array.
357 * <code>sample</code> is interpreted as signed (as Java does).
358 * <p>
359 * For little endian, buffer[byteOffset] is filled with lowest byte of sample,
360 * and buffer[byteOffset+3] is filled with the high byte of sample + sign bit.
361 * <p> For big endian, this is reversed.
362 * <p> This is a reference function.
363 */
364 public static void intToBytes32(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
365 if (bigEndian) {
366 buffer[byteOffset++]=(byte) (sample >> 24);
367 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
368 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
369 buffer[byteOffset]=(byte) (sample & 0xFF);
370 } else {
371 buffer[byteOffset++]=(byte) (sample & 0xFF);
372 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
373 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
374 buffer[byteOffset]=(byte) (sample >> 24);
375 }
376 }
377
378
379 /////////////////////// ULAW ///////////////////////////////////////////
380
381 private static final boolean ZEROTRAP=true;
382 private static final short BIAS=0x84;
383 private static final int CLIP=32635;
384 private static final int exp_lut1[] ={
385 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
386 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
387 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
388 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
389 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
390 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
391 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
392 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
393 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
394 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
395 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
396 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
397 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
398 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
399 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
400 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
401 };
402
403
404 /**
405 * Converts a linear signed 16bit sample to a uLaw byte.
406 * Ported to Java by fb.
407 * <BR>Originally by:<BR>
408 * Craig Reese: IDA/Supercomputing Research Center <BR>
409 * Joe Campbell: Department of Defense <BR>
410 * 29 September 1989 <BR>
411 */
412 public static byte linear2ulaw(int sample) {
413 int sign, exponent, mantissa, ulawbyte;
414
415 if (sample>32767) sample=32767;
416 else if (sample<-32768) sample=-32768;
417 /* Get the sample into sign-magnitude. */
418 sign = (sample >> 8) & 0x80; /* set aside the sign */
419 if (sign != 0) sample = -sample; /* get magnitude */
420 if (sample > CLIP) sample = CLIP; /* clip the magnitude */
421
422 /* Convert from 16 bit linear to ulaw. */
423 sample = sample + BIAS;
424 exponent = exp_lut1[(sample >> 7) & 0xFF];
425 mantissa = (sample >> (exponent + 3)) & 0x0F;
426 ulawbyte = ~(sign | (exponent << 4) | mantissa);
427 if (ZEROTRAP)
428 if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
429 return((byte) ulawbyte);
430 }
431
432 /* u-law to linear conversion table */
433 private static short[] u2l = {
434 -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
435 -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
436 -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
437 -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
438 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
439 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
440 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
441 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
442 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
443 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
444 -876, -844, -812, -780, -748, -716, -684, -652,
445 -620, -588, -556, -524, -492, -460, -428, -396,
446 -372, -356, -340, -324, -308, -292, -276, -260,
447 -244, -228, -212, -196, -180, -164, -148, -132,
448 -120, -112, -104, -96, -88, -80, -72, -64,
449 -56, -48, -40, -32, -24, -16, -8, 0,
450 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
451 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
452 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
453 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
454 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
455 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
456 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
457 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
458 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
459 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
460 876, 844, 812, 780, 748, 716, 684, 652,
461 620, 588, 556, 524, 492, 460, 428, 396,
462 372, 356, 340, 324, 308, 292, 276, 260,
463 244, 228, 212, 196, 180, 164, 148, 132,
464 120, 112, 104, 96, 88, 80, 72, 64,
465 56, 48, 40, 32, 24, 16, 8, 0
466 };
467 public static short ulaw2linear(byte ulawbyte) {
468 return u2l[ulawbyte & 0xFF];
469 }
470
471
472
473 /**
474 * Converts a buffer of signed 16bit big endian samples to uLaw.
475 * The uLaw bytes overwrite the original 16 bit values.
476 * The first byte-offset of the uLaw bytes is byteOffset.
477 * It will be written sampleCount/2 bytes.
478 */
479 public static void pcm162ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
480 int shortIndex=byteOffset;
481 int ulawIndex=shortIndex;
482 if (bigEndian) {
483 while (sampleCount>0) {
484 buffer[ulawIndex++]=linear2ulaw
485 (bytesToInt16(buffer[shortIndex], buffer[shortIndex+1]));
486 shortIndex++;
487 shortIndex++;
488 sampleCount--;
489 }
490 } else {
491 while (sampleCount>0) {
492 buffer[ulawIndex++]=linear2ulaw
493 (bytesToInt16(buffer[shortIndex+1], buffer[shortIndex]));
494 shortIndex++;
495 shortIndex++;
496 sampleCount--;
497 }
498 }
499 }
500
501 /**
502 * Fills outBuffer with ulaw samples.
503 * reading starts from inBuffer[inByteOffset].
504 * writing starts at outBuffer[outByteOffset].
505 * There will be sampleCount*2 bytes read from inBuffer;
506 * There will be sampleCount <B>bytes</B> written to outBuffer.
507 */
508 public static void pcm162ulaw(byte[] inBuffer, int inByteOffset,
509 byte[] outBuffer, int outByteOffset,
510 int sampleCount, boolean bigEndian) {
511 int shortIndex=inByteOffset;
512 int ulawIndex=outByteOffset;
513 if (bigEndian) {
514 while (sampleCount>0) {
515 outBuffer[ulawIndex++]=linear2ulaw
516 (bytesToInt16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
517 shortIndex++;
518 shortIndex++;
519 sampleCount--;
520 }
521 } else {
522 while (sampleCount>0) {
523 outBuffer[ulawIndex++]=linear2ulaw
524 (bytesToInt16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
525 shortIndex++;
526 shortIndex++;
527 sampleCount--;
528 }
529 }
530 }
531
532 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
533 /**
534 * Converts a buffer of 8bit samples to uLaw.
535 * The uLaw bytes overwrite the original 8 bit values.
536 * The first byte-offset of the uLaw bytes is byteOffset.
537 * It will be written sampleCount bytes.
538 */
539 public static void pcm82ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
540 sampleCount+=byteOffset;
541 if (signed) {
542 for (int i=byteOffset; i<sampleCount; i++) {
543 buffer[i]=linear2ulaw(buffer[i] << 8);
544 }
545 } else {
546 for (int i=byteOffset; i<sampleCount; i++) {
547 buffer[i]=linear2ulaw(((byte) (buffer[i]+128)) << 8);
548 }
549 }
550 }
551
552 /**
553 * Fills outBuffer with ulaw samples.
554 * reading starts from inBuffer[inByteOffset].
555 * writing starts at outBuffer[outByteOffset].
556 * There will be sampleCount <B>bytes</B> written to outBuffer.
557 */
558 public static void pcm82ulaw(byte[] inBuffer, int inByteOffset,
559 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
560 int ulawIndex=outByteOffset;
561 int pcmIndex=inByteOffset;
562 if (signed) {
563 while (sampleCount>0) {
564 outBuffer[ulawIndex++]=linear2ulaw(inBuffer[pcmIndex++] << 8);
565 sampleCount--;
566 }
567 } else {
568 while (sampleCount>0) {
569 outBuffer[ulawIndex++]=linear2ulaw(((byte) (inBuffer[pcmIndex++]+128)) << 8);
570 sampleCount--;
571 }
572 }
573 }
574
575 /**
576 * Fills outBuffer with pcm signed 16 bit samples.
577 * reading starts from inBuffer[inByteOffset].
578 * writing starts at outBuffer[outByteOffset].
579 * There will be sampleCount bytes read from inBuffer;
580 * There will be sampleCount*2 bytes written to outBuffer.
581 */
582 public static void ulaw2pcm16(byte[] inBuffer, int inByteOffset,
583 byte[] outBuffer, int outByteOffset,
584 int sampleCount, boolean bigEndian) {
585 int shortIndex=outByteOffset;
586 int ulawIndex=inByteOffset;
587 while (sampleCount>0) {
588 intToBytes16
589 (u2l[inBuffer[ulawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
590 shortIndex++;
591 sampleCount--;
592 }
593 }
594
595
596 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
597 /**
598 * Inplace-conversion of a ulaw buffer to 8bit samples.
599 * The 8bit bytes overwrite the original ulaw values.
600 * The first byte-offset of the uLaw bytes is byteOffset.
601 * It will be written sampleCount bytes.
602 */
603 public static void ulaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
604 sampleCount+=byteOffset;
605 if (signed) {
606 for (int i=byteOffset; i<sampleCount; i++) {
607 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF] >> 8) & 0xFF);
608 }
609 } else {
610 for (int i=byteOffset; i<sampleCount; i++) {
611 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF]>>8)+128);
612 }
613 }
614 }
615
616 /**
617 * Fills outBuffer with ulaw samples.
618 * reading starts from inBuffer[inByteOffset].
619 * writing starts at outBuffer[outByteOffset].
620 * There will be sampleCount <B>bytes</B> written to outBuffer.
621 */
622 public static void ulaw2pcm8(byte[] inBuffer, int inByteOffset,
623 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
624 int ulawIndex=inByteOffset;
625 int pcmIndex=outByteOffset;
626 if (signed) {
627 while (sampleCount>0) {
628 outBuffer[pcmIndex++]=
629 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF] >> 8) & 0xFF);
630 sampleCount--;
631 }
632 } else {
633 while (sampleCount>0) {
634 outBuffer[pcmIndex++]=
635 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF]>>8)+128);
636 sampleCount--;
637 }
638 }
639 }
640
641
642 //////////////////// ALAW ////////////////////////////
643
644
645 /*
646 * This source code is a product of Sun Microsystems, Inc. and is provided
647 * for unrestricted use. Users may copy or modify this source code without
648 * charge.
649 *
650 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
651 *
652 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
653 *
654 * Linear Input Code Compressed Code
655 * ------------------------ ---------------
656 * 0000000wxyza 000wxyz
657 * 0000001wxyza 001wxyz
658 * 000001wxyzab 010wxyz
659 * 00001wxyzabc 011wxyz
660 * 0001wxyzabcd 100wxyz
661 * 001wxyzabcde 101wxyz
662 * 01wxyzabcdef 110wxyz
663 * 1wxyzabcdefg 111wxyz
664 *
665 * For further information see John C. Bellamy's Digital Telephony, 1982,
666 * John Wiley & Sons, pps 98-111 and 472-476.
667 */
668 private static final byte QUANT_MASK = 0xf; /* Quantization field mask. */
669 private static final byte SEG_SHIFT = 4; /* Left shift for segment number. */
670 private static final short[] seg_end = {
671 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
672 };
673
674 public static byte linear2alaw(short pcm_val) /* 2's complement (16-bit range) */
675 {
676 byte mask;
677 byte seg=8;
678 byte aval;
679
680 if (pcm_val >= 0) {
681 mask = (byte) 0xD5; /* sign (7th) bit = 1 */
682 } else {
683 mask = 0x55; /* sign bit = 0 */
684 pcm_val = (short) (-pcm_val - 8);
685 }
686
687 /* Convert the scaled magnitude to segment number. */
688 for (int i = 0; i < 8; i++) {
689 if (pcm_val <= seg_end[i]) {
690 seg=(byte) i;
691 break;
692 }
693 }
694
695 /* Combine the sign, segment, and quantization bits. */
696 if (seg >= 8) /* out of range, return maximum value. */
697 return (byte) ((0x7F ^ mask) & 0xFF);
698 else {
699 aval = (byte) (seg << SEG_SHIFT);
700 if (seg < 2)
701 aval |= (pcm_val >> 4) & QUANT_MASK;
702 else
703 aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
704 return (byte) ((aval ^ mask) & 0xFF);
705 }
706 }
707
708 private static short[] a2l = {
709 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
710 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
711 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
712 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
713 -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
714 -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
715 -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
716 -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
717 -344, -328, -376, -360, -280, -264, -312, -296,
718 -472, -456, -504, -488, -408, -392, -440, -424,
719 -88, -72, -120, -104, -24, -8, -56, -40,
720 -216, -200, -248, -232, -152, -136, -184, -168,
721 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
722 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
723 -688, -656, -752, -720, -560, -528, -624, -592,
724 -944, -912, -1008, -976, -816, -784, -880, -848,
725 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
726 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
727 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
728 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
729 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
730 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
731 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
732 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
733 344, 328, 376, 360, 280, 264, 312, 296,
734 472, 456, 504, 488, 408, 392, 440, 424,
735 88, 72, 120, 104, 24, 8, 56, 40,
736 216, 200, 248, 232, 152, 136, 184, 168,
737 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
738 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
739 688, 656, 752, 720, 560, 528, 624, 592,
740 944, 912, 1008, 976, 816, 784, 880, 848
741 };
742
743 public static short alaw2linear(byte ulawbyte) {
744 return a2l[ulawbyte & 0xFF];
745 }
746
747 /**
748 * Converts a buffer of signed 16bit big endian samples to uLaw.
749 * The uLaw bytes overwrite the original 16 bit values.
750 * The first byte-offset of the uLaw bytes is byteOffset.
751 * It will be written sampleCount/2 bytes.
752 */
753 public static void pcm162alaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
754 int shortIndex=byteOffset;
755 int alawIndex=shortIndex;
756 if (bigEndian) {
757 while (sampleCount>0) {
758 buffer[alawIndex++]=
759 linear2alaw(bytesToShort16
760 (buffer[shortIndex], buffer[shortIndex+1]));
761 shortIndex++;
762 shortIndex++;
763 sampleCount--;
764 }
765 } else {
766 while (sampleCount>0) {
767 buffer[alawIndex++]=
768 linear2alaw(bytesToShort16
769 (buffer[shortIndex+1], buffer[shortIndex]));
770 shortIndex++;
771 shortIndex++;
772 sampleCount--;
773 }
774 }
775 }
776
777 /**
778 * Fills outBuffer with alaw samples.
779 * reading starts from inBuffer[inByteOffset].
780 * writing starts at outBuffer[outByteOffset].
781 * There will be sampleCount*2 bytes read from inBuffer;
782 * There will be sampleCount <B>bytes</B> written to outBuffer.
783 */
784 public static void pcm162alaw(byte[] inBuffer, int inByteOffset,
785 byte[] outBuffer, int outByteOffset, int sampleCount, boolean bigEndian) {
786 int shortIndex=inByteOffset;
787 int alawIndex=outByteOffset;
788 if (bigEndian) {
789 while (sampleCount>0) {
790 outBuffer[alawIndex++]=linear2alaw
791 (bytesToShort16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
792 shortIndex++;
793 shortIndex++;
794 sampleCount--;
795 }
796 } else {
797 while (sampleCount>0) {
798 outBuffer[alawIndex++]=linear2alaw
799 (bytesToShort16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
800 shortIndex++;
801 shortIndex++;
802 sampleCount--;
803 }
804 }
805 }
806
807 /**
808 * Converts a buffer of 8bit samples to alaw.
809 * The alaw bytes overwrite the original 8 bit values.
810 * The first byte-offset of the aLaw bytes is byteOffset.
811 * It will be written sampleCount bytes.
812 */
813 public static void pcm82alaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
814 sampleCount+=byteOffset;
815 if (signed) {
816 for (int i=byteOffset; i<sampleCount; i++) {
817 buffer[i]=linear2alaw((short) (buffer[i] << 8));
818 }
819 } else {
820 for (int i=byteOffset; i<sampleCount; i++) {
821 buffer[i]=linear2alaw((short) (((byte) (buffer[i]+128)) << 8));
822 }
823 }
824 }
825
826 /**
827 * Fills outBuffer with alaw samples.
828 * reading starts from inBuffer[inByteOffset].
829 * writing starts at outBuffer[outByteOffset].
830 * There will be sampleCount <B>bytes</B> written to outBuffer.
831 */
832 public static void pcm82alaw(byte[] inBuffer, int inByteOffset,
833 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
834 int alawIndex=outByteOffset;
835 int pcmIndex=inByteOffset;
836 if (signed) {
837 while (sampleCount>0) {
838 outBuffer[alawIndex++]=
839 linear2alaw((short) (inBuffer[pcmIndex++] << 8));
840 sampleCount--;
841 }
842 } else {
843 while (sampleCount>0) {
844 outBuffer[alawIndex++]=
845 linear2alaw((short) (((byte) (inBuffer[pcmIndex++]+128)) << 8));
846 sampleCount--;
847 }
848 }
849 }
850
851
852
853 /**
854 * Converts an alaw buffer to 8bit pcm samples
855 * The 8bit bytes overwrite the original alaw values.
856 * The first byte-offset of the aLaw bytes is byteOffset.
857 * It will be written sampleCount bytes.
858 */
859 public static void alaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
860 sampleCount+=byteOffset;
861 if (signed) {
862 for (int i=byteOffset; i<sampleCount; i++) {
863 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF] >> 8) & 0xFF);
864 }
865 } else {
866 for (int i=byteOffset; i<sampleCount; i++) {
867 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF]>>8)+128);
868 }
869 }
870 }
871
872 /**
873 * Fills outBuffer with alaw samples.
874 * reading starts from inBuffer[inByteOffset].
875 * writing starts at outBuffer[outByteOffset].
876 * There will be sampleCount <B>bytes</B> written to outBuffer.
877 */
878 public static void alaw2pcm8(byte[] inBuffer, int inByteOffset,
879 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
880 int alawIndex=inByteOffset;
881 int pcmIndex=outByteOffset;
882 if (signed) {
883 while (sampleCount>0) {
884 outBuffer[pcmIndex++]=
885 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF] >> 8) & 0xFF);
886 sampleCount--;
887 }
888 } else {
889 while (sampleCount>0) {
890 outBuffer[pcmIndex++]=
891 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF]>>8)+128);
892 sampleCount--;
893 }
894 }
895 }
896
897 /**
898 * Fills outBuffer with pcm signed 16 bit samples.
899 * reading starts from inBuffer[inByteOffset].
900 * writing starts at outBuffer[outByteOffset].
901 * There will be sampleCount bytes read from inBuffer;
902 * There will be sampleCount*2 bytes written to outBuffer.
903 */
904 public static void alaw2pcm16(byte[] inBuffer, int inByteOffset,
905 byte[] outBuffer, int outByteOffset,
906 int sampleCount, boolean bigEndian) {
907 int shortIndex=outByteOffset;
908 int alawIndex=inByteOffset;
909 while (sampleCount>0) {
910 intToBytes16
911 (a2l[inBuffer[alawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
912 shortIndex++;
913 sampleCount--;
914 }
915 }
916
917 //////////////////////// cross conversion alaw <-> ulaw ////////////////////////////////////////
918
919 private static byte[] u2a = {
920 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
921 -70, -69, -72, -71, -66, -65, -68, -67, -78, -77, -80, -79, -74, -73, -76, -75,
922 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
923 -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107, -22,
924 -24, -23, -18, -17, -20, -19, -30, -29, -32, -31, -26, -25, -28, -27, -6, -8,
925 -2, -1, -4, -3, -14, -13, -16, -15, -10, -9, -12, -11, -53, -55, -49, -51,
926 -62, -61, -64, -63, -58, -57, -60, -59, -38, -37, -40, -39, -34, -33, -36, -35,
927 -46, -46, -45, -45, -48, -48, -47, -47, -42, -42, -41, -41, -44, -44, -43, -43,
928 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
929 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53,
930 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
931 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106,
932 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120,
933 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77,
934 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93,
935 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85,
936 };
937
938 public static byte ulaw2alaw(byte sample) {
939 return u2a[sample & 0xFF];
940 }
941
942 /**
943 * Converts a buffer of uLaw samples to aLaw.
944 */
945 public static void ulaw2alaw(byte[] buffer, int byteOffset, int sampleCount) {
946 sampleCount+=byteOffset;
947 for (int i=byteOffset; i<sampleCount; i++) {
948 buffer[i]=u2a[buffer[i] & 0xFF];
949 }
950 }
951
952 /**
953 * Fills outBuffer with alaw samples.
954 */
955 public static void ulaw2alaw(byte[] inBuffer, int inByteOffset,
956 byte[] outBuffer, int outByteOffset, int sampleCount) {
957 int ulawIndex=outByteOffset;
958 int alawIndex=inByteOffset;
959 while (sampleCount>0) {
960 outBuffer[alawIndex++]=u2a[inBuffer[ulawIndex++] & 0xFF];
961 sampleCount--;
962 }
963 }
964
965 private static byte[] a2u = {
966 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
967 -71, -70, -73, -72, -67, -66, -69, -68, -79, -78, -80, -80, -75, -74, -77, -76,
968 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
969 -102, -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107,
970 -30, -29, -32, -31, -26, -25, -28, -27, -35, -35, -36, -36, -33, -33, -34, -34,
971 -12, -10, -16, -14, -4, -2, -8, -6, -22, -21, -24, -23, -18, -17, -20, -19,
972 -56, -55, -58, -57, -52, -51, -54, -53, -64, -63, -65, -65, -60, -59, -62, -61,
973 -42, -41, -44, -43, -38, -37, -40, -39, -49, -49, -50, -50, -46, -45, -48, -47,
974 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
975 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 48, 48, 53, 54, 51, 52,
976 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
977 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21,
978 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94,
979 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
980 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67,
981 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81,
982 };
983
984 public static byte alaw2ulaw(byte sample) {
985 return a2u[sample & 0xFF];
986 }
987
988 /**
989 * Converts a buffer of aLaw samples to uLaw.
990 * The uLaw bytes overwrite the original aLaw values.
991 * The first byte-offset of the uLaw bytes is byteOffset.
992 * It will be written sampleCount bytes.
993 */
994 public static void alaw2ulaw(byte[] buffer, int byteOffset, int sampleCount) {
995 sampleCount+=byteOffset;
996 for (int i=byteOffset; i<sampleCount; i++) {
997 buffer[i]=a2u[buffer[i] & 0xFF];
998 }
999 }
1000
1001 /**
1002 * Fills outBuffer with ulaw samples.
1003 * reading starts from inBuffer[inByteOffset].
1004 * writing starts at outBuffer[outByteOffset].
1005 * There will be sampleCount <B>bytes</B> written to outBuffer.
1006 */
1007 public static void alaw2ulaw(byte[] inBuffer, int inByteOffset,
1008 byte[] outBuffer, int outByteOffset, int sampleCount) {
1009 int ulawIndex=outByteOffset;
1010 int alawIndex=inByteOffset;
1011 while (sampleCount>0) {
1012 outBuffer[ulawIndex++]=a2u[inBuffer[alawIndex++] & 0xFF];
1013 sampleCount--;
1014 }
1015 }
1016
1017
1018 //////////////////////// high level methods /////////////////////////////////////////////////
1019
1020 /*
1021 * !! Here, unlike other functions in this class, the length is
1022 * in bytes rather than samples !!
1023 */
1024 public static void changeOrderOrSign(byte[] buffer, int nOffset,
1025 int nByteLength, int nBytesPerSample) {
1026 switch (nBytesPerSample) {
1027 case 1:
1028 convertSign8(buffer, nOffset, nByteLength);
1029 break;
1030
1031 case 2:
1032 swapOrder16(buffer, nOffset, nByteLength / 2);
1033 break;
1034
1035 case 3:
1036 swapOrder24(buffer, nOffset, nByteLength / 3);
1037 break;
1038
1039 case 4:
1040 swapOrder32(buffer, nOffset, nByteLength / 4);
1041 break;
1042 }
1043 }
1044
1045
1046
1047 /*
1048 * !! Here, unlike other functions in this class, the length is
1049 * in bytes rather than samples !!
1050 */
1051 public static void changeOrderOrSign(
1052 byte[] inBuffer, int nInOffset,
1053 byte[] outBuffer, int nOutOffset,
1054 int nByteLength, int nBytesPerSample) {
1055 switch (nBytesPerSample) {
1056 case 1:
1057 convertSign8(
1058 inBuffer, nInOffset,
1059 outBuffer, nOutOffset,
1060 nByteLength);
1061 break;
1062
1063 case 2:
1064 swapOrder16(
1065 inBuffer, nInOffset,
1066 outBuffer, nOutOffset,
1067 nByteLength / 2);
1068 break;
1069
1070 case 3:
1071 swapOrder24(
1072 inBuffer, nInOffset,
1073 outBuffer, nOutOffset,
1074 nByteLength / 3);
1075 break;
1076
1077 case 4:
1078 swapOrder32(
1079 inBuffer, nInOffset,
1080 outBuffer, nOutOffset,
1081 nByteLength / 4);
1082 break;
1083 }
1084 }
1085
1086
1087 ///////////////// Annexe: how the arrays were created. //////////////////////////////////
1088
1089 /*
1090 * Converts a uLaw byte to a linear signed 16bit sample.
1091 * Ported to Java by fb.
1092 * <BR>Originally by:<BR>
1093 *
1094 * Craig Reese: IDA/Supercomputing Research Center <BR>
1095 * 29 September 1989 <BR>
1096 *
1097 * References: <BR>
1098 * <OL>
1099 * <LI>CCITT Recommendation G.711 (very difficult to follow)</LI>
1100 * <LI>MIL-STD-188-113,"Interoperability and Performance Standards
1101 * for Analog-to_Digital Conversion Techniques,"
1102 * 17 February 1987</LI>
1103 * </OL>
1104 */
1105 /*
1106 private static final int exp_lut2[] = {
1107 0,132,396,924,1980,4092,8316,16764
1108};
1109
1110 public static short _ulaw2linear(int ulawbyte) {
1111 int sign, exponent, mantissa, sample;
1112
1113 ulawbyte = ~ulawbyte;
1114 sign = (ulawbyte & 0x80);
1115 exponent = (ulawbyte >> 4) & 0x07;
1116 mantissa = ulawbyte & 0x0F;
1117 sample = exp_lut2[exponent] + (mantissa << (exponent + 3));
1118 if (sign != 0) sample = -sample;
1119 return((short) sample);
1120}*/
1121
1122
1123 /* u- to A-law conversions: copied from CCITT G.711 specifications */
1124 /*
1125 private static byte[] _u2a = {
1126 1, 1, 2, 2, 3, 3, 4, 4,
1127 5, 5, 6, 6, 7, 7, 8, 8,
1128 9, 10, 11, 12, 13, 14, 15, 16,
1129 17, 18, 19, 20, 21, 22, 23, 24,
1130 25, 27, 29, 31, 33, 34, 35, 36,
1131 37, 38, 39, 40, 41, 42, 43, 44,
1132 46, 48, 49, 50, 51, 52, 53, 54,
1133 55, 56, 57, 58, 59, 60, 61, 62,
1134 64, 65, 66, 67, 68, 69, 70, 71,
1135 72, 73, 74, 75, 76, 77, 78, 79,
1136 81, 82, 83, 84, 85, 86, 87, 88,
1137 89, 90, 91, 92, 93, 94, 95, 96,
1138 97, 98, 99, 100, 101, 102, 103, 104,
1139 105, 106, 107, 108, 109, 110, 111, 112,
1140 113, 114, 115, 116, 117, 118, 119, 120,
1141 121, 122, 123, 124, 125, 126, 127, (byte) 128};
1142 */
1143
1144 /* u-law to A-law conversion */
1145 /*
1146 * This source code is a product of Sun Microsystems, Inc. and is provided
1147 * for unrestricted use. Users may copy or modify this source code without
1148 * charge.
1149 */
1150 /*
1151 public static byte _ulaw2alaw(byte sample) {
1152 sample &= 0xff;
1153 return (byte) (((sample & 0x80)!=0) ? (0xD5 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)) :
1154 (0x55 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)));
1155}*/
1156
1157 /* A- to u-law conversions */
1158 /*
1159 private static byte[] _a2u = {
1160 1, 3, 5, 7, 9, 11, 13, 15,
1161 16, 17, 18, 19, 20, 21, 22, 23,
1162 24, 25, 26, 27, 28, 29, 30, 31,
1163 32, 32, 33, 33, 34, 34, 35, 35,
1164 36, 37, 38, 39, 40, 41, 42, 43,
1165 44, 45, 46, 47, 48, 48, 49, 49,
1166 50, 51, 52, 53, 54, 55, 56, 57,
1167 58, 59, 60, 61, 62, 63, 64, 64,
1168 65, 66, 67, 68, 69, 70, 71, 72,
1169 73, 74, 75, 76, 77, 78, 79, 79,
1170 80, 81, 82, 83, 84, 85, 86, 87,
1171 88, 89, 90, 91, 92, 93, 94, 95,
1172 96, 97, 98, 99, 100, 101, 102, 103,
1173 104, 105, 106, 107, 108, 109, 110, 111,
1174 112, 113, 114, 115, 116, 117, 118, 119,
1175 120, 121, 122, 123, 124, 125, 126, 127};
1176 */
1177
1178 /*
1179 * This source code is a product of Sun Microsystems, Inc. and is provided
1180 * for unrestricted use. Users may copy or modify this source code without
1181 * charge.
1182 */
1183 /*
1184 public static byte _alaw2ulaw(byte sample) {
1185 sample &= 0xff;
1186 return (byte) (((sample & 0x80)!=0) ? (0xFF ^ _a2u[(sample ^ 0xD5) & 0x7F]) :
1187 (0x7F ^ _a2u[(sample ^ 0x55) & 0x7F]));
1188}
1189
1190 public static void print_a2u() {
1191 System.out.println("\tprivate static byte[] a2u = {");
1192 for (int i=-128; i<128; i++) {
1193 if (((i+128) % 16)==0) {
1194 System.out.print("\t\t");
1195 }
1196 byte b=(byte) i;
1197 System.out.print(_alaw2ulaw(b)+", ");
1198 if (((i+128) % 16)==15) {
1199 System.out.println("");
1200 }
1201}
1202 System.out.println("\t};");
1203}
1204
1205 public static void print_u2a() {
1206 System.out.println("\tprivate static byte[] u2a = {");
1207 for (int i=-128; i<128; i++) {
1208 if (((i+128) % 16)==0) {
1209 System.out.print("\t\t");
1210 }
1211 byte b=(byte) i;
1212 System.out.print(_ulaw2alaw(b)+", ");
1213 if (((i+128) % 16)==15) {
1214 System.out.println("");
1215 }
1216}
1217 System.out.println("\t};");
1218}
1219 */
1220
1221}
1222
1223
1224/*** TConversionTool.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TVolumeUtils.java b/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
deleted file mode 100644
index 0eaf1388da..0000000000
--- a/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * TVolumeUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31
32
33public class TVolumeUtils
34{
35 private static final double FACTOR1 = 20.0 / Math.log(10.0);
36 private static final double FACTOR2 = 1 / 20.0;
37
38
39
40 public static double lin2log(double dLinear)
41 {
42 return FACTOR1 * Math.log(dLinear);
43 }
44
45
46
47 public static double log2lin(double dLogarithmic)
48 {
49 return Math.pow(10.0, dLogarithmic * FACTOR2);
50 }
51}
52
53
54
55/*** TVolumeUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
deleted file mode 100644
index 83349439eb..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
+++ /dev/null
@@ -1,256 +0,0 @@
1/*
2 * TAsynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.ByteArrayInputStream;
34import java.io.IOException;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.TCircularBuffer;
41
42
43
44/** Base class for asynchronus converters.
45 This class serves as base class for
46 converters that do not have a fixed
47 ratio between the size of a block of input
48 data and the size of a block of output data.
49 These types of converters therefore need an
50 internal buffer, which is realized in this
51 class.
52
53 @author Matthias Pfisterer
54*/
55public abstract class TAsynchronousFilteredAudioInputStream
56extends TAudioInputStream
57implements TCircularBuffer.Trigger
58{
59 private static final int DEFAULT_BUFFER_SIZE = 327670;
60 private static final int DEFAULT_MIN_AVAILABLE = 4096;
61 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
62
63
64 private TCircularBuffer m_circularBuffer;
65 private int m_nMinAvailable;
66 private byte[] m_abSingleByte;
67
68
69
70 /** Constructor.
71 This constructor uses the default buffer size and the default
72 min available amount.
73
74 @param lLength length of this stream in frames. May be
75 AudioSystem.NOT_SPECIFIED.
76 */
77 public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength)
78 {
79 this(outputFormat, lLength,
80 DEFAULT_BUFFER_SIZE,
81 DEFAULT_MIN_AVAILABLE);
82 }
83
84
85
86 /** Constructor.
87 With this constructor, the buffer size and the minimum
88 available amount can be specified as parameters.
89
90 @param lLength length of this stream in frames. May be
91 AudioSystem.NOT_SPECIFIED.
92
93 @param nBufferSize size of the circular buffer in bytes.
94 */
95 public TAsynchronousFilteredAudioInputStream(
96 AudioFormat outputFormat, long lLength,
97 int nBufferSize,
98 int nMinAvailable)
99 {
100 /* The usage of a ByteArrayInputStream is a hack.
101 * (the infamous "JavaOne hack", because I did it on June
102 * 6th 2000 in San Francisco, only hours before a
103 * JavaOne session where I wanted to show mp3 playback
104 * with Java Sound.) It is necessary because in the FCS
105 * version of the Sun jdk1.3, the constructor of
106 * AudioInputStream throws an exception if its first
107 * argument is null. So we have to pass a dummy non-null
108 * value.
109 */
110 super(new ByteArrayInputStream(EMPTY_BYTE_ARRAY),
111 outputFormat,
112 lLength);
113 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): begin"); }
114 m_circularBuffer = new TCircularBuffer(
115 nBufferSize,
116 false, // blocking read
117 true, // blocking write
118 this); // trigger
119 m_nMinAvailable = nMinAvailable;
120 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): end"); }
121 }
122
123
124 /** Returns the circular buffer.
125 */
126 protected TCircularBuffer getCircularBuffer()
127 {
128 return m_circularBuffer;
129 }
130
131
132
133 /** Check if writing more data to the circular buffer is recommanded.
134 This checks the available write space in the circular buffer
135 against the minimum available property. If the available write
136 space is greater than th minimum available property, more
137 writing is encouraged, so this method returns true.
138 Note that this is only a hint to subclasses. However,
139 it is an important hint.
140
141 @return true if more writing to the circular buffer is
142 recommanden. Otherwise, false is returned.
143 */
144 protected boolean writeMore()
145 {
146 return getCircularBuffer().availableWrite() > m_nMinAvailable;
147 }
148
149
150
151 public int read()
152 throws IOException
153 {
154 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): begin"); }
155 int nByte = -1;
156 if (m_abSingleByte == null)
157 {
158 m_abSingleByte = new byte[1];
159 }
160 int nReturn = read(m_abSingleByte);
161 if (nReturn == -1)
162 {
163 nByte = -1;
164 }
165 else
166 {
167 //$$fb 2001-04-14 nobody really knows that...
168 nByte = m_abSingleByte[0] & 0xFF;
169 }
170 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): end"); }
171 return nByte;
172 }
173
174
175
176 public int read(byte[] abData)
177 throws IOException
178 {
179 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): begin"); }
180 int nRead = read(abData, 0, abData.length);
181 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): end"); }
182 return nRead;
183 }
184
185
186
187 public int read(byte[] abData, int nOffset, int nLength)
188 throws IOException
189 {
190 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): begin"); }
191 //$$fb 2001-04-22: this returns at maximum circular buffer
192 // length. This is not very efficient...
193 //$$fb 2001-04-25: we should check that we do not exceed getFrameLength() !
194 int nRead = m_circularBuffer.read(abData, nOffset, nLength);
195 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): end"); }
196 return nRead;
197 }
198
199
200
201 public long skip(long lSkip)
202 throws IOException
203 {
204 // TODO: this is quite inefficient
205 for (long lSkipped = 0; lSkipped < lSkip; lSkipped++)
206 {
207 int nReturn = read();
208 if (nReturn == -1)
209 {
210 return lSkipped;
211 }
212 }
213 return lSkip;
214 }
215
216
217
218 public int available()
219 throws IOException
220 {
221 return m_circularBuffer.availableRead();
222 }
223
224
225
226 public void close()
227 throws IOException
228 {
229 m_circularBuffer.close();
230 }
231
232
233
234 public boolean markSupported()
235 {
236 return false;
237 }
238
239
240
241 public void mark(int nReadLimit)
242 {
243 }
244
245
246
247 public void reset()
248 throws IOException
249 {
250 throw new IOException("mark not supported");
251 }
252}
253
254
255
256/*** TAsynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
deleted file mode 100644
index d84530e115..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
+++ /dev/null
@@ -1,120 +0,0 @@
1/*
2 * TAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.convert;
30
31import java.io.InputStream;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39
40
41/** AudioInputStream base class. This class implements "dynamic"
42 properties. "Dynamic" properties are properties that may change
43 during the life time of the objects. This is typically used to
44 pass information like the current frame number, volume of subbands
45 and similar values. "Dynamic" properties are different from
46 properties in AudioFormat and AudioFileFormat, which are
47 considered "static", as they aren't allowed to change after
48 creating of the object, thereby maintaining the immutable
49 character of these classes.
50*/
51
52public class TAudioInputStream
53extends AudioInputStream
54{
55 private Map<String, Object> m_properties;
56 private Map<String, Object> m_unmodifiableProperties;
57
58
59 /** Constructor without properties.
60 Creates an empty properties map.
61 */
62 public TAudioInputStream(InputStream inputStream,
63 AudioFormat audioFormat,
64 long lLengthInFrames)
65 {
66 super(inputStream, audioFormat, lLengthInFrames);
67 initMaps(new HashMap<String, Object>());
68 }
69
70
71 /** Constructor with properties.
72 The passed properties map is not copied. This allows subclasses
73 to change values in the map after creation, and the changes are
74 reflected in the map the application program can obtain.
75 */
76 public TAudioInputStream(InputStream inputStream,
77 AudioFormat audioFormat,
78 long lLengthInFrames,
79 Map<String, Object> properties)
80 {
81 super(inputStream, audioFormat, lLengthInFrames);
82 initMaps(properties);
83 }
84
85
86 private void initMaps(Map<String, Object> properties)
87 {
88 /* Here, we make a shallow copy of the map. It's unclear if this
89 is sufficient (of if a deep copy should be made).
90 */
91 m_properties = properties;
92 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
93 }
94
95
96 /** Obtain a Map containing the properties. This method returns a
97 Map that cannot be modified by the application program, but
98 reflects changes to the map made by the implementation.
99
100 @return a map containing the properties.
101 */
102 public Map<String, Object> properties()
103 {
104 return m_unmodifiableProperties;
105 }
106
107
108 /** Set a property. Unlike in AudioFormat and AudioFileFormat,
109 this method may be used anywhere by subclasses - it is not
110 restricted to be used in the constructor.
111 */
112 protected void setProperty(String key, Object value)
113 {
114 m_properties.put(key, value);
115 }
116}
117
118
119
120/*** TAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
deleted file mode 100644
index 6b83403c43..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
+++ /dev/null
@@ -1,129 +0,0 @@
1/*
2 * TEncodingFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.util.Collection;
34import java.util.Iterator;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.ArraySet;
41
42
43// this class depends on handling of AudioSystem.NOT_SPECIFIED in AudioFormat.matches()
44
45/**
46 * This is a base class for FormatConversionProviders that only
47 * change the encoding, i.e. they never
48 * <ul>
49 * <li> change the sample size in bits without changing the encoding
50 * <li> change the sample rate
51 * <li> change the number of channels
52 * </ul>
53 * <p>It is assumed that each source format can be encoded to all
54 * target formats.
55 * <p>In the sourceFormats and targetFormats collections that are passed to
56 * the constructor of this class, fields may be set to AudioSystem.NOT_SPECIFIED.
57 * This means that it handles all values of that field, but cannot change it.
58 * <p>This class prevents that a conversion is done (e.g. for sample rates),
59 * because the overriding class specified AudioSystem.NOT_SPECIFIED as sample rate,
60 * meaning it handles all sample rates.
61 * <p>Overriding classes must implement at least
62 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>
63 * and provide a constructor that calls the protected constructor of this class.
64 *
65 * @author Florian Bomers
66 */
67public abstract class TEncodingFormatConversionProvider
68extends TSimpleFormatConversionProvider
69{
70 protected TEncodingFormatConversionProvider(
71 Collection<AudioFormat> sourceFormats,
72 Collection<AudioFormat> targetFormats)
73 {
74 super(sourceFormats, targetFormats);
75 }
76
77
78
79 /**
80 * This implementation assumes that the converter can convert
81 * from each of its source formats to each of its target
82 * formats. If this is not the case, the converter has to
83 * override this method.
84 * <p>When conversion is supported, for every target encoding,
85 * the fields sample size in bits, channels and sample rate are checked:
86 * <ul>
87 * <li>When a field in both the source and target format is AudioSystem.NOT_SPECIFIED,
88 * one instance of that targetFormat is returned with this field set to AudioSystem.NOT_SPECIFIED.
89 * <li>When a field in sourceFormat is set and it is AudioSystem.NOT_SPECIFIED in the target format,
90 * the value of the field of source format is set in the returned format.
91 * <li>The same applies for the other way round.
92 * </ul>
93 * For this, <code>replaceNotSpecified(sourceFormat, targetFormat)</code> in the base
94 * class TSimpleFormatConversionProvider is used - and accordingly, the frameSize
95 * is recalculated with <code>getFrameSize(...)</code> if a field with AudioSystem.NOT_SPECIFIED
96 * is replaced. Inheriting classes may wish to override this method if the
97 * default mode of calculating the frame size is not appropriate.
98 */
99 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
100 if (TDebug.TraceAudioConverter) {
101 TDebug.out(">TEncodingFormatConversionProvider.getTargetFormats(AudioFormat.Encoding, AudioFormat):");
102 TDebug.out("checking if conversion possible");
103 TDebug.out("from: " + sourceFormat);
104 TDebug.out("to: " + targetEncoding);
105 }
106 if (isConversionSupported(targetEncoding, sourceFormat)) {
107 // TODO: check that no duplicates may occur...
108 ArraySet<AudioFormat> result=new ArraySet<AudioFormat>();
109 Iterator<AudioFormat> iterator = getCollectionTargetFormats().iterator();
110 while (iterator.hasNext()) {
111 AudioFormat targetFormat = iterator.next();
112 targetFormat=replaceNotSpecified(sourceFormat, targetFormat);
113 result.add(targetFormat);
114 }
115 if (TDebug.TraceAudioConverter) {
116 TDebug.out("< returning "+result.size()+" elements.");
117 }
118 return result.toArray(EMPTY_FORMAT_ARRAY);
119 } else {
120 if (TDebug.TraceAudioConverter) {
121 TDebug.out("< returning empty array.");
122 }
123 return EMPTY_FORMAT_ARRAY;
124 }
125 }
126
127}
128
129/*** TEncodingFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
deleted file mode 100644
index eaec65bb06..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * TFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import javax.sound.sampled.AudioSystem;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioInputStream;
36import javax.sound.sampled.spi.FormatConversionProvider;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.AudioFormats;
40
41
42
43/** Base class for all conversion providers of Tritonus.
44 *
45 * @author Matthias Pfisterer
46 */
47public abstract class TFormatConversionProvider
48extends FormatConversionProvider
49{
50 protected static final AudioFormat.Encoding[] EMPTY_ENCODING_ARRAY = new AudioFormat.Encoding[0];
51 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
52
53
54
55 // $$fb2000-10-04: use AudioSystem.NOT_SPECIFIED for all fields.
56 public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream audioInputStream)
57 {
58 AudioFormat sourceFormat = audioInputStream.getFormat();
59 AudioFormat targetFormat = new AudioFormat(
60 targetEncoding,
61 AudioSystem.NOT_SPECIFIED, // sample rate
62 AudioSystem.NOT_SPECIFIED, // sample size in bits
63 AudioSystem.NOT_SPECIFIED, // channels
64 AudioSystem.NOT_SPECIFIED, // frame size
65 AudioSystem.NOT_SPECIFIED, // frame rate
66 sourceFormat.isBigEndian()); // big endian
67 if (TDebug.TraceAudioConverter)
68 {
69 TDebug.out("TFormatConversionProvider.getAudioInputStream(AudioFormat.Encoding, AudioInputStream):");
70 TDebug.out("trying to convert to " + targetFormat);
71 }
72 return getAudioInputStream(targetFormat, audioInputStream);
73 }
74
75
76
77 /**
78 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
79 * which may create infinite loops if the latter is overwritten.
80 * <p>
81 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
82 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
83 */
84 /* $$mp: if we decide to use getMatchingFormat(), this method should be
85 implemented by simply calling getMatchingFormat() and comparing the
86 result against null.
87 */
88 public boolean isConversionSupported(
89 AudioFormat targetFormat,
90 AudioFormat sourceFormat)
91 {
92 if (TDebug.TraceAudioConverter)
93 {
94 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
95 TDebug.out("class: "+getClass().getName());
96 TDebug.out("checking if conversion possible");
97 TDebug.out("from: " + sourceFormat);
98 TDebug.out("to: " + targetFormat);
99 }
100 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
101 for (int i = 0; i < aTargetFormats.length; i++)
102 {
103 if (TDebug.TraceAudioConverter)
104 {
105 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
106 }
107 if (aTargetFormats[i] != null
108 && AudioFormats.matches(aTargetFormats[i], targetFormat))
109 {
110 if (TDebug.TraceAudioConverter)
111 {
112 TDebug.out("<result=true");
113 }
114 return true;
115 }
116 }
117 if (TDebug.TraceAudioConverter) {
118 TDebug.out("<result=false");
119 }
120 return false;
121 }
122
123
124 /**
125 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
126 * which may create infinite loops if the latter is overwritten.
127 * <p>
128 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
129 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
130 */
131 public AudioFormat getMatchingFormat(
132 AudioFormat targetFormat,
133 AudioFormat sourceFormat)
134 {
135 if (TDebug.TraceAudioConverter)
136 {
137 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
138 TDebug.out("class: "+getClass().getName());
139 TDebug.out("checking if conversion possible");
140 TDebug.out("from: " + sourceFormat);
141 TDebug.out("to: " + targetFormat);
142 }
143 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
144 for (int i = 0; i < aTargetFormats.length; i++)
145 {
146 if (TDebug.TraceAudioConverter)
147 {
148 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
149 }
150 if (aTargetFormats[i] != null
151 && AudioFormats.matches(aTargetFormats[i], targetFormat))
152 {
153 if (TDebug.TraceAudioConverter)
154 {
155 TDebug.out("<result=true");
156 }
157 return aTargetFormats[i];
158 }
159 }
160 if (TDebug.TraceAudioConverter) {
161 TDebug.out("<result=false");
162 }
163 return null;
164 }
165
166}
167
168
169
170/*** TFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
deleted file mode 100644
index 05dca90309..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
+++ /dev/null
@@ -1,182 +0,0 @@
1/*
2 * TMatrixFormatConversionProvider.java
3 */
4
5/*
6 * Copyright (c) 1999, 2000 by Matthias Pfisterer <Matthias.Pfisterer@gmx.de>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Library General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25
26package org.tritonus.share.sampled.convert;
27
28
29import java.util.Collection;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import java.util.HashMap;
34import java.util.ArrayList;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.FormatConversionProvider;
40
41import org.tritonus.share.sampled.AudioFormats;
42import org.tritonus.share.ArraySet;
43
44/**
45 * Base class for arbitrary formatConversionProviders.
46 *
47 * @author Matthias Pfisterer
48 */
49
50
51public abstract class TMatrixFormatConversionProvider
52 extends TSimpleFormatConversionProvider
53{
54 /*
55 * keys: source AudioFormat
56 * values: collection of possible target encodings
57 *
58 * Note that accessing values with get() is not appropriate,
59 * since the equals() method in AudioFormat is not overloaded.
60 * The hashtable is just used as a convenient storage
61 * organization.
62 */
63 private Map m_targetEncodingsFromSourceFormat;
64
65
66 /*
67 * keys: source AudioFormat
68 * values: a Map that contains a mapping from target encodings
69 * (keys) to a collection of target formats (values).
70 *
71 * Note that accessing values with get() is not appropriate,
72 * since the equals() method in AudioFormat is not overloaded.
73 * The hashtable is just used as a convenient storage
74 * organization.
75 */
76 private Map m_targetFormatsFromSourceFormat;
77
78
79
80 protected TMatrixFormatConversionProvider(
81 List sourceFormats,
82 List targetFormats,
83 boolean[][] abConversionPossible)
84 {
85 super(sourceFormats,
86 targetFormats);
87 m_targetEncodingsFromSourceFormat = new HashMap();
88 m_targetFormatsFromSourceFormat = new HashMap();
89
90 for (int nSourceFormat = 0;
91 nSourceFormat < sourceFormats.size();
92 nSourceFormat++)
93 {
94 AudioFormat sourceFormat = (AudioFormat) sourceFormats.get(nSourceFormat);
95 List supportedTargetEncodings = new ArraySet();
96 m_targetEncodingsFromSourceFormat.put(sourceFormat, supportedTargetEncodings);
97 Map targetFormatsFromTargetEncodings = new HashMap();
98 m_targetFormatsFromSourceFormat.put(sourceFormat, targetFormatsFromTargetEncodings);
99 for (int nTargetFormat = 0;
100 nTargetFormat < targetFormats.size();
101 nTargetFormat++)
102 {
103 AudioFormat targetFormat = (AudioFormat) targetFormats.get(nTargetFormat);
104 if (abConversionPossible[nSourceFormat][nTargetFormat])
105 {
106 AudioFormat.Encoding targetEncoding = targetFormat.getEncoding();
107 supportedTargetEncodings.add(targetEncoding);
108 Collection supportedTargetFormats = (Collection) targetFormatsFromTargetEncodings.get(targetEncoding);
109 if (supportedTargetFormats == null)
110 {
111 supportedTargetFormats = new ArraySet();
112 targetFormatsFromTargetEncodings.put(targetEncoding, supportedTargetFormats);
113 }
114 supportedTargetFormats.add(targetFormat);
115 }
116 }
117 }
118 }
119
120
121
122 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
123 {
124 Iterator iterator = m_targetEncodingsFromSourceFormat.entrySet().iterator();
125 while (iterator.hasNext())
126 {
127 Map.Entry entry = (Map.Entry) iterator.next();
128 AudioFormat format = (AudioFormat) entry.getKey();
129 if (AudioFormats.matches(format, sourceFormat))
130 {
131 Collection targetEncodings = (Collection) entry.getValue();
132 return (AudioFormat.Encoding[]) targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
133 }
134
135 }
136 return EMPTY_ENCODING_ARRAY;
137 }
138
139
140
141 // TODO: this should work on the array returned by getTargetEncodings(AudioFormat)
142/*
143 public boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
144 {
145 return isAllowedSourceFormat(sourceFormat) &&
146 isTargetEncodingSupported(targetEncoding);
147 }
148*/
149
150
151
152 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
153 {
154 Iterator iterator = m_targetFormatsFromSourceFormat.entrySet().iterator();
155 while (iterator.hasNext())
156 {
157 Map.Entry entry = (Map.Entry) iterator.next();
158 AudioFormat format = (AudioFormat) entry.getKey();
159 if (AudioFormats.matches(format, sourceFormat))
160 {
161 Map targetEncodings = (Map) entry.getValue();
162 Collection targetFormats = (Collection) targetEncodings.get(targetEncoding);
163 if (targetFormats != null)
164 {
165 return (AudioFormat[]) targetFormats.toArray(EMPTY_FORMAT_ARRAY);
166 }
167 else
168 {
169 return EMPTY_FORMAT_ARRAY;
170 }
171 }
172
173 }
174 return EMPTY_FORMAT_ARRAY;
175 }
176
177
178}
179
180
181
182/*** TMatrixFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
deleted file mode 100644
index 71b055ff79..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
+++ /dev/null
@@ -1,367 +0,0 @@
1/*
2 * TSimpleFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.convert;
31
32import java.util.Collection;
33import java.util.Iterator;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.sampled.AudioFormats;
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.TDebug;
41
42
43/**
44 * This is a base class for FormatConversionProviders that can convert
45 * from each source encoding/format to each target encoding/format.
46 * If this is not the case, use TEncodingFormatConversionProvider.
47 *
48 * <p>Overriding classes must
49 * provide a constructor that calls the protected constructor of this class and override
50 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>.
51 * The latter method should be able to handle the case that all fields are NOT_SPECIFIED
52 * and provide appropriate default values.
53 *
54 * @author Matthias Pfisterer
55 */
56
57// todo:
58// - declare a constant ALL_BUT_SAME_VALUE (==-2) or so that can be used in format lists
59// - consistent implementation of replacing NOT_SPECIFIED when not given in conversion
60
61public abstract class TSimpleFormatConversionProvider
62extends TFormatConversionProvider
63{
64 private Collection<AudioFormat.Encoding> m_sourceEncodings;
65 private Collection<AudioFormat.Encoding> m_targetEncodings;
66 private Collection<AudioFormat> m_sourceFormats;
67 private Collection<AudioFormat> m_targetFormats;
68
69
70
71 protected TSimpleFormatConversionProvider(
72 Collection<AudioFormat> sourceFormats,
73 Collection<AudioFormat> targetFormats)
74 {
75 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
76 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
77 m_sourceFormats = sourceFormats;
78 m_targetFormats = targetFormats;
79 collectEncodings(m_sourceFormats, m_sourceEncodings);
80 collectEncodings(m_targetFormats, m_targetEncodings);
81 }
82
83
84
85 /** Disables this FormatConversionProvider.
86 This may be useful when e.g. native libraries are not present.
87 TODO: enable method, better implementation
88 */
89 protected void disable()
90 {
91 if (TDebug.TraceAudioConverter) { TDebug.out("TSimpleFormatConversionProvider.disable(): disabling " + getClass().getName()); }
92 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
93 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
94 m_sourceFormats = new ArraySet<AudioFormat>();
95 m_targetFormats = new ArraySet<AudioFormat>();
96 }
97
98
99
100 private static void collectEncodings(Collection<AudioFormat> formats,
101 Collection<AudioFormat.Encoding> encodings)
102 {
103 Iterator<AudioFormat> iterator = formats.iterator();
104 while (iterator.hasNext())
105 {
106 AudioFormat format = iterator.next();
107 encodings.add(format.getEncoding());
108 }
109 }
110
111
112
113 public AudioFormat.Encoding[] getSourceEncodings()
114 {
115 return m_sourceEncodings.toArray(EMPTY_ENCODING_ARRAY);
116 }
117
118
119
120 public AudioFormat.Encoding[] getTargetEncodings()
121 {
122 return m_targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
123 }
124
125
126
127 // overwritten of FormatConversionProvider
128 public boolean isSourceEncodingSupported(AudioFormat.Encoding sourceEncoding)
129 {
130 return m_sourceEncodings.contains(sourceEncoding);
131 }
132
133
134
135 // overwritten of FormatConversionProvider
136 public boolean isTargetEncodingSupported(AudioFormat.Encoding targetEncoding)
137 {
138 return m_targetEncodings.contains(targetEncoding);
139 }
140
141
142
143 /**
144 * This implementation assumes that the converter can convert
145 * from each of its source encodings to each of its target
146 * encodings. If this is not the case, the converter has to
147 * override this method.
148 */
149 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
150 {
151 if (isAllowedSourceFormat(sourceFormat))
152 {
153 return getTargetEncodings();
154 }
155 else
156 {
157 return EMPTY_ENCODING_ARRAY;
158 }
159 }
160
161
162
163 /**
164 * This implementation assumes that the converter can convert
165 * from each of its source formats to each of its target
166 * formats. If this is not the case, the converter has to
167 * override this method.
168 */
169 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
170 {
171 if (isConversionSupported(targetEncoding, sourceFormat))
172 {
173 return m_targetFormats.toArray(EMPTY_FORMAT_ARRAY);
174 }
175 else
176 {
177 return EMPTY_FORMAT_ARRAY;
178 }
179 }
180
181
182 // TODO: check if necessary
183 protected boolean isAllowedSourceEncoding(AudioFormat.Encoding sourceEncoding)
184 {
185 return m_sourceEncodings.contains(sourceEncoding);
186 }
187
188
189
190 protected boolean isAllowedTargetEncoding(AudioFormat.Encoding targetEncoding)
191 {
192 return m_targetEncodings.contains(targetEncoding);
193 }
194
195
196
197 protected boolean isAllowedSourceFormat(AudioFormat sourceFormat)
198 {
199 Iterator<AudioFormat> iterator = m_sourceFormats.iterator();
200 while (iterator.hasNext())
201 {
202 AudioFormat format = iterator.next();
203 if (AudioFormats.matches(format, sourceFormat))
204 {
205 return true;
206 }
207 }
208 return false;
209 }
210
211
212
213 protected boolean isAllowedTargetFormat(AudioFormat targetFormat)
214 {
215 Iterator<AudioFormat> iterator = m_targetFormats.iterator();
216 while (iterator.hasNext())
217 {
218 AudioFormat format = iterator.next();
219 if (AudioFormats.matches(format, targetFormat))
220 {
221 return true;
222 }
223 }
224 return false;
225 }
226
227 // $$fb 2000-04-02 added some convenience methods for overriding classes
228 protected Collection<AudioFormat.Encoding> getCollectionSourceEncodings()
229 {
230 return m_sourceEncodings;
231 }
232
233 protected Collection<AudioFormat.Encoding> getCollectionTargetEncodings()
234 {
235 return m_targetEncodings;
236 }
237
238 protected Collection<AudioFormat> getCollectionSourceFormats() {
239 return m_sourceFormats;
240 }
241
242 protected Collection<AudioFormat> getCollectionTargetFormats() {
243 return m_targetFormats;
244 }
245
246 /**
247 * Utility method to check whether these values match,
248 * taking into account AudioSystem.NOT_SPECIFIED.
249 * @return true if any of the values is AudioSystem.NOT_SPECIFIED
250 * or both values have the same value.
251 */
252 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
253 protected static boolean doMatch(int i1, int i2) {
254 return i1==AudioSystem.NOT_SPECIFIED
255 || i2==AudioSystem.NOT_SPECIFIED
256 || i1==i2;
257 }
258
259 /**
260 * @see #doMatch(int,int)
261 */
262 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
263 protected static boolean doMatch(float f1, float f2) {
264 return f1==AudioSystem.NOT_SPECIFIED
265 || f2==AudioSystem.NOT_SPECIFIED
266 || Math.abs(f1 - f2) < 1.0e-9;
267 }
268
269 /**
270 * Utility method, replaces all occurences of AudioSystem.NOT_SPECIFIED
271 * in <code>targetFormat</code> with the corresponding value in <code>sourceFormat</code>.
272 * If <code>targetFormat</code> does not contain any fields with AudioSystem.NOT_SPECIFIED,
273 * it is returned unmodified. The endian-ness and encoding remain the same in all cases.
274 * <p>
275 * If any of the fields is AudioSystem.NOT_SPECIFIED in both <code>sourceFormat</code> and
276 * <code>targetFormat</code>, it will remain not specified.
277 * <p>
278 * This method uses <code>getFrameSize(...)</code> (see below) to set the new frameSize,
279 * if a new AudioFormat instance is created.
280 * <p>
281 * This method isn't used in TSimpleFormatConversionProvider - it is solely there
282 * for inheriting classes.
283 */
284 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
285 protected AudioFormat replaceNotSpecified(AudioFormat sourceFormat, AudioFormat targetFormat) {
286 boolean bSetSampleSize=false;
287 boolean bSetChannels=false;
288 boolean bSetSampleRate=false;
289 boolean bSetFrameRate=false;
290 if (targetFormat.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
291 && sourceFormat.getSampleSizeInBits()!=AudioSystem.NOT_SPECIFIED) {
292 bSetSampleSize=true;
293 }
294 if (targetFormat.getChannels()==AudioSystem.NOT_SPECIFIED
295 && sourceFormat.getChannels()!=AudioSystem.NOT_SPECIFIED) {
296 bSetChannels=true;
297 }
298 if (targetFormat.getSampleRate()==AudioSystem.NOT_SPECIFIED
299 && sourceFormat.getSampleRate()!=AudioSystem.NOT_SPECIFIED) {
300 bSetSampleRate=true;
301 }
302 if (targetFormat.getFrameRate()==AudioSystem.NOT_SPECIFIED
303 && sourceFormat.getFrameRate()!=AudioSystem.NOT_SPECIFIED) {
304 bSetFrameRate=true;
305 }
306 if (bSetSampleSize || bSetChannels || bSetSampleRate || bSetFrameRate
307 || (targetFormat.getFrameSize()==AudioSystem.NOT_SPECIFIED
308 && sourceFormat.getFrameSize()!=AudioSystem.NOT_SPECIFIED)) {
309 // create new format in place of the original target format
310 float sampleRate=bSetSampleRate?
311 sourceFormat.getSampleRate():targetFormat.getSampleRate();
312 float frameRate=bSetFrameRate?
313 sourceFormat.getFrameRate():targetFormat.getFrameRate();
314 int sampleSize=bSetSampleSize?
315 sourceFormat.getSampleSizeInBits():targetFormat.getSampleSizeInBits();
316 int channels=bSetChannels?
317 sourceFormat.getChannels():targetFormat.getChannels();
318 int frameSize=getFrameSize(
319 targetFormat.getEncoding(),
320 sampleRate,
321 sampleSize,
322 channels,
323 frameRate,
324 targetFormat.isBigEndian(),
325 targetFormat.getFrameSize());
326 targetFormat= new AudioFormat(
327 targetFormat.getEncoding(),
328 sampleRate,
329 sampleSize,
330 channels,
331 frameSize,
332 frameRate,
333 targetFormat.isBigEndian());
334 }
335 return targetFormat;
336 }
337
338 /**
339 * Calculates the frame size for the given format description.
340 * The default implementation returns AudioSystem.NOT_SPECIFIED
341 * if either <code>sampleSize</code> or <code>channels</code> is AudioSystem.NOT_SPECIFIED,
342 * otherwise <code>sampleSize*channels/8</code> is returned.
343 * <p>
344 * If this does not reflect the way to calculate the right frame size,
345 * inheriting classes should overwrite this method if they use
346 * replaceNotSpecified(...). It is not used elsewhere in this class.
347 */
348 //$$fb 2000-08-16: added
349 protected int getFrameSize(
350 AudioFormat.Encoding encoding,
351 float sampleRate,
352 int sampleSize,
353 int channels,
354 float frameRate,
355 boolean bigEndian,
356 int oldFrameSize) {
357 if (sampleSize==AudioSystem.NOT_SPECIFIED || channels==AudioSystem.NOT_SPECIFIED) {
358 return AudioSystem.NOT_SPECIFIED;
359 }
360 return sampleSize*channels/8;
361 }
362
363
364
365}
366
367/*** TSimpleFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
deleted file mode 100644
index 8a588e5c3e..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
+++ /dev/null
@@ -1,271 +0,0 @@
1/*
2 * TSynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38import javax.sound.sampled.spi.FormatConversionProvider;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.AudioUtils;
42
43
44
45/**
46 * Base class for types of audio filter/converter that translate one frame to another frame.<br>
47 * It provides all the transformation of frame sizes.<br>
48 * It does NOT handle different sample rates of original stream and this stream !
49 *
50 * @author Florian Bomers
51 */
52public abstract class TSynchronousFilteredAudioInputStream
53extends TAudioInputStream {
54
55 private AudioInputStream originalStream;
56 private AudioFormat originalFormat;
57 /** 1 if original format's frame size is NOT_SPECIFIED */
58 private int originalFrameSize;
59 /** 1 if original format's frame size is NOT_SPECIFIED */
60 private int newFrameSize;
61
62 /**
63 * The intermediate buffer used during convert actions
64 * (if not convertInPlace is used).
65 * It remains until this audioStream is closed or destroyed
66 * and grows with the time - it always has the size of the
67 * largest intermediate buffer ever needed.
68 */
69 protected byte[] buffer=null;
70
71 /**
72 * For use of the more efficient method convertInPlace.
73 * it will be set to true when (frameSizeFactor==1)
74 */
75 private boolean m_bConvertInPlace = false;
76
77 public TSynchronousFilteredAudioInputStream(AudioInputStream audioInputStream, AudioFormat newFormat) {
78 // the super class will do nothing... we override everything
79 super(audioInputStream, newFormat, audioInputStream.getFrameLength());
80 originalStream=audioInputStream;
81 originalFormat=audioInputStream.getFormat();
82 originalFrameSize=(originalFormat.getFrameSize()<=0) ?
83 1 : originalFormat.getFrameSize();
84 newFrameSize=(getFormat().getFrameSize()<=0) ?
85 1 : getFormat().getFrameSize();
86 if (TDebug.TraceAudioConverter) {
87 TDebug.out("TSynchronousFilteredAudioInputStream: original format ="
88 +AudioUtils.format2ShortStr(originalFormat));
89 TDebug.out("TSynchronousFilteredAudioInputStream: converted format="
90 +AudioUtils.format2ShortStr(getFormat()));
91 }
92 //$$fb 2000-07-17: convert in place has to be enabled explicitly with "enableConvertInPlace"
93 //if (getFormat().getFrameSize() == originalFormat.getFrameSize()) {
94 // m_bConvertInPlace = true;
95 //}
96 m_bConvertInPlace = false;
97 }
98
99 protected boolean enableConvertInPlace() {
100 if (newFrameSize >= originalFrameSize) {
101 m_bConvertInPlace = true;
102 }
103 return m_bConvertInPlace;
104 }
105
106
107 /**
108 * Override this method to do the actual conversion.
109 * inBuffer starts always at index 0 (it is an internal buffer)
110 * You should always override this.
111 * inFrameCount is the number of frames in inBuffer. These
112 * frames are of the format originalFormat.
113 * @return the resulting number of <B>frames</B> converted and put into
114 * outBuffer. The return value is in the format of this stream.
115 */
116 protected abstract int convert(byte[] inBuffer, byte[] outBuffer, int outByteOffset, int inFrameCount);
117
118
119
120 /**
121 * Override this method to provide in-place conversion of samples.
122 * To use it, call "enableConvertInPlace()". It will only be used when
123 * input bytes per frame >= output bytes per frame.
124 * This method must always convert frameCount frames, so no return value is necessary.
125 */
126 protected void convertInPlace(byte[] buffer, int byteOffset, int frameCount) {
127 throw new RuntimeException("Illegal call to convertInPlace");
128 }
129
130 public int read()
131 throws IOException {
132 if (newFrameSize != 1) {
133 throw new IOException("frame size must be 1 to read a single byte");
134 }
135 // very ugly, but efficient. Who uses this method anyway ?
136 // TODO: use an instance variable
137 byte[] temp = new byte[1];
138 int result = read(temp);
139 if (result == -1) {
140 return -1;
141 }
142 if (result == 0) {
143 // what in this case ??? Let's hope it never occurs.
144 return -1;
145 }
146 return temp[0] & 0xFF;
147 }
148
149
150
151 private void clearBuffer() {
152 buffer = null;
153 }
154
155 public AudioInputStream getOriginalStream() {
156 return originalStream;
157 }
158
159 public AudioFormat getOriginalFormat() {
160 return originalFormat;
161 }
162
163 /**
164 * Read nLength bytes that will be the converted samples
165 * of the original InputStream.
166 * When nLength is not an integral number of frames,
167 * this method may read less than nLength bytes.
168 */
169 public int read(byte[] abData, int nOffset, int nLength)
170 throws IOException {
171 // number of frames that we have to read from the underlying stream.
172 int nFrameLength = nLength/newFrameSize;
173
174 // number of bytes that we need to read from underlying stream.
175 int originalBytes = nFrameLength * originalFrameSize;
176
177 if (TDebug.TraceAudioConverter) {
178 TDebug.out("> TSynchronousFilteredAIS.read(buffer["+abData.length+"], "
179 +nOffset+" ,"+nLength+" bytes ^="+nFrameLength+" frames)");
180 }
181 int nFramesConverted = 0;
182
183 // set up buffer to read
184 byte readBuffer[];
185 int readOffset;
186 if (m_bConvertInPlace) {
187 readBuffer=abData;
188 readOffset=nOffset;
189 } else {
190 // assert that the buffer fits
191 if (buffer == null || buffer.length < originalBytes) {
192 buffer = new byte[originalBytes];
193 }
194 readBuffer=buffer;
195 readOffset=0;
196 }
197 int nBytesRead = originalStream.read(readBuffer, readOffset, originalBytes);
198 if (nBytesRead == -1) {
199 // end of stream
200 clearBuffer();
201 return -1;
202 }
203 int nFramesRead = nBytesRead / originalFrameSize;
204 if (TDebug.TraceAudioConverter) {
205 TDebug.out("original.read returned "
206 +nBytesRead+" bytes ^="+nFramesRead+" frames");
207 }
208 if (m_bConvertInPlace) {
209 convertInPlace(abData, nOffset, nFramesRead);
210 nFramesConverted=nFramesRead;
211 } else {
212 nFramesConverted = convert(buffer, abData, nOffset, nFramesRead);
213 }
214 if (TDebug.TraceAudioConverter) {
215 TDebug.out("< converted "+nFramesConverted+" frames");
216 }
217 return nFramesConverted*newFrameSize;
218 }
219
220
221 public long skip(long nSkip)
222 throws IOException {
223 // only returns integral frames
224 long skipFrames = nSkip / newFrameSize;
225 long originalSkippedBytes = originalStream.skip(skipFrames*originalFrameSize);
226 long skippedFrames = originalSkippedBytes/originalFrameSize;
227 return skippedFrames * newFrameSize;
228 }
229
230
231 public int available()
232 throws IOException {
233 int origAvailFrames = originalStream.available()/originalFrameSize;
234 return origAvailFrames*newFrameSize;
235 }
236
237
238 public void close()
239 throws IOException {
240 originalStream.close();
241 clearBuffer();
242 }
243
244
245
246 public void mark(int readlimit) {
247 int readLimitFrames=readlimit/newFrameSize;
248 originalStream.mark(readLimitFrames*originalFrameSize);
249 }
250
251
252
253 public void reset()
254 throws IOException {
255 originalStream.reset();
256 }
257
258
259 public boolean markSupported() {
260 return originalStream.markSupported();
261 }
262
263
264 private int getFrameSize() {
265 return getFormat().getFrameSize();
266 }
267
268}
269
270
271/*** TSynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/package.html b/songdbj/org/tritonus/share/sampled/convert/package.html
deleted file mode 100644
index d0cc35c408..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/package.html
+++ /dev/null
@@ -1,17 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of FormatConversionProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.FormatConversionProvider
11 @see org.tritonus.sampled.convert
12 @see org.tritonus.sampled.convert.gsm
13 @see org.tritonus.sampled.convert.jorbis
14 @see org.tritonus.sampled.convert.lame
15 @see org.tritonus.sampled.convert.vorbis
16 </body>
17</html>
diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
deleted file mode 100644
index d76296cd2d..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * AudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39/** Represents a one-time writing of audio data to a destination (file or output stream).
40 *
41 * This interface is the lowest abstraction level of writing audio data.
42 * Implementations of this interface should, when write() is called, never
43 * do buffering and they should never do format conversions. However,
44 * this interface is intended to abstract the file format (how the
45 * headers and data chunks look like) and the way of writing to the
46 * destination object. (implementation note [non-normative]: the last
47 * should be done by using TDataOutputStream implementing classes).
48 *
49 * One reasoning behind this interface was to allow direct, unbuffered
50 * writing of recorded data.
51 * In JS API 0.90, there was no obvious way for this.
52 * Data have had to be recorded to a buffer, then written to a file
53 * from that buffer.
54 * This gave problems with long recordings, where the main
55 * memory of the machine is not big enough to hold all data. There are
56 * two ways so solve this:
57 *
58 * a) Having a special AudioInputStream that fetches its data from a
59 * TargetDataLine. This way, the loop inside the AudioFileWriters reads
60 * directely from the recording line via the special AudioInputStream.
61 * This is the solution Sun adopted for JS 1.0.
62 *
63 * b) The other way is to expose a direct interface to the writing of the
64 * audio file with no loop inside it. This is to enable the application
65 * programmer to write the main loop itself, possibly doing some
66 * additional processing inside it. This is the more flexible way.
67 * The drawback is that it requires a new architecture for writing files.
68 *
69 * This interface is the central part of a proposal for the second
70 * solution.
71 * The idea is now to use the new structure inside the old one to gain
72 * experience with it before proposing to make it a public interface
73 * (public in the sense that it is part of the javax.sound.sampled
74 * package).
75 *
76 * @author Matthias Pfisterer
77 */
78public interface AudioOutputStream
79{
80 /**
81 * Retrieves the AufioFormat of this AudioOutputStream.
82 */
83 public AudioFormat getFormat();
84
85
86 /** Gives length of the stream.
87 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
88 * to express that the length is unknown.
89 */
90 public long getLength();
91
92
93
94 /**
95 * Writes a chunk of audio data to the destination (file or output stream).
96 */
97 // IDEA: use long?
98 public int write(byte[] abData, int nOffset, int nLength)
99 throws IOException;
100
101
102
103 /** Closes the stream.
104 * This does write remaining buffered data to the destination,
105 * backpatch the header, if necessary, and closes the destination.
106 */
107 public void close()
108 throws IOException;
109}
110
111
112
113/*** AudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
deleted file mode 100644
index 3083fd5b8f..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
+++ /dev/null
@@ -1,58 +0,0 @@
1/*
2 * HeaderlessAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35
36
37/**
38 * AudioOutputStream for files without a header; the input is written as it is.
39 *
40 * @author Florian Bomers
41 */
42
43// todo: implement directly AudioOutputStream without using TAudioOutputStream
44
45public class HeaderlessAudioOutputStream extends TAudioOutputStream {
46
47 public HeaderlessAudioOutputStream(AudioFormat audioFormat,
48 long lLength,
49 TDataOutputStream dataOutputStream) {
50 super(audioFormat, lLength, dataOutputStream, false);
51 }
52
53 protected void writeHeader() throws IOException
54 {
55 }
56}
57
58/*** HeaderlessAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
deleted file mode 100644
index fd9831e291..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * TAudioFileFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40
41
42/**
43 * This class is just to have a public constructor taking the
44 * number of bytes of the whole file. The public constructor of
45 * AudioFileFormat doesn't take this parameter, the one who takes
46 * it is protected.
47 *
48 * @author Matthias Pfisterer
49 */
50public class TAudioFileFormat
51extends AudioFileFormat
52{
53 private Map<String, Object> m_properties;
54 private Map<String, Object> m_unmodifiableProperties;
55
56
57 /*
58 * Note that the order of the arguments is different from
59 * the one in AudioFileFormat.
60 */
61 public TAudioFileFormat(Type type,
62 AudioFormat audioFormat,
63 int nLengthInFrames,
64 int nLengthInBytes)
65 {
66 super(type,
67 nLengthInBytes,
68 audioFormat,
69 nLengthInFrames);
70 }
71
72
73 public TAudioFileFormat(Type type,
74 AudioFormat audioFormat,
75 int nLengthInFrames,
76 int nLengthInBytes,
77 Map<String, Object> properties)
78 {
79 super(type,
80 nLengthInBytes,
81 audioFormat,
82 nLengthInFrames);
83 initMaps(properties);
84 }
85
86
87 private void initMaps(Map<String, Object> properties)
88 {
89 /* Here, we make a shallow copy of the map. It's unclear if this
90 is sufficient (of if a deep copy should be made).
91 */
92 m_properties = new HashMap<String, Object>();
93 m_properties.putAll(properties);
94 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
95 }
96
97
98 public Map<String, Object> properties()
99 {
100 return m_unmodifiableProperties;
101 }
102
103
104
105 protected void setProperty(String key, Object value)
106 {
107 m_properties.put(key, value);
108 }
109}
110
111
112
113/*** TAudioFileFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
deleted file mode 100644
index ee79becf20..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
+++ /dev/null
@@ -1,510 +0,0 @@
1/*
2 * TAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.BufferedInputStream;
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.DataInputStream;
36import java.io.InputStream;
37import java.io.IOException;
38import java.io.EOFException;
39
40import java.net.URL;
41import java.net.URLConnection;
42
43import javax.sound.sampled.AudioFormat;
44import javax.sound.sampled.AudioInputStream;
45import javax.sound.sampled.AudioFileFormat;
46import javax.sound.sampled.AudioSystem;
47import javax.sound.sampled.UnsupportedAudioFileException;
48import javax.sound.sampled.spi.AudioFileReader;
49
50import org.tritonus.share.TDebug;
51
52
53
54/** Base class for audio file readers.
55 This is Tritonus' base class for classes that provide the facility
56 of detecting an audio file type and reading its header.
57 Classes should be derived from this class or one of its subclasses
58 rather than from javax.sound.sampled.spi.AudioFileReader.
59
60 @author Matthias Pfisterer
61 @author Florian Bomers
62*/
63public abstract class TAudioFileReader
64extends AudioFileReader
65{
66 private int m_nMarkLimit = -1;
67 private boolean m_bRereading;
68
69
70 protected TAudioFileReader(int nMarkLimit)
71 {
72 this(nMarkLimit, false);
73 }
74
75
76
77 protected TAudioFileReader(int nMarkLimit, boolean bRereading)
78 {
79 m_nMarkLimit = nMarkLimit;
80 m_bRereading = bRereading;
81 }
82
83
84
85 private int getMarkLimit()
86 {
87 return m_nMarkLimit;
88 }
89
90
91
92 private boolean isRereading()
93 {
94 return m_bRereading;
95 }
96
97
98
99 /** Get an AudioFileFormat object for a File.
100 This method calls getAudioFileFormat(InputStream, long).
101 Subclasses should not override this method unless there are
102 really severe reasons. Normally, it is sufficient to
103 implement getAudioFileFormat(InputStream, long).
104
105 @param file the file to read from.
106 @return an AudioFileFormat instance containing
107 information from the header of the file passed in.
108 */
109 public AudioFileFormat getAudioFileFormat(File file)
110 throws UnsupportedAudioFileException, IOException
111 {
112 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin"); }
113 long lFileLengthInBytes = file.length();
114 InputStream inputStream = new FileInputStream(file);
115 AudioFileFormat audioFileFormat = null;
116 try
117 {
118 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
119 }
120 finally
121 {
122 inputStream.close();
123 }
124 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): end"); }
125 return audioFileFormat;
126 }
127
128
129
130 /** Get an AudioFileFormat object for a URL.
131 This method calls getAudioFileFormat(InputStream, long).
132 Subclasses should not override this method unless there are
133 really severe reasons. Normally, it is sufficient to
134 implement getAudioFileFormat(InputStream, long).
135
136 @param url the URL to read from.
137 @return an AudioFileFormat instance containing
138 information from the header of the URL passed in.
139 */
140 public AudioFileFormat getAudioFileFormat(URL url)
141 throws UnsupportedAudioFileException, IOException
142
143 {
144 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin"); }
145 long lFileLengthInBytes = getDataLength(url);
146 InputStream inputStream = url.openStream();
147 AudioFileFormat audioFileFormat = null;
148 try
149 {
150 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
151 }
152 finally
153 {
154 inputStream.close();
155 }
156 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end"); }
157 return audioFileFormat;
158 }
159
160
161
162 /** Get an AudioFileFormat object for an InputStream.
163 This method calls getAudioFileFormat(InputStream, long).
164 Subclasses should not override this method unless there are
165 really severe reasons. Normally, it is sufficient to
166 implement getAudioFileFormat(InputStream, long).
167
168 @param inputStream the stream to read from.
169 @return an AudioFileFormat instance containing
170 information from the header of the stream passed in.
171 */
172 public AudioFileFormat getAudioFileFormat(InputStream inputStream)
173 throws UnsupportedAudioFileException, IOException
174
175 {
176 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin"); }
177 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
178 inputStream.mark(getMarkLimit());
179 AudioFileFormat audioFileFormat = null;
180 try
181 {
182 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
183 }
184 finally
185 {
186 /* TODO: required semantics is unclear: should reset()
187 be executed only when there is an exception or
188 should it be done always?
189 */
190 inputStream.reset();
191 }
192 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end"); }
193 return audioFileFormat;
194 }
195
196
197
198 /** Get an AudioFileFormat (internal implementation).
199 Subclasses must implement this method in a way specific
200 to the file format they handle.
201
202 Note that depending on the implementation of this method,
203 you should or should not override
204 getAudioInputStream(InputStream, long), too (see comment
205 there).
206
207 @param inputStream The InputStream to read from.
208 @param lFileLengthInBytes The size of the originating
209 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
210 should be passed. This value may be used for byteLength in
211 AudioFileFormat, if this value can't be derived from the
212 informmation in the file header.
213
214 @return an AudioFileFormat instance containing
215 information from the header of the stream passed in as
216 inputStream.
217 */
218 protected abstract AudioFileFormat getAudioFileFormat(
219 InputStream inputStream,
220 long lFileLengthInBytes)
221 throws UnsupportedAudioFileException, IOException;
222
223
224
225 /** Get an AudioInputStream object for a file.
226 This method calls getAudioInputStream(InputStream, long).
227 Subclasses should not override this method unless there are
228 really severe reasons. Normally, it is sufficient to
229 implement getAudioFileFormat(InputStream, long) and perhaps
230 override getAudioInputStream(InputStream, long).
231
232 @param file the File object to read from.
233 @return an AudioInputStream instance containing
234 the audio data from this file.
235 */
236 public AudioInputStream getAudioInputStream(File file)
237 throws UnsupportedAudioFileException, IOException
238 {
239 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): begin"); }
240 long lFileLengthInBytes = file.length();
241 InputStream inputStream = new FileInputStream(file);
242 AudioInputStream audioInputStream = null;
243 try
244 {
245 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
246 }
247 catch (UnsupportedAudioFileException e)
248 {
249 inputStream.close();
250 throw e;
251 }
252 catch (IOException e)
253 {
254 inputStream.close();
255 throw e;
256 }
257 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): end"); }
258 return audioInputStream;
259 }
260
261
262
263 /** Get an AudioInputStream object for a URL.
264 This method calls getAudioInputStream(InputStream, long).
265 Subclasses should not override this method unless there are
266 really severe reasons. Normally, it is sufficient to
267 implement getAudioFileFormat(InputStream, long) and perhaps
268 override getAudioInputStream(InputStream, long).
269
270 @param url the URL to read from.
271 @return an AudioInputStream instance containing
272 the audio data from this URL.
273 */
274 public AudioInputStream getAudioInputStream(URL url)
275 throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin"); }
278 long lFileLengthInBytes = getDataLength(url);
279 InputStream inputStream = url.openStream();
280 AudioInputStream audioInputStream = null;
281 try
282 {
283 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
284 }
285 catch (UnsupportedAudioFileException e)
286 {
287 inputStream.close();
288 throw e;
289 }
290 catch (IOException e)
291 {
292 inputStream.close();
293 throw e;
294 }
295 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): end"); }
296 return audioInputStream;
297 }
298
299
300
301 /** Get an AudioInputStream object for an InputStream.
302 This method calls getAudioInputStream(InputStream, long).
303 Subclasses should not override this method unless there are
304 really severe reasons. Normally, it is sufficient to
305 implement getAudioFileFormat(InputStream, long) and perhaps
306 override getAudioInputStream(InputStream, long).
307
308 @param inputStream the stream to read from.
309 @return an AudioInputStream instance containing
310 the audio data from this stream.
311 */
312 public AudioInputStream getAudioInputStream(InputStream inputStream)
313 throws UnsupportedAudioFileException, IOException
314 {
315 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin"); }
316 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
317 AudioInputStream audioInputStream = null;
318 inputStream.mark(getMarkLimit());
319 try
320 {
321 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
322 }
323 catch (UnsupportedAudioFileException e)
324 {
325 inputStream.reset();
326 throw e;
327 }
328 catch (IOException e)
329 {
330 inputStream.reset();
331 throw e;
332 }
333 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end"); }
334 return audioInputStream;
335 }
336
337
338
339 /** Get an AudioInputStream (internal implementation).
340 This implementation calls getAudioFileFormat() with the
341 same arguments as passed in here. Then, it constructs
342 an AudioInputStream instance. This instance takes the passed
343 inputStream in the state it is left after getAudioFileFormat()
344 did its work. In other words, the implementation here
345 assumes that getAudioFileFormat() reads the entire header
346 up to a position exactely where the audio data starts.
347 If this can't be realized for a certain format, this method
348 should be overridden.
349
350 @param inputStream The InputStream to read from.
351 @param lFileLengthInBytes The size of the originating
352 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
353 should be passed. This value may be used for byteLength in
354 AudioFileFormat, if this value can't be derived from the
355 informmation in the file header.
356 */
357 protected AudioInputStream getAudioInputStream(InputStream inputStream, long lFileLengthInBytes)
358 throws UnsupportedAudioFileException, IOException
359 {
360 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin"); }
361 if (isRereading())
362 {
363 inputStream = new BufferedInputStream(inputStream, getMarkLimit());
364 inputStream.mark(getMarkLimit());
365 }
366 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
367 if (isRereading())
368 {
369 inputStream.reset();
370 }
371 AudioInputStream audioInputStream =
372 new AudioInputStream(inputStream,
373 audioFileFormat.getFormat(),
374 audioFileFormat.getFrameLength());
375 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end"); }
376 return audioInputStream;
377 }
378
379
380
381 protected static int calculateFrameSize(int nSampleSize, int nNumChannels)
382 {
383 return ((nSampleSize + 7) / 8) * nNumChannels;
384 }
385
386
387
388 private static long getDataLength(URL url)
389 throws IOException
390 {
391 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
392 URLConnection connection = url.openConnection();
393 connection.connect();
394 int nLength = connection.getContentLength();
395 if (nLength > 0)
396 {
397 lFileLengthInBytes = nLength;
398 }
399 return lFileLengthInBytes;
400 }
401
402
403
404 public static int readLittleEndianInt(InputStream is)
405 throws IOException
406 {
407 int b0 = is.read();
408 int b1 = is.read();
409 int b2 = is.read();
410 int b3 = is.read();
411 if ((b0 | b1 | b2 | b3) < 0)
412 {
413 throw new EOFException();
414 }
415 return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
416 }
417
418
419
420 public static short readLittleEndianShort(InputStream is)
421 throws IOException
422 {
423 int b0 = is.read();
424 int b1 = is.read();
425 if ((b0 | b1) < 0)
426 {
427 throw new EOFException();
428 }
429 return (short) ((b1 << 8) + (b0 << 0));
430 }
431
432
433/*
434 * C O N V E R T F R O M I E E E E X T E N D E D
435 */
436
437/*
438 * Copyright (C) 1988-1991 Apple Computer, Inc.
439 * All rights reserved.
440 *
441 * Machine-independent I/O routines for IEEE floating-point numbers.
442 *
443 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
444 * happens to be infinity on IEEE machines. Unfortunately, it is
445 * impossible to preserve NaN's in a machine-independent way.
446 * Infinities are, however, preserved on IEEE machines.
447 *
448 * These routines have been tested on the following machines:
449 * Apple Macintosh, MPW 3.1 C compiler
450 * Apple Macintosh, THINK C compiler
451 * Silicon Graphics IRIS, MIPS compiler
452 * Cray X/MP and Y/MP
453 * Digital Equipment VAX
454 *
455 *
456 * Implemented by Malcolm Slaney and Ken Turkowski.
457 *
458 * Malcolm Slaney contributions during 1988-1990 include big- and little-
459 * endian file I/O, conversion to and from Motorola's extended 80-bit
460 * floating-point format, and conversions to and from IEEE single-
461 * precision floating-point format.
462 *
463 * In 1991, Ken Turkowski implemented the conversions to and from
464 * IEEE double-precision format, added more precision to the extended
465 * conversions, and accommodated conversions involving +/- infinity,
466 * NaN's, and denormalized numbers.
467 */
468
469 public static double readIeeeExtended(DataInputStream dis)
470 throws IOException
471 {
472 double f = 0.0D;
473 int expon = 0;
474 long hiMant = 0L;
475 long loMant = 0L;
476 double HUGE = 3.4028234663852886E+038D;
477 expon = dis.readUnsignedShort();
478 long t1 = dis.readUnsignedShort();
479 long t2 = dis.readUnsignedShort();
480 hiMant = t1 << 16 | t2;
481 t1 = dis.readUnsignedShort();
482 t2 = dis.readUnsignedShort();
483 loMant = t1 << 16 | t2;
484 if(expon == 0 && hiMant == 0L && loMant == 0L)
485 {
486 f = 0.0D;
487 }
488 else
489 {
490 if(expon == 32767)
491 {
492 f = HUGE;
493 }
494 else
495 {
496 expon -= 16383;
497 expon -= 31;
498 f = hiMant * Math.pow(2D, expon);
499 expon -= 32;
500 f += loMant * Math.pow(2D, expon);
501 }
502 }
503 return f;
504 }
505}
506
507
508
509/*** TAudioFileReader.java ***/
510
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
deleted file mode 100644
index d9d6ee86ec..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
+++ /dev/null
@@ -1,484 +0,0 @@
1/*
2 * TAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 * Copyright (c) 1999, 2000 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.File;
34import java.io.FileOutputStream;
35import java.io.InputStream;
36import java.io.IOException;
37import java.io.OutputStream;
38import java.util.Collection;
39import java.util.Iterator;
40
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.AudioSystem;
45import javax.sound.sampled.spi.AudioFileWriter;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.sampled.AudioFormats;
49import org.tritonus.share.sampled.AudioUtils;
50import org.tritonus.share.sampled.TConversionTool;
51import org.tritonus.share.ArraySet;
52
53/**
54 * Common base class for implementing classes of AudioFileWriter.
55 * <p>It provides often-used functionality and the new architecture using
56 * an AudioOutputStream.
57 * <p>There should be only one set of audio formats supported by any given
58 * class of TAudioFileWriter. This class assumes implicitely that all
59 * supported file types have a common set of audio formats they can handle.
60 *
61 * @author Matthias Pfisterer
62 * @author Florian Bomers
63 */
64
65public abstract class TAudioFileWriter
66extends AudioFileWriter
67{
68 protected static final int ALL = AudioSystem.NOT_SPECIFIED;
69
70 public static AudioFormat.Encoding PCM_SIGNED=new AudioFormat.Encoding("PCM_SIGNED");
71 public static AudioFormat.Encoding PCM_UNSIGNED=new AudioFormat.Encoding("PCM_UNSIGNED");
72
73 /** Buffer length for the loop in the write() method.
74 * This is in bytes. Perhaps it should be in frames to give an
75 * equal amount of latency.
76 */
77 private static final int BUFFER_LENGTH = 16384;
78
79 // only needed for Collection.toArray()
80 protected static final AudioFileFormat.Type[] NULL_TYPE_ARRAY = new AudioFileFormat.Type[0];
81
82
83 /** The audio file types (AudioFileFormat.Type) that can be
84 * handled by the AudioFileWriter.
85 */
86 private Collection<AudioFileFormat.Type> m_audioFileTypes;
87
88
89
90 /** The AudioFormats that can be handled by the
91 * AudioFileWriter.
92 */
93 // IDEA: implement a special collection that uses matches() to test whether an element is already in
94 private Collection<AudioFormat> m_audioFormats;
95
96
97 /**
98 * Inheriting classes should call this constructor
99 * in order to make use of the functionality of TAudioFileWriter.
100 */
101 protected TAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
102 Collection<AudioFormat> audioFormats)
103 {
104 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): begin"); }
105 m_audioFileTypes = fileTypes;
106 m_audioFormats = audioFormats;
107 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): end"); }
108 }
109
110 // implementing the interface
111 public AudioFileFormat.Type[] getAudioFileTypes()
112 {
113 return m_audioFileTypes.toArray(NULL_TYPE_ARRAY);
114 }
115
116
117 // implementing the interface
118 public boolean isFileTypeSupported(AudioFileFormat.Type fileType)
119 {
120 return m_audioFileTypes.contains(fileType);
121 }
122
123
124
125 // implementing the interface
126 public AudioFileFormat.Type[] getAudioFileTypes(
127 AudioInputStream audioInputStream)
128 {
129 //$$fb 2000-08-16: rewrote this method. We need to check for *each*
130 // file type, whether the format is supported !
131 AudioFormat format = audioInputStream.getFormat();
132 ArraySet<AudioFileFormat.Type> res=new ArraySet<AudioFileFormat.Type>();
133 Iterator<AudioFileFormat.Type> it=m_audioFileTypes.iterator();
134 while (it.hasNext()) {
135 AudioFileFormat.Type thisType = it.next();
136 if (isAudioFormatSupportedImpl(format, thisType)) {
137 res.add(thisType);
138 }
139 }
140 return res.toArray(NULL_TYPE_ARRAY);
141 }
142
143
144
145 // implementing the interface
146 public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream audioInputStream)
147 {
148 // $$fb 2000-08-16: finally this method works reliably !
149 return isFileTypeSupported(fileType)
150 && (isAudioFormatSupportedImpl(audioInputStream.getFormat(), fileType)
151 || findConvertableFormat(audioInputStream.getFormat(), fileType)!=null);
152 // we may soft it up by including the possibility of endian/sign
153 // changing for PCM formats.
154 // I prefer to return false if the format is not exactly supported
155 // but still exectute the write, if only sign/endian changing is necessary.
156 }
157
158
159
160 // implementing the interface
161 public int write(AudioInputStream audioInputStream,
162 AudioFileFormat.Type fileType,
163 File file)
164 throws IOException
165 {
166 if (TDebug.TraceAudioFileWriter)
167 {
168 TDebug.out(">TAudioFileWriter.write(.., File): called");
169 TDebug.out("class: "+getClass().getName());
170 }
171 //$$fb added this check
172 if (!isFileTypeSupported(fileType)) {
173 if (TDebug.TraceAudioFileWriter)
174 {
175 TDebug.out("< file type is not supported");
176 }
177 throw new IllegalArgumentException("file type is not supported.");
178 }
179
180 AudioFormat inputFormat = audioInputStream.getFormat();
181 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
182 AudioFormat outputFormat = null;
183 boolean bNeedsConversion = false;
184 if (isAudioFormatSupportedImpl(inputFormat, fileType))
185 {
186 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
187 outputFormat = inputFormat;
188 bNeedsConversion = false;
189 }
190 else
191 {
192 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
193 outputFormat = findConvertableFormat(inputFormat, fileType);
194 if (outputFormat != null)
195 {
196 bNeedsConversion = true;
197 // $$fb 2000-08-16 made consistent with new conversion trials
198 // if 8 bit and only endianness changed, don't convert !
199 if (outputFormat.getSampleSizeInBits()==8
200 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
201 bNeedsConversion = false;
202 }
203 }
204 else
205 {
206 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input format is not supported and not convertable."); }
207 throw new IllegalArgumentException("format not supported and not convertable");
208 }
209 }
210 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
211 TDataOutputStream dataOutputStream = new TSeekableDataOutputStream(file);
212 AudioOutputStream audioOutputStream =
213 getAudioOutputStream(
214 outputFormat,
215 lLengthInBytes,
216 fileType,
217 dataOutputStream);
218 int written=writeImpl(audioInputStream,
219 audioOutputStream,
220 bNeedsConversion);
221 if (TDebug.TraceAudioFileWriter)
222 {
223 TDebug.out("< wrote "+written+" bytes.");
224 }
225 return written;
226 }
227
228
229
230 // implementing the interface
231 public int write(AudioInputStream audioInputStream,
232 AudioFileFormat.Type fileType,
233 OutputStream outputStream)
234 throws IOException
235 {
236 //$$fb added this check
237 if (!isFileTypeSupported(fileType)) {
238 throw new IllegalArgumentException("file type is not supported.");
239 }
240 if (TDebug.TraceAudioFileWriter)
241 {
242 TDebug.out(">TAudioFileWriter.write(.., OutputStream): called");
243 TDebug.out("class: "+getClass().getName());
244 }
245 AudioFormat inputFormat = audioInputStream.getFormat();
246 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
247 AudioFormat outputFormat = null;
248 boolean bNeedsConversion = false;
249 if (isAudioFormatSupportedImpl(inputFormat, fileType))
250 {
251 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
252 outputFormat = inputFormat;
253 bNeedsConversion = false;
254 }
255 else
256 {
257 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
258 outputFormat = findConvertableFormat(inputFormat, fileType);
259 if (outputFormat != null)
260 {
261 bNeedsConversion = true;
262 // $$fb 2000-08-16 made consistent with new conversion trials
263 // if 8 bit and only endianness changed, don't convert !
264 if (outputFormat.getSampleSizeInBits()==8
265 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
266 bNeedsConversion = false;
267 }
268 }
269 else
270 {
271 if (TDebug.TraceAudioFileWriter) { TDebug.out("< format is not supported"); }
272 throw new IllegalArgumentException("format not supported and not convertable");
273 }
274 }
275 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
276 TDataOutputStream dataOutputStream = new TNonSeekableDataOutputStream(outputStream);
277 AudioOutputStream audioOutputStream =
278 getAudioOutputStream(
279 outputFormat,
280 lLengthInBytes,
281 fileType,
282 dataOutputStream);
283 int written=writeImpl(audioInputStream,
284 audioOutputStream,
285 bNeedsConversion);
286 if (TDebug.TraceAudioFileWriter) { TDebug.out("< wrote "+written+" bytes."); }
287 return written;
288 }
289
290
291
292 protected int writeImpl(
293 AudioInputStream audioInputStream,
294 AudioOutputStream audioOutputStream,
295 boolean bNeedsConversion)
296 throws IOException
297 {
298 if (TDebug.TraceAudioFileWriter)
299 {
300 TDebug.out(">TAudioFileWriter.writeImpl(): called");
301 TDebug.out("class: "+getClass().getName());
302 }
303 int nTotalWritten = 0;
304 AudioFormat inputFormat = audioInputStream.getFormat();
305 AudioFormat outputFormat = audioOutputStream.getFormat();
306
307 // TODO: handle case when frame size is unknown ?
308 int nBytesPerSample = outputFormat.getFrameSize() / outputFormat.getChannels();
309
310 //$$fb 2000-07-18: BUFFER_LENGTH must be a multiple of frame size...
311 int nBufferSize=((int)BUFFER_LENGTH/outputFormat.getFrameSize())*outputFormat.getFrameSize();
312 byte[] abBuffer = new byte[nBufferSize];
313 while (true)
314 {
315 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying to read (bytes): " + abBuffer.length); }
316 int nBytesRead = audioInputStream.read(abBuffer);
317 if (TDebug.TraceAudioFileWriter) { TDebug.out("read (bytes): " + nBytesRead); }
318 if (nBytesRead == -1)
319 {
320 break;
321 }
322 if (bNeedsConversion)
323 {
324 TConversionTool.changeOrderOrSign(abBuffer, 0,
325 nBytesRead, nBytesPerSample);
326 }
327 int nWritten = audioOutputStream.write(abBuffer, 0, nBytesRead);
328 nTotalWritten += nWritten;
329 }
330 if (TDebug.TraceAudioFileWriter) { TDebug.out("<TAudioFileWriter.writeImpl(): after main loop. Wrote "+nTotalWritten+" bytes"); }
331 audioOutputStream.close();
332 // TODO: get bytes written for header etc. from AudioOutputStrem and add to nTotalWrittenBytes
333 return nTotalWritten;
334 }
335
336
337 /** Returns the AudioFormat that can be handled for the given file type.
338 * In this simple implementation, all handled AudioFormats are
339 * returned (i.e. the fileType argument is ignored). If the
340 * handled AudioFormats depend on the file type, this method
341 * has to be overwritten by subclasses.
342 */
343 protected Iterator<AudioFormat> getSupportedAudioFormats(AudioFileFormat.Type fileType)
344 {
345 return m_audioFormats.iterator();
346 }
347
348
349 /** Checks whether the passed <b>AudioFormat</b> can be handled.
350 * In this simple implementation, it is only checked if the
351 * passed AudioFormat matches one of the generally handled
352 * formats (i.e. the fileType argument is ignored). If the
353 * handled AudioFormats depend on the file type, this method
354 * or getSupportedAudioFormats() (on which this method relies)
355 * has to be overwritten by subclasses.
356 * <p>
357 * This is the central method for checking if a FORMAT is supported.
358 * Inheriting classes can overwrite this for performance
359 * or to exclude/include special type/format combinations.
360 * <p>
361 * This method is only called when the <code>fileType</code>
362 * is in the list of supported file types ! Overriding
363 * classes <b>need not</b> check this.
364 */
365 //$$fb 2000-08-16 changed name, changed documentation. Semantics !
366 protected boolean isAudioFormatSupportedImpl(
367 AudioFormat audioFormat,
368 AudioFileFormat.Type fileType)
369 {
370 if (TDebug.TraceAudioFileWriter)
371 {
372 TDebug.out("> TAudioFileWriter.isAudioFormatSupportedImpl(): format to test: " + audioFormat);
373 TDebug.out("class: "+getClass().getName());
374 }
375 Iterator audioFormats = getSupportedAudioFormats(fileType);
376 while (audioFormats.hasNext())
377 {
378 AudioFormat handledFormat = (AudioFormat) audioFormats.next();
379 if (TDebug.TraceAudioFileWriter) { TDebug.out("matching against format : " + handledFormat); }
380 if (AudioFormats.matches(handledFormat, audioFormat))
381 {
382 if (TDebug.TraceAudioFileWriter) { TDebug.out("<...succeeded."); }
383 return true;
384 }
385 }
386 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
387 return false;
388 }
389
390
391
392 protected abstract AudioOutputStream getAudioOutputStream(
393 AudioFormat audioFormat,
394 long lLengthInBytes,
395 AudioFileFormat.Type fileType,
396 TDataOutputStream dataOutputStream)
397 throws IOException;
398
399 private AudioFormat findConvertableFormat(
400 AudioFormat inputFormat,
401 AudioFileFormat.Type fileType)
402 {
403 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.findConvertableFormat(): input format: " + inputFormat); }
404 if (!isFileTypeSupported(fileType)) {
405 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input file type is not supported."); }
406 return null;
407 }
408 AudioFormat.Encoding inputEncoding = inputFormat.getEncoding();
409 if ((inputEncoding.equals(PCM_SIGNED) || inputEncoding.equals(PCM_UNSIGNED))
410 && inputFormat.getSampleSizeInBits() == 8)
411 {
412 AudioFormat outputFormat = convertFormat(inputFormat, true, false);
413 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
414 if (isAudioFormatSupportedImpl(outputFormat, fileType))
415 {
416 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
417 return outputFormat;
418 }
419 //$$fb 2000-08-16: added trial of other endianness for 8bit. We try harder !
420 outputFormat = convertFormat(inputFormat, false, true);
421 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
422 if (isAudioFormatSupportedImpl(outputFormat, fileType))
423 {
424 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
425 return outputFormat;
426 }
427 outputFormat = convertFormat(inputFormat, true, true);
428 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
429 if (isAudioFormatSupportedImpl(outputFormat, fileType))
430 {
431 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
432 return outputFormat;
433 }
434 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
435 return null;
436 }
437 else if (inputEncoding.equals(PCM_SIGNED) &&
438 (inputFormat.getSampleSizeInBits() == 16 ||
439 inputFormat.getSampleSizeInBits() == 24 ||
440 inputFormat.getSampleSizeInBits() == 32) )
441 {
442 // TODO: possible to allow all sample sized > 8 bit?
443 // $$ fb: don't think that this is necessary. Well, let's talk about that in 5 years :)
444 AudioFormat outputFormat = convertFormat(inputFormat, false, true);
445 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
446 if (isAudioFormatSupportedImpl(outputFormat, fileType))
447 {
448 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
449 return outputFormat;
450 }
451 else
452 {
453 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
454 return null;
455 }
456 }
457 else
458 {
459 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
460 return null;
461 }
462 }
463
464 // $$fb 2000-08-16: added convenience method
465 private AudioFormat convertFormat(AudioFormat format, boolean changeSign, boolean changeEndian) {
466 AudioFormat.Encoding enc=PCM_SIGNED;
467 if (format.getEncoding().equals(PCM_UNSIGNED)!=changeSign) {
468 enc=PCM_UNSIGNED;
469 }
470 return new AudioFormat(
471 enc,
472 format.getSampleRate(),
473 format.getSampleSizeInBits(),
474 format.getChannels(),
475 format.getFrameSize(),
476 format.getFrameRate(),
477 format.isBigEndian() ^ changeEndian);
478 }
479
480}
481
482
483
484/*** TAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
deleted file mode 100644
index e54316c0a6..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 * TAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39
40
41/**
42 * Base class for classes implementing AudioOutputStream.
43 *
44 * @author Matthias Pfisterer
45 */
46
47public abstract class TAudioOutputStream
48implements AudioOutputStream
49{
50 private AudioFormat m_audioFormat;
51 private long m_lLength; // in bytes
52 private long m_lCalculatedLength;
53 private TDataOutputStream m_dataOutputStream;
54 private boolean m_bDoBackPatching;
55 private boolean m_bHeaderWritten;
56
57
58
59 protected TAudioOutputStream(AudioFormat audioFormat,
60 long lLength,
61 TDataOutputStream dataOutputStream,
62 boolean bDoBackPatching)
63 {
64 m_audioFormat = audioFormat;
65 m_lLength = lLength;
66 m_lCalculatedLength = 0;
67 m_dataOutputStream = dataOutputStream;
68 m_bDoBackPatching = bDoBackPatching;
69 m_bHeaderWritten = false;
70 }
71
72
73
74 public AudioFormat getFormat()
75 {
76 return m_audioFormat;
77 }
78
79
80
81 /** Gives length of the stream.
82 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
83 * to express that the length is unknown.
84 */
85 public long getLength()
86 {
87 return m_lLength;
88 }
89
90
91
92 /** Gives number of bytes already written.
93 */
94 // IDEA: rename this to BytesWritten or something like that ?
95 public long getCalculatedLength()
96 {
97 return m_lCalculatedLength;
98 }
99
100 protected TDataOutputStream getDataOutputStream()
101 {
102 return m_dataOutputStream;
103 }
104
105
106 /** Writes audio data to the destination (file or output stream).
107 */
108 // IDEA: use long?
109 public int write(byte[] abData, int nOffset, int nLength)
110 throws IOException
111 {
112 if (TDebug.TraceAudioOutputStream)
113 {
114 TDebug.out("TAudioOutputStream.write(): wanted length: " + nLength);
115 }
116 if (! m_bHeaderWritten)
117 {
118 writeHeader();
119 m_bHeaderWritten = true;
120 }
121 // $$fb added
122 // check that total writes do not exceed specified length
123 long lTotalLength=getLength();
124 if (lTotalLength!=AudioSystem.NOT_SPECIFIED && (m_lCalculatedLength+nLength)>lTotalLength) {
125 if (TDebug.TraceAudioOutputStream) {
126 TDebug.out("TAudioOutputStream.write(): requested more bytes to write than possible.");
127 }
128 nLength=(int) (lTotalLength-m_lCalculatedLength);
129 // sanity
130 if (nLength<0) {
131 nLength=0;
132 }
133 }
134 // TODO: throw an exception if nLength==0 ? (to indicate end of file ?)
135 if (nLength>0) {
136 m_dataOutputStream.write(abData, nOffset, nLength);
137 m_lCalculatedLength += nLength;
138 }
139 if (TDebug.TraceAudioOutputStream)
140 {
141 TDebug.out("TAudioOutputStream.write(): calculated (total) length: " + m_lCalculatedLength+" bytes = "+(m_lCalculatedLength/getFormat().getFrameSize())+" frames");
142 }
143 return nLength;
144 }
145
146
147
148 /** Writes the header of the audio file.
149 */
150 protected abstract void writeHeader()
151 throws IOException;
152
153
154
155 /** Closes the stream.
156 * This does write remaining buffered data to the destination,
157 * backpatch the header, if necessary, and closes the destination.
158 */
159 public void close()
160 throws IOException
161 {
162 if (TDebug.TraceAudioOutputStream)
163 {
164 TDebug.out("TAudioOutputStream.close(): called");
165 }
166 // flush?
167 if (m_bDoBackPatching)
168 {
169 if (TDebug.TraceAudioOutputStream)
170 {
171 TDebug.out("TAudioOutputStream.close(): patching header");
172 }
173 patchHeader();
174 }
175 m_dataOutputStream.close();
176 }
177
178
179
180 protected void patchHeader()
181 throws IOException
182 {
183 TDebug.out("TAudioOutputStream.patchHeader(): called");
184 // DO NOTHING
185 }
186
187
188
189 protected void setLengthFromCalculatedLength()
190 {
191 m_lLength = m_lCalculatedLength;
192 }
193}
194
195
196
197/*** TAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
deleted file mode 100644
index eacc00a2e2..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 * TDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.DataOutput;
34import java.io.IOException;
35import java.io.InputStream;
36
37
38/**
39 * Interface for the file writing classes.
40 * <p>Like that it is possible to write to a file without knowing
41 * the length before.
42 *
43 * @author Florian Bomers
44 */
45public interface TDataOutputStream
46extends DataOutput
47{
48 public boolean supportsSeek();
49
50
51
52 public void seek(long position)
53 throws IOException;
54
55
56
57 public long getFilePointer()
58 throws IOException;
59
60
61
62 public long length()
63 throws IOException;
64
65
66 public void writeLittleEndian32(int value)
67 throws IOException;
68
69
70 public void writeLittleEndian16(short value)
71 throws IOException;
72
73 public void close()
74 throws IOException;
75}
76
77
78
79/*** TDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
deleted file mode 100644
index a9d76de505..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * THeaderlessAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 - 2002 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.IOException;
33import java.util.Collection;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39
40
41
42/** Base class for formats without extra header.
43 This AudioFileWriter is typically used for compressed formats
44 where the encoder puts a header into the encoded stream. In this
45 case, the AudioFileWriter needs not to add a header. This is why
46 THeaderlessAudioOutputStream is used here.
47
48 @author Florian Bomers
49 @author Matthias Pfisterer
50*/
51public class THeaderlessAudioFileWriter
52extends TAudioFileWriter
53{
54 protected THeaderlessAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
55 Collection<AudioFormat> audioFormats)
56 {
57 super(fileTypes, audioFormats);
58 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): begin"); }
59 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): end"); }
60 }
61
62
63
64 protected AudioOutputStream getAudioOutputStream(
65 AudioFormat audioFormat,
66 long lLengthInBytes,
67 AudioFileFormat.Type fileType,
68 TDataOutputStream dataOutputStream)
69 throws IOException
70 {
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): begin"); }
72 AudioOutputStream aos = new HeaderlessAudioOutputStream(
73 audioFormat,
74 lLengthInBytes,
75 dataOutputStream);
76 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): end"); }
77 return aos;
78 }
79
80}
81
82
83
84/*** THeaderlessAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
deleted file mode 100644
index 2e9704ed10..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 * TNonSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.DataOutputStream;
37
38
39
40/**
41 * A TDataOutputStream that does not allow seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TNonSeekableDataOutputStream
47extends DataOutputStream
48implements TDataOutputStream
49{
50 public TNonSeekableDataOutputStream(OutputStream outputStream)
51 {
52 super(outputStream);
53 }
54
55
56
57 public boolean supportsSeek()
58 {
59 return false;
60 }
61
62
63
64 public void seek(long position)
65 throws IOException
66 {
67 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to seek not allowed.");
68 }
69
70
71
72 public long getFilePointer()
73 throws IOException
74 {
75 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to getFilePointer not allowed.");
76 }
77
78
79
80 public long length()
81 throws IOException
82 {
83 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to length not allowed.");
84 }
85
86
87
88 public void writeLittleEndian32(int value)
89 throws IOException
90 {
91 writeByte(value & 0xFF);
92 writeByte((value >> 8) & 0xFF);
93 writeByte((value >> 16) & 0xFF);
94 writeByte((value >> 24) & 0xFF);
95 }
96
97
98
99 public void writeLittleEndian16(short value)
100 throws IOException
101 {
102 writeByte(value & 0xFF);
103 writeByte((value >> 8) & 0xFF);
104 }
105}
106
107
108
109/*** TNonSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
deleted file mode 100644
index 6f688c5b2e..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * TSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.File;
35import java.io.RandomAccessFile;
36import java.io.IOException;
37
38
39
40/**
41 * A TDataOutputStream that allows seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TSeekableDataOutputStream
47extends RandomAccessFile
48implements TDataOutputStream
49{
50 public TSeekableDataOutputStream(File file)
51 throws IOException
52 {
53 super(file, "rw");
54 }
55
56
57
58 public boolean supportsSeek()
59 {
60 return true;
61 }
62
63
64
65 public void writeLittleEndian32(int value)
66 throws IOException
67 {
68 writeByte(value & 0xFF);
69 writeByte((value >> 8) & 0xFF);
70 writeByte((value >> 16) & 0xFF);
71 writeByte((value >> 24) & 0xFF);
72 }
73
74
75
76 public void writeLittleEndian16(short value)
77 throws IOException
78 {
79 writeByte(value & 0xFF);
80 writeByte((value >> 8) & 0xFF);
81 }
82}
83
84
85
86/*** TSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/package.html b/songdbj/org/tritonus/share/sampled/file/package.html
deleted file mode 100644
index a79274048c..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/package.html
+++ /dev/null
@@ -1,18 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of AudioFileReaders and AudioFileWriters.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.AudioFileReader
11 @see javax.sound.sampled.spi.AudioFileWriter
12 @see org.tritonus.sampled.file
13 @see org.tritonus.sampled.file.gsm
14 @see org.tritonus.sampled.file.jorbis
15 @see org.tritonus.sampled.file.mpeg
16 @see org.tritonus.sampled.file.vorbis
17 </body>
18</html>
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
deleted file mode 100644
index e589439838..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
+++ /dev/null
@@ -1,107 +0,0 @@
1/*
2 * TBaseDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.Collection;
32import java.util.EventListener;
33import java.util.EventObject;
34import java.util.HashSet;
35import java.util.Set;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.LineEvent;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineUnavailableException;
44
45import org.tritonus.share.TDebug;
46
47
48
49/** Base class for implementing SourceDataLine or TargetDataLine.
50 */
51public abstract class TBaseDataLine
52extends TDataLine
53{
54 public TBaseDataLine(TMixer mixer,
55 DataLine.Info info)
56 {
57 super(mixer,
58 info);
59 }
60
61
62
63 public TBaseDataLine(TMixer mixer,
64 DataLine.Info info,
65 Collection<Control> controls)
66 {
67 super(mixer,
68 info,
69 controls);
70 }
71
72
73
74 public void open(AudioFormat format, int nBufferSize)
75 throws LineUnavailableException
76 {
77 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat, int): called with buffer size: " + nBufferSize); }
78 setBufferSize(nBufferSize);
79 open(format);
80 }
81
82
83
84 public void open(AudioFormat format)
85 throws LineUnavailableException
86 {
87 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat): called"); }
88 setFormat(format);
89 open();
90 }
91
92
93 // IDEA: move to TDataLine or TLine?
94 // necessary and wise at all?
95 protected void finalize()
96 {
97 if (isOpen())
98 {
99 close();
100 }
101 }
102}
103
104
105
106/*** TBaseDataLine.java ***/
107
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java b/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
deleted file mode 100644
index a722edbf31..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * TBooleanControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.BooleanControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing BooleanControl.
41 */
42public class TBooleanControl
43extends BooleanControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TBooleanControl(BooleanControl.Type type,
51 boolean bInitialValue)
52 {
53 this(type, bInitialValue, null);
54 }
55
56
57
58 public TBooleanControl(BooleanControl.Type type,
59 boolean bInitialValue,
60 TCompoundControl parentControl)
61 {
62 super(type, bInitialValue);
63 if (TDebug.TraceControl)
64 {
65 TDebug.out("TBooleanControl.<init>: begin");
66 }
67 m_controller = new TControlController();
68 if (TDebug.TraceControl)
69 {
70 TDebug.out("TBooleanControl.<init>: end");
71 }
72 }
73
74
75
76 public TBooleanControl(BooleanControl.Type type,
77 boolean bInitialValue,
78 String strTrueStateLabel,
79 String strFalseStateLabel)
80 {
81 this(type, bInitialValue, strTrueStateLabel, strFalseStateLabel, null);
82 }
83
84
85
86 public TBooleanControl(BooleanControl.Type type,
87 boolean bInitialValue,
88 String strTrueStateLabel,
89 String strFalseStateLabel,
90 TCompoundControl parentControl)
91 {
92 super(type, bInitialValue, strTrueStateLabel, strFalseStateLabel);
93 if (TDebug.TraceControl)
94 {
95 TDebug.out("TBooleanControl.<init>: begin");
96 }
97 m_controller = new TControlController();
98 if (TDebug.TraceControl)
99 {
100 TDebug.out("TBooleanControl.<init>: end");
101 }
102 }
103
104
105
106 public void setParentControl(TCompoundControl compoundControl)
107 {
108 m_controller.setParentControl(compoundControl);
109 }
110
111
112
113 public TCompoundControl getParentControl()
114 {
115 return m_controller.getParentControl();
116 }
117
118
119
120 public void commit()
121 {
122 m_controller.commit();
123 }
124}
125
126
127
128/*** TBooleanControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TClip.java b/songdbj/org/tritonus/share/sampled/mixer/TClip.java
deleted file mode 100644
index e0a8140c37..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TClip.java
+++ /dev/null
@@ -1,340 +0,0 @@
1/*
2 * TClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.mixer;
31
32import java.io.IOException;
33import java.io.ByteArrayInputStream;
34import java.util.Collection;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38import javax.sound.sampled.Clip;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TClip
52extends TDataLine
53implements Clip
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_FRAMES = 16384;
57
58
59 public TClip(DataLine.Info info)
60 {
61 super(null, // TMixer
62 info);
63 }
64
65
66
67 public TClip(DataLine.Info info,
68 Collection<Control> controls)
69 {
70 super(null, // TMixer
71 info,
72 controls);
73 }
74
75
76
77 public void open(AudioFormat audioFormat,
78 byte[] abData,
79 int nOffset,
80 int nLength)
81 throws LineUnavailableException
82 {
83 // int nBufferLength = nNumFrames * audioFormat.getFrameSize();
84 // TODO: check if nOffset + nBufferLength <= abData.length
85 // perhaps truncate automatically
86 ByteArrayInputStream bais = new ByteArrayInputStream(abData, nOffset, nLength);
87 AudioInputStream audioInputStream = new AudioInputStream(bais, audioFormat, AudioSystem.NOT_SPECIFIED);
88 try
89 {
90 open(audioInputStream);
91 }
92 catch (IOException e)
93 {
94 if (TDebug.TraceAllExceptions)
95 {
96 TDebug.out(e);
97 }
98 throw new LineUnavailableException("IOException occured");
99 }
100 }
101
102
103
104 public void open(AudioInputStream audioInputStream)
105 throws LineUnavailableException, IOException
106 {
107 AudioFormat audioFormat = audioInputStream.getFormat();
108 // TOOD:
109 DataLine.Info info = new DataLine.Info(Clip.class,
110 audioFormat, -1/*nBufferSize*/);
111/*
112 setLineInfo(info);
113 int nFrameSize = audioFormat.getFrameSize();
114 long lTotalLength = audioInputStream.getFrameLength() * nFrameSize;
115 int nFormat = Esd.ESD_STREAM | Esd.ESD_PLAY | EsdUtils.getEsdFormat(audioFormat);
116 if (TDebug.TraceClip)
117 {
118 TDebug.out("format: " + nFormat);
119 TDebug.out("sample rate: " + audioFormat.getSampleRate());
120 }
121 // m_esdSample.open(nFormat, (int) audioFormat.getSampleRate(), (int) lTotalLength);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("size in esd: " + audioInputStream.getFrameLength() * nFrameSize);
125 }
126 int nBufferLength = BUFFER_FRAMES * nFrameSize;
127 byte[] abData = new byte[nBufferLength];
128 int nBytesRead = 0;
129 int nTotalBytes = 0;
130 while (nBytesRead != -1)
131 {
132 try
133 {
134 nBytesRead = audioInputStream.read(abData, 0, abData.length);
135 }
136 catch (IOException e)
137 {
138 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
139 {
140 TDebug.out(e);
141 }
142 }
143 if (nBytesRead >= 0)
144 {
145 nTotalBytes += nBytesRead;
146 if (TDebug.TraceClip)
147 {
148 TDebug.out("TClip.open(): total bytes: " + nTotalBytes);
149 TDebug.out("TClip.open(): Trying to write: " + nBytesRead);
150 }
151 int nBytesWritten = 0; //m_esdSample.write(abData, 0, nBytesRead);
152 if (TDebug.TraceClip)
153 {
154 TDebug.out("TClip.open(): Written: " + nBytesWritten);
155 }
156 }
157 }
158 // to trigger the events
159 // open();
160 */
161 }
162
163
164
165 public int getFrameLength()
166 {
167 // TODO:
168 return -1;
169 }
170
171
172
173 public long getMicrosecondLength()
174 {
175 // TODO:
176 return -1;
177 }
178
179
180
181 public void setFramePosition(int nPosition)
182 {
183 // TOOD:
184 }
185
186
187
188 public void setMicrosecondPosition(long lPosition)
189 {
190 // TOOD:
191 }
192
193
194
195 public int getFramePosition()
196 {
197 // TOOD:
198 return -1;
199 }
200
201
202
203 public long getMicrosecondPosition()
204 {
205 // TOOD:
206 return -1;
207 }
208
209
210
211 public void setLoopPoints(int nStart, int nEnd)
212 {
213 // TOOD:
214 }
215
216
217
218 public void loop(int nCount)
219 {
220 if (TDebug.TraceClip)
221 {
222 TDebug.out("TClip.loop(int): called; count = " + nCount);
223 }
224 if (false/*isStarted()*/)
225 {
226 /*
227 * only allow zero count to stop the looping
228 * at the end of an iteration.
229 */
230 if (nCount == 0)
231 {
232 if (TDebug.TraceClip)
233 {
234 TDebug.out("TClip.loop(int): stopping sample");
235 }
236 // m_esdSample.stop();
237 }
238 }
239 else
240 {
241 if (nCount == 0)
242 {
243 if (TDebug.TraceClip)
244 {
245 TDebug.out("TClip.loop(int): starting sample (once)");
246 }
247 // m_esdSample.play();
248 }
249 else
250 {
251 /*
252 * we're ignoring the count, because esd
253 * cannot loop for a fixed number of
254 * times.
255 */
256 // TDebug.out("hallo");
257 if (TDebug.TraceClip)
258 {
259 TDebug.out("TClip.loop(int): starting sample (forever)");
260 }
261 // m_esdSample.loop();
262 }
263 }
264 // TOOD:
265 }
266
267
268
269 public void flush()
270 {
271 // TOOD:
272 }
273
274
275
276 public void drain()
277 {
278 // TOOD:
279 }
280
281
282
283 public void close()
284 {
285 // m_esdSample.free();
286 // m_esdSample.close();
287 // TOOD:
288 }
289
290
291
292
293 public void open()
294 {
295 // TODO:
296 }
297
298
299
300 public void start()
301 {
302 if (TDebug.TraceClip)
303 {
304 TDebug.out("TClip.start(): called");
305 }
306 /*
307 * This is a hack. What start() really should do is
308 * start playing at the position playback was stopped.
309 */
310 if (TDebug.TraceClip)
311 {
312 TDebug.out("TClip.start(): calling 'loop(0)' [hack]");
313 }
314 loop(0);
315 }
316
317
318
319 public void stop()
320 {
321 // TODO:
322 // m_esdSample.kill();
323 }
324
325
326
327 /*
328 * This method is enforced by DataLine, but doesn't make any
329 * sense for Clips.
330 */
331 public int available()
332 {
333 return -1;
334 }
335}
336
337
338
339/*** TClip.java ***/
340
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
deleted file mode 100644
index 4a370eb86c..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 * TCompoundControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.CompoundControl;
34import javax.sound.sampled.Control;
35
36import org.tritonus.share.TDebug;
37
38
39
40
41/** Base class for classes implementing Line.
42 */
43public class TCompoundControl
44extends CompoundControl
45implements TControllable
46{
47 private TControlController m_controller;
48
49
50
51 public TCompoundControl(CompoundControl.Type type,
52 Control[] aMemberControls)
53 {
54 super(type, aMemberControls);
55 if (TDebug.TraceControl)
56 {
57 TDebug.out("TCompoundControl.<init>: begin");
58 }
59 m_controller = new TControlController();
60 if (TDebug.TraceControl)
61 {
62 TDebug.out("TCompoundControl.<init>: end");
63 }
64 }
65
66
67
68 public void setParentControl(TCompoundControl compoundControl)
69 {
70 m_controller.setParentControl(compoundControl);
71 }
72
73
74
75 public TCompoundControl getParentControl()
76 {
77 return m_controller.getParentControl();
78 }
79
80
81
82 public void commit()
83 {
84 m_controller.commit();
85 }
86}
87
88
89
90/*** TCompoundControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
deleted file mode 100644
index 1b90b1a673..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * TCompoundControlType.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import javax.sound.sampled.CompoundControl;
32
33
34
35/** CompoundControl.Type class.
36 This class is only needed to provide a public constructor.
37 */
38public class TCompoundControlType
39extends CompoundControl.Type
40{
41 /** Constructor.
42 Constructs a CompoundControl.Type with the
43 name given.
44
45 @param strName The name of the control.
46 */
47 public TCompoundControlType(String strName)
48 {
49 super(strName);
50 }
51}
52
53
54
55/*** TCompoundControlType.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControlController.java b/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
deleted file mode 100644
index ec17c45b59..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * TControlController.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public class TControlController
56implements TControllable
57{
58 /** The parent (compound) control.
59 In case this control is part of a compound control, the parentControl
60 property is set to a value other than null.
61 */
62 private TCompoundControl m_parentControl;
63
64
65 public TControlController()
66 {
67 }
68
69
70
71 public void setParentControl(TCompoundControl compoundControl)
72 {
73 m_parentControl = compoundControl;
74 }
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_parentControl;
80 }
81
82
83 public void commit()
84 {
85 if (TDebug.TraceControl)
86 {
87 TDebug.out("TControlController.commit(): called [" + this.getClass().getName() + "]");
88 }
89 if (getParentControl() != null)
90 {
91 getParentControl().commit();
92 }
93 }
94}
95
96
97
98/*** TControlController.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControllable.java b/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
deleted file mode 100644
index b89d34a2b3..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * TControllable.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53public interface TControllable
54{
55 public void setParentControl(TCompoundControl compoundControl);
56 public TCompoundControl getParentControl();
57 public void commit();
58}
59
60
61
62/*** TControllable.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
deleted file mode 100644
index a493bac6c5..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
+++ /dev/null
@@ -1,304 +0,0 @@
1/*
2 * TDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.EventListener;
35import java.util.EventObject;
36import java.util.HashSet;
37import java.util.Set;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.DataLine;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.Line;
45
46import org.tritonus.share.TDebug;
47
48
49
50/** Base class for classes implementing DataLine.
51 */
52public abstract class TDataLine
53extends TLine
54implements DataLine
55{
56 private static final int DEFAULT_BUFFER_SIZE = 128000;
57
58 private AudioFormat m_format;
59 private int m_nBufferSize;
60 private boolean m_bRunning;
61 // private boolean m_bActive;
62
63
64
65
66 public TDataLine(TMixer mixer,
67 DataLine.Info info)
68 {
69 super(mixer,
70 info);
71 init(info);
72 }
73
74
75
76 public TDataLine(TMixer mixer,
77 DataLine.Info info,
78 Collection<Control> controls)
79 {
80 super(mixer,
81 info,
82 controls);
83 init(info);
84 }
85
86
87
88 // IDEA: extract format and bufsize from info?
89 private void init(DataLine.Info info)
90 {
91 m_format = null;
92 m_nBufferSize = AudioSystem.NOT_SPECIFIED;
93 setRunning(false);
94 // setActive(false);
95 }
96
97
98
99 // not defined here:
100 // public void drain()
101 // public void flush()
102
103
104
105 public void start()
106 {
107 if (TDebug.TraceSourceDataLine)
108 {
109 TDebug.out("TDataLine.start(): called");
110 }
111 setRunning(true);
112 }
113
114
115
116 public void stop()
117 {
118 if (TDebug.TraceSourceDataLine)
119 {
120 TDebug.out("TDataLine.stop(): called");
121 }
122 setRunning(false);
123 }
124
125
126
127 public boolean isRunning()
128 {
129 return m_bRunning;
130 }
131
132
133
134 // TODO: recheck
135 protected void setRunning(boolean bRunning)
136 {
137 boolean bOldValue = isRunning();
138 m_bRunning = bRunning;
139 if (bOldValue != isRunning())
140 {
141 if (isRunning())
142 {
143 startImpl();
144 notifyLineEvent(LineEvent.Type.START);
145 }
146 else
147 {
148 stopImpl();
149 notifyLineEvent(LineEvent.Type.STOP);
150 }
151 }
152 }
153
154
155
156 protected void startImpl()
157 {
158 }
159
160
161
162 protected void stopImpl()
163 {
164 }
165
166
167
168 /**
169 * This implementation returns the status of isRunning().
170 * Subclasses should overwrite this method if there is more
171 * precise information about the status of the line available.
172 */
173 public boolean isActive()
174 {
175 return isRunning();
176 }
177
178
179/*
180 public boolean isStarted()
181 {
182 return m_bStarted;
183 }
184*/
185
186 // TODO: should only ALLOW engaging in data I/O.
187 // actual START event should only be sent when line really becomes active
188/*
189 protected void setStarted(boolean bStarted)
190 {
191 m_bStarted = bStarted;
192 if (!isRunning())
193 {
194 setActive(false);
195 }
196 }
197*/
198
199
200 public AudioFormat getFormat()
201 {
202 return m_format;
203 }
204
205
206
207 protected void setFormat(AudioFormat format)
208 {
209 if (TDebug.TraceDataLine)
210 {
211 TDebug.out("TDataLine.setFormat(): setting: " + format);
212 }
213 m_format = format;
214 }
215
216
217
218 public int getBufferSize()
219 {
220 return m_nBufferSize;
221 }
222
223
224
225 protected void setBufferSize(int nBufferSize)
226 {
227 if (TDebug.TraceDataLine)
228 {
229 TDebug.out("TDataLine.setBufferSize(): setting: " + nBufferSize);
230 }
231 m_nBufferSize = nBufferSize;
232 }
233
234
235
236 // not defined here:
237 // public int available()
238
239
240
241 public int getFramePosition()
242 {
243 // TODO:
244 return -1;
245 }
246
247
248
249 public long getLongFramePosition()
250 {
251 // TODO:
252 return -1;
253 }
254
255
256
257 public long getMicrosecondPosition()
258 {
259 return (long) (getFramePosition() * getFormat().getFrameRate() * 1000000);
260 }
261
262
263
264 /*
265 * Has to be overridden to be useful.
266 */
267 public float getLevel()
268 {
269 return AudioSystem.NOT_SPECIFIED;
270 }
271
272
273
274 protected void checkOpen()
275 {
276 if (getFormat() == null)
277 {
278 throw new IllegalStateException("format must be specified");
279 }
280 if (getBufferSize() == AudioSystem.NOT_SPECIFIED)
281 {
282 setBufferSize(getDefaultBufferSize());
283 }
284 }
285
286
287
288 protected int getDefaultBufferSize()
289 {
290 return DEFAULT_BUFFER_SIZE;
291 }
292
293
294
295 protected void notifyLineEvent(LineEvent.Type type)
296 {
297 notifyLineEvent(new LineEvent(this, type, getFramePosition()));
298 }
299}
300
301
302
303/*** TDataLine.java ***/
304
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java b/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
deleted file mode 100644
index 2c9132401f..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
+++ /dev/null
@@ -1,92 +0,0 @@
1/*
2 * TEnumControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.EnumControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TEnumControl
43extends EnumControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TEnumControl(EnumControl.Type type,
51 Object[] aValues,
52 Object value)
53 {
54 super(type,
55 aValues,
56 value);
57 if (TDebug.TraceControl)
58 {
59 TDebug.out("TEnumControl.<init>: begin");
60 }
61 m_controller = new TControlController();
62 if (TDebug.TraceControl)
63 {
64 TDebug.out("TEnumControl.<init>: end");
65 }
66 }
67
68
69
70 public void setParentControl(TCompoundControl compoundControl)
71 {
72 m_controller.setParentControl(compoundControl);
73 }
74
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_controller.getParentControl();
80 }
81
82
83
84 public void commit()
85 {
86 m_controller.commit();
87 }
88}
89
90
91
92/*** TEnumControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java b/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
deleted file mode 100644
index 8a80016865..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
+++ /dev/null
@@ -1,134 +0,0 @@
1/*
2 * TFloatControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.FloatControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TFloatControl
43extends FloatControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TFloatControl(FloatControl.Type type,
51 float fMinimum,
52 float fMaximum,
53 float fPrecision,
54 int nUpdatePeriod,
55 float fInitialValue,
56 String strUnits)
57 {
58 super(type,
59 fMinimum,
60 fMaximum,
61 fPrecision,
62 nUpdatePeriod,
63 fInitialValue,
64 strUnits);
65 if (TDebug.TraceControl)
66 {
67 TDebug.out("TFloatControl.<init>: begin");
68 }
69 m_controller = new TControlController();
70 if (TDebug.TraceControl)
71 {
72 TDebug.out("TFloatControl.<init>: end");
73 }
74 }
75
76
77
78 public TFloatControl(FloatControl.Type type,
79 float fMinimum,
80 float fMaximum,
81 float fPrecision,
82 int nUpdatePeriod,
83 float fInitialValue,
84 String strUnits,
85 String strMinLabel,
86 String strMidLabel,
87 String strMaxLabel)
88 {
89 super(type,
90 fMinimum,
91 fMaximum,
92 fPrecision,
93 nUpdatePeriod,
94 fInitialValue,
95 strUnits,
96 strMinLabel,
97 strMidLabel,
98 strMaxLabel);
99 if (TDebug.TraceControl)
100 {
101 TDebug.out("TFloatControl.<init>: begin");
102 }
103 m_controller = new TControlController();
104 if (TDebug.TraceControl)
105 {
106 TDebug.out("TFloatControl.<init>: end");
107 }
108 }
109
110
111
112 public void setParentControl(TCompoundControl compoundControl)
113 {
114 m_controller.setParentControl(compoundControl);
115 }
116
117
118
119 public TCompoundControl getParentControl()
120 {
121 return m_controller.getParentControl();
122 }
123
124
125
126 public void commit()
127 {
128 m_controller.commit();
129 }
130}
131
132
133
134/*** TFloatControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TLine.java b/songdbj/org/tritonus/share/sampled/mixer/TLine.java
deleted file mode 100644
index 89b38099ed..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TLine.java
+++ /dev/null
@@ -1,362 +0,0 @@
1/*
2 * TLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.TNotifier;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public abstract class TLine
56implements Line
57{
58 private static final Control[] EMPTY_CONTROL_ARRAY = new Control[0];
59
60 private Line.Info m_info;
61 private boolean m_bOpen;
62 private List<Control> m_controls;
63 private Set<LineListener> m_lineListeners;
64 private TMixer m_mixer;
65
66
67
68 protected TLine(TMixer mixer,
69 Line.Info info)
70 {
71 setLineInfo(info);
72 setOpen(false);
73 m_controls = new ArrayList<Control>();
74 m_lineListeners = new HashSet<LineListener>();
75 m_mixer = mixer;
76 }
77
78
79
80 protected TLine(TMixer mixer,
81 Line.Info info,
82 Collection<Control> controls)
83 {
84 this (mixer, info);
85 m_controls.addAll(controls);
86 }
87
88
89 protected TMixer getMixer()
90 {
91 return m_mixer;
92 }
93
94
95 public Line.Info getLineInfo()
96 {
97 return m_info;
98 }
99
100
101
102 protected void setLineInfo(Line.Info info)
103 {
104 if (TDebug.TraceLine)
105 {
106 TDebug.out("TLine.setLineInfo(): setting: " + info);
107 }
108 synchronized (this)
109 {
110 m_info = info;
111 }
112 }
113
114
115
116 public void open()
117 throws LineUnavailableException
118 {
119 if (TDebug.TraceLine)
120 {
121 TDebug.out("TLine.open(): called");
122 }
123 if (! isOpen())
124 {
125 if (TDebug.TraceLine)
126 {
127 TDebug.out("TLine.open(): opening");
128 }
129 openImpl();
130 if (getMixer() != null)
131 {
132 getMixer().registerOpenLine(this);
133 }
134 setOpen(true);
135 }
136 else
137 {
138 if (TDebug.TraceLine)
139 {
140 TDebug.out("TLine.open(): already open");
141 }
142 }
143 }
144
145
146
147 /**
148 * Subclasses should override this method.
149 */
150 protected void openImpl()
151 throws LineUnavailableException
152 {
153 if (TDebug.TraceLine)
154 {
155 TDebug.out("TLine.openImpl(): called");
156 }
157 }
158
159
160
161 public void close()
162 {
163 if (TDebug.TraceLine)
164 {
165 TDebug.out("TLine.close(): called");
166 }
167 if (isOpen())
168 {
169 if (TDebug.TraceLine)
170 {
171 TDebug.out("TLine.close(): closing");
172 }
173 if (getMixer() != null)
174 {
175 getMixer().unregisterOpenLine(this);
176 }
177 closeImpl();
178 setOpen(false);
179 }
180 else
181 {
182 if (TDebug.TraceLine)
183 {
184 TDebug.out("TLine.close(): not open");
185 }
186 }
187 }
188
189
190
191 /**
192 * Subclasses should override this method.
193 */
194 protected void closeImpl()
195 {
196 if (TDebug.TraceLine)
197 {
198 TDebug.out("TLine.closeImpl(): called");
199 }
200 }
201
202
203
204
205
206 public boolean isOpen()
207 {
208 return m_bOpen;
209 }
210
211
212
213
214 protected void setOpen(boolean bOpen)
215 {
216 if (TDebug.TraceLine)
217 {
218 TDebug.out("TLine.setOpen(): called, value: " + bOpen);
219 }
220 boolean bOldValue = isOpen();
221 m_bOpen = bOpen;
222 if (bOldValue != isOpen())
223 {
224 if (isOpen())
225 {
226 if (TDebug.TraceLine)
227 {
228 TDebug.out("TLine.setOpen(): opened");
229 }
230 notifyLineEvent(LineEvent.Type.OPEN);
231 }
232 else
233 {
234 if (TDebug.TraceLine)
235 {
236 TDebug.out("TLine.setOpen(): closed");
237 }
238 notifyLineEvent(LineEvent.Type.CLOSE);
239 }
240 }
241 }
242
243
244
245 protected void addControl(Control control)
246 {
247 synchronized (m_controls)
248 {
249 m_controls.add(control);
250 }
251 }
252
253
254
255 protected void removeControl(Control control)
256 {
257 synchronized (m_controls)
258 {
259 m_controls.remove(control);
260 }
261 }
262
263
264
265 public Control[] getControls()
266 {
267 synchronized (m_controls)
268 {
269 return m_controls.toArray(EMPTY_CONTROL_ARRAY);
270 }
271 }
272
273
274
275 public Control getControl(Control.Type controlType)
276 {
277 synchronized (m_controls)
278 {
279 Iterator<Control> it = m_controls.iterator();
280 while (it.hasNext())
281 {
282 Control control = it.next();
283 if (control.getType().equals(controlType))
284 {
285 return control;
286 }
287 }
288 throw new IllegalArgumentException("no control of type " + controlType);
289 }
290 }
291
292
293
294 public boolean isControlSupported(Control.Type controlType)
295 {
296 // TDebug.out("TLine.isSupportedControl(): called");
297 try
298 {
299 return getControl(controlType) != null;
300 }
301 catch (IllegalArgumentException e)
302 {
303 if (TDebug.TraceAllExceptions)
304 {
305 TDebug.out(e);
306 }
307 // TDebug.out("TLine.isSupportedControl(): returning false");
308 return false;
309 }
310 }
311
312
313
314 public void addLineListener(LineListener listener)
315 {
316 // TDebug.out("%% TChannel.addListener(): called");
317 synchronized (m_lineListeners)
318 {
319 m_lineListeners.add(listener);
320 }
321 }
322
323
324
325 public void removeLineListener(LineListener listener)
326 {
327 synchronized (m_lineListeners)
328 {
329 m_lineListeners.remove(listener);
330 }
331 }
332
333
334
335 private Set<LineListener> getLineListeners()
336 {
337 synchronized (m_lineListeners)
338 {
339 return new HashSet<LineListener>(m_lineListeners);
340 }
341 }
342
343
344 // is overridden in TDataLine to provide a position
345 protected void notifyLineEvent(LineEvent.Type type)
346 {
347 notifyLineEvent(new LineEvent(this, type, AudioSystem.NOT_SPECIFIED));
348 }
349
350
351
352 protected void notifyLineEvent(LineEvent event)
353 {
354 // TDebug.out("%% TChannel.notifyChannelEvent(): called");
355 // Channel.Event event = new Channel.Event(this, type, getPosition());
356 TNotifier.notifier.addEntry(event, getLineListeners());
357 }
358}
359
360
361
362/*** TLine.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixer.java b/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
deleted file mode 100644
index 6a5dc4db72..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
+++ /dev/null
@@ -1,506 +0,0 @@
1/*
2 * TMixer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36import java.util.Set;
37
38import javax.sound.sampled.AudioFormat;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.Line;
42import javax.sound.sampled.LineUnavailableException;
43import javax.sound.sampled.Mixer;
44import javax.sound.sampled.Port;
45import javax.sound.sampled.SourceDataLine;
46import javax.sound.sampled.TargetDataLine;
47
48import org.tritonus.share.TDebug;
49import org.tritonus.share.sampled.AudioFormats;
50import org.tritonus.share.ArraySet;
51
52
53
54// TODO: global controls (that use the system mixer)
55public abstract class TMixer
56extends TLine
57implements Mixer
58{
59 private static Line.Info[] EMPTY_LINE_INFO_ARRAY = new Line.Info[0];
60 private static Line[] EMPTY_LINE_ARRAY = new Line[0];
61
62 private Mixer.Info m_mixerInfo;
63 private Collection<AudioFormat> m_supportedSourceFormats;
64 private Collection<AudioFormat> m_supportedTargetFormats;
65 private Collection<Line.Info> m_supportedSourceLineInfos;
66 private Collection<Line.Info> m_supportedTargetLineInfos;
67 private Set<SourceDataLine> m_openSourceDataLines;
68 private Set<TargetDataLine> m_openTargetDataLines;
69
70
71 /** Constructor for mixers that use setSupportInformation().
72 */
73 protected TMixer(Mixer.Info mixerInfo,
74 Line.Info lineInfo)
75 {
76 this(mixerInfo,
77 lineInfo,
78 new ArrayList<AudioFormat>(),
79 new ArrayList<AudioFormat>(),
80 new ArrayList<Line.Info>(),
81 new ArrayList<Line.Info>());
82 }
83
84
85
86 /** Constructor for mixers.
87 */
88 protected TMixer(Mixer.Info mixerInfo,
89 Line.Info lineInfo,
90 Collection<AudioFormat> supportedSourceFormats,
91 Collection<AudioFormat> supportedTargetFormats,
92 Collection<Line.Info> supportedSourceLineInfos,
93 Collection<Line.Info> supportedTargetLineInfos)
94 {
95 super(null, // TMixer
96 lineInfo);
97 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): begin"); }
98 m_mixerInfo = mixerInfo;
99 setSupportInformation(
100 supportedSourceFormats,
101 supportedTargetFormats,
102 supportedSourceLineInfos,
103 supportedTargetLineInfos);
104 m_openSourceDataLines = new ArraySet<SourceDataLine>();
105 m_openTargetDataLines = new ArraySet<TargetDataLine>();
106 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): end"); }
107 }
108
109
110
111 protected void setSupportInformation(
112 Collection<AudioFormat> supportedSourceFormats,
113 Collection<AudioFormat> supportedTargetFormats,
114 Collection<Line.Info> supportedSourceLineInfos,
115 Collection<Line.Info> supportedTargetLineInfos)
116 {
117 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): begin"); }
118 m_supportedSourceFormats = supportedSourceFormats;
119 m_supportedTargetFormats = supportedTargetFormats;
120 m_supportedSourceLineInfos = supportedSourceLineInfos;
121 m_supportedTargetLineInfos = supportedTargetLineInfos;
122 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): end"); }
123 }
124
125
126
127 public Mixer.Info getMixerInfo()
128 {
129 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): begin"); }
130 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): end"); }
131 return m_mixerInfo;
132 }
133
134
135
136 public Line.Info[] getSourceLineInfo()
137 {
138 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): begin"); }
139 Line.Info[] infos = (Line.Info[]) m_supportedSourceLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
140 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): end"); }
141 return infos;
142 }
143
144
145
146 public Line.Info[] getTargetLineInfo()
147 {
148 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): begin"); }
149 Line.Info[] infos = (Line.Info[]) m_supportedTargetLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
150 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): end"); }
151 return infos;
152 }
153
154
155
156 public Line.Info[] getSourceLineInfo(Line.Info info)
157 {
158 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(Line.Info): info to test: " + info); }
159 // TODO:
160 return EMPTY_LINE_INFO_ARRAY;
161 }
162
163
164
165 public Line.Info[] getTargetLineInfo(Line.Info info)
166 {
167 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(Line.Info): info to test: " + info); }
168 // TODO:
169 return EMPTY_LINE_INFO_ARRAY;
170 }
171
172
173
174 public boolean isLineSupported(Line.Info info)
175 {
176 if (TDebug.TraceMixer) { TDebug.out("TMixer.isLineSupported(): info to test: " + info); }
177 Class lineClass = info.getLineClass();
178 if (lineClass.equals(SourceDataLine.class))
179 {
180 return isLineSupportedImpl(info, m_supportedSourceLineInfos);
181 }
182 else if (lineClass.equals(TargetDataLine.class))
183 {
184 return isLineSupportedImpl(info, m_supportedTargetLineInfos);
185 }
186 else if (lineClass.equals(Port.class))
187 {
188 return isLineSupportedImpl(info, m_supportedSourceLineInfos) || isLineSupportedImpl(info, m_supportedTargetLineInfos);
189 }
190 else
191 {
192 return false;
193 }
194 }
195
196
197
198 private static boolean isLineSupportedImpl(Line.Info info, Collection supportedLineInfos)
199 {
200 Iterator iterator = supportedLineInfos.iterator();
201 while (iterator.hasNext())
202 {
203 Line.Info info2 = (Line.Info) iterator.next();
204 if (info2.matches(info))
205 {
206 return true;
207 }
208 }
209 return false;
210 }
211
212
213
214 public Line getLine(Line.Info info)
215 throws LineUnavailableException
216 {
217 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): begin"); }
218 Class lineClass = info.getLineClass();
219 DataLine.Info dataLineInfo = null;
220 Port.Info portInfo = null;
221 AudioFormat[] aFormats = null;
222 if (info instanceof DataLine.Info)
223 {
224 dataLineInfo = (DataLine.Info) info;
225 aFormats = dataLineInfo.getFormats();
226 }
227 else if (info instanceof Port.Info)
228 {
229 portInfo = (Port.Info) info;
230 }
231 AudioFormat format = null;
232 Line line = null;
233 if (lineClass == SourceDataLine.class)
234 {
235 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: SourceDataLine"); }
236 if (dataLineInfo == null)
237 {
238 throw new IllegalArgumentException("need DataLine.Info for SourceDataLine");
239 }
240 format = getSupportedSourceFormat(aFormats);
241 line = getSourceDataLine(format, dataLineInfo.getMaxBufferSize());
242 }
243 else if (lineClass == Clip.class)
244 {
245 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: Clip"); }
246 if (dataLineInfo == null)
247 {
248 throw new IllegalArgumentException("need DataLine.Info for Clip");
249 }
250 format = getSupportedSourceFormat(aFormats);
251 line = getClip(format);
252 }
253 else if (lineClass == TargetDataLine.class)
254 {
255 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
256 if (dataLineInfo == null)
257 {
258 throw new IllegalArgumentException("need DataLine.Info for TargetDataLine");
259 }
260 format = getSupportedTargetFormat(aFormats);
261 line = getTargetDataLine(format, dataLineInfo.getMaxBufferSize());
262 }
263 else if (lineClass == Port.class)
264 {
265 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
266 if (portInfo == null)
267 {
268 throw new IllegalArgumentException("need Port.Info for Port");
269 }
270 line = getPort(portInfo);
271 }
272 else
273 {
274 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): unknown line type, will throw exception"); }
275 throw new LineUnavailableException("unknown line class: " + lineClass);
276 }
277 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): end"); }
278 return line;
279 }
280
281
282
283 protected SourceDataLine getSourceDataLine(AudioFormat format, int nBufferSize)
284 throws LineUnavailableException
285 {
286 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceDataLine(): begin"); }
287 throw new IllegalArgumentException("this mixer does not support SourceDataLines");
288 }
289
290
291
292 protected Clip getClip(AudioFormat format)
293 throws LineUnavailableException
294 {
295 if (TDebug.TraceMixer) { TDebug.out("TMixer.getClip(): begin"); }
296 throw new IllegalArgumentException("this mixer does not support Clips");
297 }
298
299
300
301 protected TargetDataLine getTargetDataLine(AudioFormat format, int nBufferSize)
302 throws LineUnavailableException
303 {
304 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
305 throw new IllegalArgumentException("this mixer does not support TargetDataLines");
306 }
307
308
309
310 protected Port getPort(Port.Info info)
311 throws LineUnavailableException
312 {
313 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
314 throw new IllegalArgumentException("this mixer does not support Ports");
315 }
316
317
318
319 private AudioFormat getSupportedSourceFormat(AudioFormat[] aFormats)
320 {
321 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): begin"); }
322 AudioFormat format = null;
323 for (int i = 0; i < aFormats.length; i++)
324 {
325 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): checking " + aFormats[i] + "..."); }
326 if (isSourceFormatSupported(aFormats[i]))
327 {
328 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): ...supported"); }
329 format = aFormats[i];
330 break;
331 }
332 else
333 {
334 if (TDebug.TraceMixer)
335 {
336 TDebug.out("TMixer.getSupportedSourceFormat(): ...no luck");
337 }
338 }
339 }
340 if (format == null)
341 {
342 throw new IllegalArgumentException("no line matchine one of the passed formats");
343 }
344 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): end"); }
345 return format;
346 }
347
348
349
350 private AudioFormat getSupportedTargetFormat(AudioFormat[] aFormats)
351 {
352 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): begin"); }
353 AudioFormat format = null;
354 for (int i = 0; i < aFormats.length; i++)
355 {
356 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): checking " + aFormats[i] + " ..."); }
357 if (isTargetFormatSupported(aFormats[i]))
358 {
359 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): ...supported"); }
360 format = aFormats[i];
361 break;
362 }
363 else
364 {
365 if (TDebug.TraceMixer)
366 {
367 TDebug.out("TMixer.getSupportedTargetFormat(): ...no luck");
368 }
369 }
370 }
371 if (format == null)
372 {
373 throw new IllegalArgumentException("no line matchine one of the passed formats");
374 }
375 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): end"); }
376 return format;
377 }
378
379
380
381/*
382 not implemented here:
383 getMaxLines(Line.Info)
384*/
385
386
387
388 public Line[] getSourceLines()
389 {
390 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLines(): called"); }
391 return (Line[]) m_openSourceDataLines.toArray(EMPTY_LINE_ARRAY);
392 }
393
394
395
396 public Line[] getTargetLines()
397 {
398 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLines(): called"); }
399 return (Line[]) m_openTargetDataLines.toArray(EMPTY_LINE_ARRAY);
400 }
401
402
403
404 public void synchronize(Line[] aLines,
405 boolean bMaintainSync)
406 {
407 throw new IllegalArgumentException("synchronization not supported");
408 }
409
410
411
412 public void unsynchronize(Line[] aLines)
413 {
414 throw new IllegalArgumentException("synchronization not supported");
415 }
416
417
418
419 public boolean isSynchronizationSupported(Line[] aLines,
420 boolean bMaintainSync)
421 {
422 return false;
423 }
424
425
426
427 protected boolean isSourceFormatSupported(AudioFormat format)
428 {
429 if (TDebug.TraceMixer) { TDebug.out("TMixer.isSourceFormatSupported(): format to test: " + format); }
430 Iterator<AudioFormat> iterator = m_supportedSourceFormats.iterator();
431 while (iterator.hasNext())
432 {
433 AudioFormat supportedFormat = iterator.next();
434 if (AudioFormats.matches(supportedFormat, format))
435 {
436 return true;
437 }
438 }
439 return false;
440 }
441
442
443
444 protected boolean isTargetFormatSupported(AudioFormat format)
445 {
446 if (TDebug.TraceMixer) { TDebug.out("TMixer.isTargetFormatSupported(): format to test: " + format); }
447 Iterator<AudioFormat> iterator = m_supportedTargetFormats.iterator();
448 while (iterator.hasNext())
449 {
450 AudioFormat supportedFormat = iterator.next();
451 if (AudioFormats.matches(supportedFormat, format))
452 {
453 return true;
454 }
455 }
456 return false;
457 }
458
459
460
461 /*package*/ void registerOpenLine(Line line)
462 {
463 if (TDebug.TraceMixer) { TDebug.out("TMixer.registerOpenLine(): line to register: " + line);
464 }
465 if (line instanceof SourceDataLine)
466 {
467 synchronized (m_openSourceDataLines)
468 {
469 m_openSourceDataLines.add((SourceDataLine) line);
470 }
471 }
472 else if (line instanceof TargetDataLine)
473 {
474 synchronized (m_openSourceDataLines)
475 {
476 m_openTargetDataLines.add((TargetDataLine) line);
477 }
478 }
479 }
480
481
482
483 /*package*/ void unregisterOpenLine(Line line)
484 {
485 if (TDebug.TraceMixer) { TDebug.out("TMixer.unregisterOpenLine(): line to unregister: " + line); }
486 if (line instanceof SourceDataLine)
487 {
488 synchronized (m_openSourceDataLines)
489 {
490 m_openSourceDataLines.remove((SourceDataLine) line);
491 }
492 }
493 else if (line instanceof TargetDataLine)
494 {
495 synchronized (m_openTargetDataLines)
496 {
497 m_openTargetDataLines.remove((TargetDataLine) line);
498 }
499 }
500 }
501}
502
503
504
505/*** TMixer.java ***/
506
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
deleted file mode 100644
index cb4b7cc860..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 * TMixerInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.Mixer;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/*
41 * This is needed only because Mixer.Info's constructor
42 * is protected (in the Sun jdk1.3).
43 */
44public class TMixerInfo
45extends Mixer.Info
46{
47 public TMixerInfo(String a, String b, String c, String d)
48 {
49 super(a, b, c, d);
50 }
51}
52
53
54
55/*** TMixerInfo.java ***/
56
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
deleted file mode 100644
index 3116d74dc3..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
+++ /dev/null
@@ -1,240 +0,0 @@
1/*
2 * TMixerProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.ArrayList;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Iterator;
35import java.util.List;
36import java.util.Map;
37import java.util.Set;
38
39import javax.sound.sampled.Mixer;
40import javax.sound.sampled.spi.MixerProvider;
41
42import org.tritonus.share.TDebug;
43
44
45
46public abstract class TMixerProvider
47extends MixerProvider
48{
49 private static final Mixer.Info[] EMPTY_MIXER_INFO_ARRAY = new Mixer.Info[0];
50
51 private static Map<Class, MixerProviderStruct> sm_mixerProviderStructs = new HashMap<Class, MixerProviderStruct>();
52
53 private boolean m_bDisabled = false;
54
55
56
57
58 public TMixerProvider()
59 {
60 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): begin"); }
61 // currently does nothing
62 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): end"); }
63 }
64
65
66
67 /*
68 Override this method if you want a thread-safe static initializaiton.
69 */
70 protected void staticInit()
71 {
72 }
73
74
75
76 private MixerProviderStruct getMixerProviderStruct()
77 {
78 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): begin"); }
79 Class cls = this.getClass();
80 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): called from " + cls); }
81 // Thread.dumpStack();
82 synchronized (TMixerProvider.class)
83 {
84 MixerProviderStruct struct = sm_mixerProviderStructs.get(cls);
85 if (struct == null)
86 {
87 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): creating new MixerProviderStruct for " + cls); }
88 struct = new MixerProviderStruct();
89 sm_mixerProviderStructs.put(cls, struct);
90 }
91 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): end"); }
92 return struct;
93 }
94 }
95
96
97
98 protected void disable()
99 {
100 if (TDebug.TraceMixerProvider) { TDebug.out("disabling " + getClass().getName()); }
101 m_bDisabled = true;
102 }
103
104
105 protected boolean isDisabled()
106 {
107 return m_bDisabled;
108 }
109
110
111
112 protected void addMixer(Mixer mixer)
113 {
114 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): begin"); }
115 MixerProviderStruct struct = getMixerProviderStruct();
116 synchronized (struct)
117 {
118 struct.m_mixers.add(mixer);
119 if (struct.m_defaultMixer == null)
120 {
121 struct.m_defaultMixer = mixer;
122 }
123 }
124 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): end"); }
125 }
126
127
128
129 protected void removeMixer(Mixer mixer)
130 {
131 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): begin"); }
132 MixerProviderStruct struct = getMixerProviderStruct();
133 synchronized (struct)
134 {
135 struct.m_mixers.remove(mixer);
136 // TODO: should search for another mixer
137 if (struct.m_defaultMixer == mixer)
138 {
139 struct.m_defaultMixer = null;
140 }
141 }
142 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): end"); }
143 }
144
145
146 // $$mp 2003/01/11: TODO: this implementation may become obsolete once the overridden method in spi.MixerProvider is implemented in a way documented officially.
147 public boolean isMixerSupported(Mixer.Info info)
148 {
149 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): begin"); }
150 boolean bIsSupported = false;
151 Mixer.Info[] infos = getMixerInfo();
152 for (int i = 0; i < infos.length; i++)
153 {
154 if (infos[i].equals(info))
155 {
156 bIsSupported = true;
157 break;
158 }
159 }
160 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): end"); }
161 return bIsSupported;
162 }
163
164
165
166 /**
167 */
168 public Mixer getMixer(Mixer.Info info)
169 {
170 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): begin"); }
171 MixerProviderStruct struct = getMixerProviderStruct();
172 Mixer mixerResult = null;
173 synchronized (struct)
174 {
175 if (info == null)
176 {
177 mixerResult = struct.m_defaultMixer;
178 }
179 else
180 {
181 Iterator mixers = struct.m_mixers.iterator();
182 while (mixers.hasNext())
183 {
184 Mixer mixer = (Mixer) mixers.next();
185 if (mixer.getMixerInfo().equals(info))
186 {
187 mixerResult = mixer;
188 break;
189 }
190 }
191 }
192 }
193 if (mixerResult == null)
194 {
195 throw new IllegalArgumentException("no mixer available for " + info);
196 }
197 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): end"); }
198 return mixerResult;
199 }
200
201
202
203 public Mixer.Info[] getMixerInfo()
204 {
205 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): begin"); }
206 Set<Mixer.Info> mixerInfos = new HashSet<Mixer.Info>();
207 MixerProviderStruct struct = getMixerProviderStruct();
208 synchronized (struct)
209 {
210 Iterator<Mixer> mixers = struct.m_mixers.iterator();
211 while (mixers.hasNext())
212 {
213 Mixer mixer = mixers.next();
214 mixerInfos.add(mixer.getMixerInfo());
215 }
216 }
217 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): end"); }
218 return mixerInfos.toArray(EMPTY_MIXER_INFO_ARRAY);
219 }
220
221
222
223 private class MixerProviderStruct
224 {
225 public List<Mixer> m_mixers;
226 public Mixer m_defaultMixer;
227
228
229
230 public MixerProviderStruct()
231 {
232 m_mixers = new ArrayList<Mixer>();
233 m_defaultMixer = null;
234 }
235 }
236}
237
238
239
240/*** TMixerProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TPort.java b/songdbj/org/tritonus/share/sampled/mixer/TPort.java
deleted file mode 100644
index 18d5abae00..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TPort.java
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 * TPort.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for Ports.
54 */
55public class TPort
56extends TLine
57implements Port
58{
59 public TPort(TMixer mixer,
60 Line.Info info)
61 {
62 super(mixer, info);
63 }
64
65
66
67 public TPort(TMixer mixer,
68 Line.Info info,
69 Collection<Control> controls)
70 {
71 super(mixer, info, controls);
72 }
73}
74
75
76
77/*** TPort.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java b/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
deleted file mode 100644
index b5a8aea2c1..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
+++ /dev/null
@@ -1,318 +0,0 @@
1/*
2 * TSoftClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.io.IOException;
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TSoftClip
52extends TClip
53implements Runnable
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_SIZE = 16384;
57
58
59 private Mixer m_mixer;
60 private SourceDataLine m_line;
61 private byte[] m_abClip;
62 private int m_nRepeatCount;
63 private Thread m_thread;
64
65 public TSoftClip(Mixer mixer, AudioFormat format)
66 throws LineUnavailableException
67 {
68 // TODO: info object
69/*
70 DataLine.Info info = new DataLine.Info(Clip.class,
71 audioFormat, -1);
72*/
73 super(null);
74 m_mixer = mixer;
75 DataLine.Info info = new DataLine.Info(
76 SourceDataLine.class,
77 // TODO: should pass a real AudioFormat object that isn't too restrictive
78 format);
79 m_line = (SourceDataLine) AudioSystem.getLine(info);
80 }
81
82
83
84 public void open(AudioInputStream audioInputStream)
85 throws LineUnavailableException, IOException
86 {
87 AudioFormat audioFormat = audioInputStream.getFormat();
88 setFormat(audioFormat);
89 int nFrameSize = audioFormat.getFrameSize();
90 if (nFrameSize < 1)
91 {
92 throw new IllegalArgumentException("frame size must be positive");
93 }
94 if (TDebug.TraceClip)
95 {
96 TDebug.out("TSoftClip.open(): format: " + audioFormat);
97 // TDebug.out("sample rate: " + audioFormat.getSampleRate());
98 }
99 byte[] abData = new byte[BUFFER_SIZE];
100 ByteArrayOutputStream baos = new ByteArrayOutputStream();
101 int nBytesRead = 0;
102 while (nBytesRead != -1)
103 {
104 try
105 {
106 nBytesRead = audioInputStream.read(abData, 0, abData.length);
107 }
108 catch (IOException e)
109 {
110 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
111 {
112 TDebug.out(e);
113 }
114 }
115 if (nBytesRead >= 0)
116 {
117 if (TDebug.TraceClip)
118 {
119 TDebug.out("TSoftClip.open(): Trying to write: " + nBytesRead);
120 }
121 baos.write(abData, 0, nBytesRead);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("TSoftClip.open(): Written: " + nBytesRead);
125 }
126 }
127 }
128 m_abClip = baos.toByteArray();
129 setBufferSize(m_abClip.length);
130 // open the line
131 m_line.open(getFormat());
132 // to trigger the events
133 // open();
134 }
135
136
137
138 public int getFrameLength()
139 {
140 if (isOpen())
141 {
142 return getBufferSize() / getFormat().getFrameSize();
143 }
144 else
145 {
146 return AudioSystem.NOT_SPECIFIED;
147 }
148 }
149
150
151
152 public long getMicrosecondLength()
153 {
154 if (isOpen())
155 {
156 return (long) (getFrameLength() * getFormat().getFrameRate() * 1000000);
157 }
158 else
159 {
160 return AudioSystem.NOT_SPECIFIED;
161 }
162 }
163
164
165
166 public void setFramePosition(int nPosition)
167 {
168 // TOOD:
169 }
170
171
172
173 public void setMicrosecondPosition(long lPosition)
174 {
175 // TOOD:
176 }
177
178
179
180 public int getFramePosition()
181 {
182 // TOOD:
183 return -1;
184 }
185
186
187
188 public long getMicrosecondPosition()
189 {
190 // TOOD:
191 return -1;
192 }
193
194
195
196 public void setLoopPoints(int nStart, int nEnd)
197 {
198 // TOOD:
199 }
200
201
202
203 public void loop(int nCount)
204 {
205 if (TDebug.TraceClip)
206 {
207 TDebug.out("TSoftClip.loop(int): called; count = " + nCount);
208 }
209 if (false/*isStarted()*/)
210 {
211 /*
212 * only allow zero count to stop the looping
213 * at the end of an iteration.
214 */
215 if (nCount == 0)
216 {
217 if (TDebug.TraceClip)
218 {
219 TDebug.out("TSoftClip.loop(int): stopping sample");
220 }
221 // m_esdSample.stop();
222 }
223 }
224 else
225 {
226 m_nRepeatCount = nCount;
227 m_thread = new Thread(this);
228 m_thread.start();
229 }
230 // TOOD:
231 }
232
233
234
235 public void flush()
236 {
237 // TOOD:
238 }
239
240
241
242 public void drain()
243 {
244 // TOOD:
245 }
246
247
248
249 public void close()
250 {
251 // m_esdSample.free();
252 // m_esdSample.close();
253 // TOOD:
254 }
255
256
257
258
259 public void open()
260 {
261 // TODO:
262 }
263
264
265
266 public void start()
267 {
268 if (TDebug.TraceClip)
269 {
270 TDebug.out("TSoftClip.start(): called");
271 }
272 /*
273 * This is a hack. What start() really should do is
274 * start playing at the position playback was stopped.
275 */
276 if (TDebug.TraceClip)
277 {
278 TDebug.out("TSoftClip.start(): calling 'loop(0)' [hack]");
279 }
280 loop(0);
281 }
282
283
284
285 public void stop()
286 {
287 // TODO:
288 // m_esdSample.kill();
289 }
290
291
292
293 /*
294 * This method is enforced by DataLine, but doesn't make any
295 * sense for Clips.
296 */
297 public int available()
298 {
299 return -1;
300 }
301
302
303
304 public void run()
305 {
306 while (m_nRepeatCount >= 0)
307 {
308 m_line.write(m_abClip, 0, m_abClip.length);
309 m_nRepeatCount--;
310 }
311 }
312
313}
314
315
316
317/*** TSoftClip.java ***/
318
diff --git a/songdbj/org/tritonus/share/sampled/mixer/package.html b/songdbj/org/tritonus/share/sampled/mixer/package.html
deleted file mode 100644
index 681024bc9d..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/package.html
+++ /dev/null
@@ -1,14 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of MixerProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.MixerProvider
11 @see org.tritonus.sampled.mixer.alsa
12 @see org.tritonus.sampled.mixer.esd
13 </body>
14</html>
diff --git a/songdbj/org/tritonus/share/sampled/package.html b/songdbj/org/tritonus/share/sampled/package.html
deleted file mode 100644
index f7a6b56099..0000000000
--- a/songdbj/org/tritonus/share/sampled/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Helper classes for the implementation of sampled audio stuff.
8 The classes provided here .</p>
9 </body>
10</html>