From 9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e Mon Sep 17 00:00:00 2001 From: Michiel Van Der Kolk Date: Mon, 11 Jul 2005 15:42:37 +0000 Subject: Songdb java version, source. only 1.5 compatible git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657 --- .../share/sampled/file/AudioOutputStream.java | 113 +++++ .../sampled/file/HeaderlessAudioOutputStream.java | 58 +++ .../share/sampled/file/TAudioFileFormat.java | 113 +++++ .../share/sampled/file/TAudioFileReader.java | 510 +++++++++++++++++++++ .../share/sampled/file/TAudioFileWriter.java | 484 +++++++++++++++++++ .../share/sampled/file/TAudioOutputStream.java | 197 ++++++++ .../share/sampled/file/TDataOutputStream.java | 79 ++++ .../sampled/file/THeaderlessAudioFileWriter.java | 84 ++++ .../sampled/file/TNonSeekableDataOutputStream.java | 109 +++++ .../sampled/file/TSeekableDataOutputStream.java | 86 ++++ .../org/tritonus/share/sampled/file/package.html | 18 + 11 files changed, 1851 insertions(+) create mode 100644 songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java create mode 100644 songdbj/org/tritonus/share/sampled/file/package.html (limited to 'songdbj/org/tritonus/share/sampled/file') diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java new file mode 100644 index 0000000000..d76296cd2d --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java @@ -0,0 +1,113 @@ +/* + * AudioOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; + + + +/** Represents a one-time writing of audio data to a destination (file or output stream). + * + * This interface is the lowest abstraction level of writing audio data. + * Implementations of this interface should, when write() is called, never + * do buffering and they should never do format conversions. However, + * this interface is intended to abstract the file format (how the + * headers and data chunks look like) and the way of writing to the + * destination object. (implementation note [non-normative]: the last + * should be done by using TDataOutputStream implementing classes). + * + * One reasoning behind this interface was to allow direct, unbuffered + * writing of recorded data. + * In JS API 0.90, there was no obvious way for this. + * Data have had to be recorded to a buffer, then written to a file + * from that buffer. + * This gave problems with long recordings, where the main + * memory of the machine is not big enough to hold all data. There are + * two ways so solve this: + * + * a) Having a special AudioInputStream that fetches its data from a + * TargetDataLine. This way, the loop inside the AudioFileWriters reads + * directely from the recording line via the special AudioInputStream. + * This is the solution Sun adopted for JS 1.0. + * + * b) The other way is to expose a direct interface to the writing of the + * audio file with no loop inside it. This is to enable the application + * programmer to write the main loop itself, possibly doing some + * additional processing inside it. This is the more flexible way. + * The drawback is that it requires a new architecture for writing files. + * + * This interface is the central part of a proposal for the second + * solution. + * The idea is now to use the new structure inside the old one to gain + * experience with it before proposing to make it a public interface + * (public in the sense that it is part of the javax.sound.sampled + * package). + * + * @author Matthias Pfisterer + */ +public interface AudioOutputStream +{ + /** + * Retrieves the AufioFormat of this AudioOutputStream. + */ + public AudioFormat getFormat(); + + + /** Gives length of the stream. + * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED + * to express that the length is unknown. + */ + public long getLength(); + + + + /** + * Writes a chunk of audio data to the destination (file or output stream). + */ + // IDEA: use long? + public int write(byte[] abData, int nOffset, int nLength) + throws IOException; + + + + /** Closes the stream. + * This does write remaining buffered data to the destination, + * backpatch the header, if necessary, and closes the destination. + */ + public void close() + throws IOException; +} + + + +/*** AudioOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java new file mode 100644 index 0000000000..3083fd5b8f --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java @@ -0,0 +1,58 @@ +/* + * HeaderlessAudioOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 by Florian Bomers + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.IOException; +import javax.sound.sampled.AudioFormat; + + +/** + * AudioOutputStream for files without a header; the input is written as it is. + * + * @author Florian Bomers + */ + +// todo: implement directly AudioOutputStream without using TAudioOutputStream + +public class HeaderlessAudioOutputStream extends TAudioOutputStream { + + public HeaderlessAudioOutputStream(AudioFormat audioFormat, + long lLength, + TDataOutputStream dataOutputStream) { + super(audioFormat, lLength, dataOutputStream, false); + } + + protected void writeHeader() throws IOException + { + } +} + +/*** HeaderlessAudioOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java new file mode 100644 index 0000000000..fd9831e291 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java @@ -0,0 +1,113 @@ +/* + * TAudioFileFormat.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; + + + +/** + * This class is just to have a public constructor taking the + * number of bytes of the whole file. The public constructor of + * AudioFileFormat doesn't take this parameter, the one who takes + * it is protected. + * + * @author Matthias Pfisterer + */ +public class TAudioFileFormat +extends AudioFileFormat +{ + private Map m_properties; + private Map m_unmodifiableProperties; + + + /* + * Note that the order of the arguments is different from + * the one in AudioFileFormat. + */ + public TAudioFileFormat(Type type, + AudioFormat audioFormat, + int nLengthInFrames, + int nLengthInBytes) + { + super(type, + nLengthInBytes, + audioFormat, + nLengthInFrames); + } + + + public TAudioFileFormat(Type type, + AudioFormat audioFormat, + int nLengthInFrames, + int nLengthInBytes, + Map properties) + { + super(type, + nLengthInBytes, + audioFormat, + nLengthInFrames); + initMaps(properties); + } + + + private void initMaps(Map properties) + { + /* Here, we make a shallow copy of the map. It's unclear if this + is sufficient (of if a deep copy should be made). + */ + m_properties = new HashMap(); + m_properties.putAll(properties); + m_unmodifiableProperties = Collections.unmodifiableMap(m_properties); + } + + + public Map properties() + { + return m_unmodifiableProperties; + } + + + + protected void setProperty(String key, Object value) + { + m_properties.put(key, value); + } +} + + + +/*** TAudioFileFormat.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java new file mode 100644 index 0000000000..ee79becf20 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java @@ -0,0 +1,510 @@ +/* + * TAudioFileReader.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Matthias Pfisterer + * Copyright (c) 2001 by Florian Bomers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.EOFException; + +import java.net.URL; +import java.net.URLConnection; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +import org.tritonus.share.TDebug; + + + +/** Base class for audio file readers. + This is Tritonus' base class for classes that provide the facility + of detecting an audio file type and reading its header. + Classes should be derived from this class or one of its subclasses + rather than from javax.sound.sampled.spi.AudioFileReader. + + @author Matthias Pfisterer + @author Florian Bomers +*/ +public abstract class TAudioFileReader +extends AudioFileReader +{ + private int m_nMarkLimit = -1; + private boolean m_bRereading; + + + protected TAudioFileReader(int nMarkLimit) + { + this(nMarkLimit, false); + } + + + + protected TAudioFileReader(int nMarkLimit, boolean bRereading) + { + m_nMarkLimit = nMarkLimit; + m_bRereading = bRereading; + } + + + + private int getMarkLimit() + { + return m_nMarkLimit; + } + + + + private boolean isRereading() + { + return m_bRereading; + } + + + + /** Get an AudioFileFormat object for a File. + This method calls getAudioFileFormat(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long). + + @param file the file to read from. + @return an AudioFileFormat instance containing + information from the header of the file passed in. + */ + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin"); } + long lFileLengthInBytes = file.length(); + InputStream inputStream = new FileInputStream(file); + AudioFileFormat audioFileFormat = null; + try + { + audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes); + } + finally + { + inputStream.close(); + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): end"); } + return audioFileFormat; + } + + + + /** Get an AudioFileFormat object for a URL. + This method calls getAudioFileFormat(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long). + + @param url the URL to read from. + @return an AudioFileFormat instance containing + information from the header of the URL passed in. + */ + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException + + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin"); } + long lFileLengthInBytes = getDataLength(url); + InputStream inputStream = url.openStream(); + AudioFileFormat audioFileFormat = null; + try + { + audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes); + } + finally + { + inputStream.close(); + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end"); } + return audioFileFormat; + } + + + + /** Get an AudioFileFormat object for an InputStream. + This method calls getAudioFileFormat(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long). + + @param inputStream the stream to read from. + @return an AudioFileFormat instance containing + information from the header of the stream passed in. + */ + public AudioFileFormat getAudioFileFormat(InputStream inputStream) + throws UnsupportedAudioFileException, IOException + + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin"); } + long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED; + inputStream.mark(getMarkLimit()); + AudioFileFormat audioFileFormat = null; + try + { + audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes); + } + finally + { + /* TODO: required semantics is unclear: should reset() + be executed only when there is an exception or + should it be done always? + */ + inputStream.reset(); + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end"); } + return audioFileFormat; + } + + + + /** Get an AudioFileFormat (internal implementation). + Subclasses must implement this method in a way specific + to the file format they handle. + + Note that depending on the implementation of this method, + you should or should not override + getAudioInputStream(InputStream, long), too (see comment + there). + + @param inputStream The InputStream to read from. + @param lFileLengthInBytes The size of the originating + file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED + should be passed. This value may be used for byteLength in + AudioFileFormat, if this value can't be derived from the + informmation in the file header. + + @return an AudioFileFormat instance containing + information from the header of the stream passed in as + inputStream. + */ + protected abstract AudioFileFormat getAudioFileFormat( + InputStream inputStream, + long lFileLengthInBytes) + throws UnsupportedAudioFileException, IOException; + + + + /** Get an AudioInputStream object for a file. + This method calls getAudioInputStream(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long) and perhaps + override getAudioInputStream(InputStream, long). + + @param file the File object to read from. + @return an AudioInputStream instance containing + the audio data from this file. + */ + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): begin"); } + long lFileLengthInBytes = file.length(); + InputStream inputStream = new FileInputStream(file); + AudioInputStream audioInputStream = null; + try + { + audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes); + } + catch (UnsupportedAudioFileException e) + { + inputStream.close(); + throw e; + } + catch (IOException e) + { + inputStream.close(); + throw e; + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): end"); } + return audioInputStream; + } + + + + /** Get an AudioInputStream object for a URL. + This method calls getAudioInputStream(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long) and perhaps + override getAudioInputStream(InputStream, long). + + @param url the URL to read from. + @return an AudioInputStream instance containing + the audio data from this URL. + */ + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin"); } + long lFileLengthInBytes = getDataLength(url); + InputStream inputStream = url.openStream(); + AudioInputStream audioInputStream = null; + try + { + audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes); + } + catch (UnsupportedAudioFileException e) + { + inputStream.close(); + throw e; + } + catch (IOException e) + { + inputStream.close(); + throw e; + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): end"); } + return audioInputStream; + } + + + + /** Get an AudioInputStream object for an InputStream. + This method calls getAudioInputStream(InputStream, long). + Subclasses should not override this method unless there are + really severe reasons. Normally, it is sufficient to + implement getAudioFileFormat(InputStream, long) and perhaps + override getAudioInputStream(InputStream, long). + + @param inputStream the stream to read from. + @return an AudioInputStream instance containing + the audio data from this stream. + */ + public AudioInputStream getAudioInputStream(InputStream inputStream) + throws UnsupportedAudioFileException, IOException + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin"); } + long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED; + AudioInputStream audioInputStream = null; + inputStream.mark(getMarkLimit()); + try + { + audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes); + } + catch (UnsupportedAudioFileException e) + { + inputStream.reset(); + throw e; + } + catch (IOException e) + { + inputStream.reset(); + throw e; + } + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end"); } + return audioInputStream; + } + + + + /** Get an AudioInputStream (internal implementation). + This implementation calls getAudioFileFormat() with the + same arguments as passed in here. Then, it constructs + an AudioInputStream instance. This instance takes the passed + inputStream in the state it is left after getAudioFileFormat() + did its work. In other words, the implementation here + assumes that getAudioFileFormat() reads the entire header + up to a position exactely where the audio data starts. + If this can't be realized for a certain format, this method + should be overridden. + + @param inputStream The InputStream to read from. + @param lFileLengthInBytes The size of the originating + file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED + should be passed. This value may be used for byteLength in + AudioFileFormat, if this value can't be derived from the + informmation in the file header. + */ + protected AudioInputStream getAudioInputStream(InputStream inputStream, long lFileLengthInBytes) + throws UnsupportedAudioFileException, IOException + { + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin"); } + if (isRereading()) + { + inputStream = new BufferedInputStream(inputStream, getMarkLimit()); + inputStream.mark(getMarkLimit()); + } + AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes); + if (isRereading()) + { + inputStream.reset(); + } + AudioInputStream audioInputStream = + new AudioInputStream(inputStream, + audioFileFormat.getFormat(), + audioFileFormat.getFrameLength()); + if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end"); } + return audioInputStream; + } + + + + protected static int calculateFrameSize(int nSampleSize, int nNumChannels) + { + return ((nSampleSize + 7) / 8) * nNumChannels; + } + + + + private static long getDataLength(URL url) + throws IOException + { + long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED; + URLConnection connection = url.openConnection(); + connection.connect(); + int nLength = connection.getContentLength(); + if (nLength > 0) + { + lFileLengthInBytes = nLength; + } + return lFileLengthInBytes; + } + + + + public static int readLittleEndianInt(InputStream is) + throws IOException + { + int b0 = is.read(); + int b1 = is.read(); + int b2 = is.read(); + int b3 = is.read(); + if ((b0 | b1 | b2 | b3) < 0) + { + throw new EOFException(); + } + return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0); + } + + + + public static short readLittleEndianShort(InputStream is) + throws IOException + { + int b0 = is.read(); + int b1 = is.read(); + if ((b0 | b1) < 0) + { + throw new EOFException(); + } + return (short) ((b1 << 8) + (b0 << 0)); + } + + +/* + * C O N V E R T F R O M I E E E E X T E N D E D + */ + +/* + * Copyright (C) 1988-1991 Apple Computer, Inc. + * All rights reserved. + * + * Machine-independent I/O routines for IEEE floating-point numbers. + * + * NaN's and infinities are converted to HUGE_VAL or HUGE, which + * happens to be infinity on IEEE machines. Unfortunately, it is + * impossible to preserve NaN's in a machine-independent way. + * Infinities are, however, preserved on IEEE machines. + * + * These routines have been tested on the following machines: + * Apple Macintosh, MPW 3.1 C compiler + * Apple Macintosh, THINK C compiler + * Silicon Graphics IRIS, MIPS compiler + * Cray X/MP and Y/MP + * Digital Equipment VAX + * + * + * Implemented by Malcolm Slaney and Ken Turkowski. + * + * Malcolm Slaney contributions during 1988-1990 include big- and little- + * endian file I/O, conversion to and from Motorola's extended 80-bit + * floating-point format, and conversions to and from IEEE single- + * precision floating-point format. + * + * In 1991, Ken Turkowski implemented the conversions to and from + * IEEE double-precision format, added more precision to the extended + * conversions, and accommodated conversions involving +/- infinity, + * NaN's, and denormalized numbers. + */ + + public static double readIeeeExtended(DataInputStream dis) + throws IOException + { + double f = 0.0D; + int expon = 0; + long hiMant = 0L; + long loMant = 0L; + double HUGE = 3.4028234663852886E+038D; + expon = dis.readUnsignedShort(); + long t1 = dis.readUnsignedShort(); + long t2 = dis.readUnsignedShort(); + hiMant = t1 << 16 | t2; + t1 = dis.readUnsignedShort(); + t2 = dis.readUnsignedShort(); + loMant = t1 << 16 | t2; + if(expon == 0 && hiMant == 0L && loMant == 0L) + { + f = 0.0D; + } + else + { + if(expon == 32767) + { + f = HUGE; + } + else + { + expon -= 16383; + expon -= 31; + f = hiMant * Math.pow(2D, expon); + expon -= 32; + f += loMant * Math.pow(2D, expon); + } + } + return f; + } +} + + + +/*** TAudioFileReader.java ***/ + diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java new file mode 100644 index 0000000000..d9d6ee86ec --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java @@ -0,0 +1,484 @@ +/* + * TAudioFileWriter.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999, 2000 by Matthias Pfisterer + * Copyright (c) 1999, 2000 by Florian Bomers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.AudioFileWriter; + +import org.tritonus.share.TDebug; +import org.tritonus.share.sampled.AudioFormats; +import org.tritonus.share.sampled.AudioUtils; +import org.tritonus.share.sampled.TConversionTool; +import org.tritonus.share.ArraySet; + +/** + * Common base class for implementing classes of AudioFileWriter. + *

It provides often-used functionality and the new architecture using + * an AudioOutputStream. + *

There should be only one set of audio formats supported by any given + * class of TAudioFileWriter. This class assumes implicitely that all + * supported file types have a common set of audio formats they can handle. + * + * @author Matthias Pfisterer + * @author Florian Bomers + */ + +public abstract class TAudioFileWriter +extends AudioFileWriter +{ + protected static final int ALL = AudioSystem.NOT_SPECIFIED; + + public static AudioFormat.Encoding PCM_SIGNED=new AudioFormat.Encoding("PCM_SIGNED"); + public static AudioFormat.Encoding PCM_UNSIGNED=new AudioFormat.Encoding("PCM_UNSIGNED"); + + /** Buffer length for the loop in the write() method. + * This is in bytes. Perhaps it should be in frames to give an + * equal amount of latency. + */ + private static final int BUFFER_LENGTH = 16384; + + // only needed for Collection.toArray() + protected static final AudioFileFormat.Type[] NULL_TYPE_ARRAY = new AudioFileFormat.Type[0]; + + + /** The audio file types (AudioFileFormat.Type) that can be + * handled by the AudioFileWriter. + */ + private Collection m_audioFileTypes; + + + + /** The AudioFormats that can be handled by the + * AudioFileWriter. + */ + // IDEA: implement a special collection that uses matches() to test whether an element is already in + private Collection m_audioFormats; + + + /** + * Inheriting classes should call this constructor + * in order to make use of the functionality of TAudioFileWriter. + */ + protected TAudioFileWriter(Collection fileTypes, + Collection audioFormats) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.(): begin"); } + m_audioFileTypes = fileTypes; + m_audioFormats = audioFormats; + if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.(): end"); } + } + + // implementing the interface + public AudioFileFormat.Type[] getAudioFileTypes() + { + return m_audioFileTypes.toArray(NULL_TYPE_ARRAY); + } + + + // implementing the interface + public boolean isFileTypeSupported(AudioFileFormat.Type fileType) + { + return m_audioFileTypes.contains(fileType); + } + + + + // implementing the interface + public AudioFileFormat.Type[] getAudioFileTypes( + AudioInputStream audioInputStream) + { + //$$fb 2000-08-16: rewrote this method. We need to check for *each* + // file type, whether the format is supported ! + AudioFormat format = audioInputStream.getFormat(); + ArraySet res=new ArraySet(); + Iterator it=m_audioFileTypes.iterator(); + while (it.hasNext()) { + AudioFileFormat.Type thisType = it.next(); + if (isAudioFormatSupportedImpl(format, thisType)) { + res.add(thisType); + } + } + return res.toArray(NULL_TYPE_ARRAY); + } + + + + // implementing the interface + public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream audioInputStream) + { + // $$fb 2000-08-16: finally this method works reliably ! + return isFileTypeSupported(fileType) + && (isAudioFormatSupportedImpl(audioInputStream.getFormat(), fileType) + || findConvertableFormat(audioInputStream.getFormat(), fileType)!=null); + // we may soft it up by including the possibility of endian/sign + // changing for PCM formats. + // I prefer to return false if the format is not exactly supported + // but still exectute the write, if only sign/endian changing is necessary. + } + + + + // implementing the interface + public int write(AudioInputStream audioInputStream, + AudioFileFormat.Type fileType, + File file) + throws IOException + { + if (TDebug.TraceAudioFileWriter) + { + TDebug.out(">TAudioFileWriter.write(.., File): called"); + TDebug.out("class: "+getClass().getName()); + } + //$$fb added this check + if (!isFileTypeSupported(fileType)) { + if (TDebug.TraceAudioFileWriter) + { + TDebug.out("< file type is not supported"); + } + throw new IllegalArgumentException("file type is not supported."); + } + + AudioFormat inputFormat = audioInputStream.getFormat(); + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); } + AudioFormat outputFormat = null; + boolean bNeedsConversion = false; + if (isAudioFormatSupportedImpl(inputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); } + outputFormat = inputFormat; + bNeedsConversion = false; + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); } + outputFormat = findConvertableFormat(inputFormat, fileType); + if (outputFormat != null) + { + bNeedsConversion = true; + // $$fb 2000-08-16 made consistent with new conversion trials + // if 8 bit and only endianness changed, don't convert ! + if (outputFormat.getSampleSizeInBits()==8 + && outputFormat.getEncoding().equals(inputFormat.getEncoding())) { + bNeedsConversion = false; + } + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< input format is not supported and not convertable."); } + throw new IllegalArgumentException("format not supported and not convertable"); + } + } + long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream); + TDataOutputStream dataOutputStream = new TSeekableDataOutputStream(file); + AudioOutputStream audioOutputStream = + getAudioOutputStream( + outputFormat, + lLengthInBytes, + fileType, + dataOutputStream); + int written=writeImpl(audioInputStream, + audioOutputStream, + bNeedsConversion); + if (TDebug.TraceAudioFileWriter) + { + TDebug.out("< wrote "+written+" bytes."); + } + return written; + } + + + + // implementing the interface + public int write(AudioInputStream audioInputStream, + AudioFileFormat.Type fileType, + OutputStream outputStream) + throws IOException + { + //$$fb added this check + if (!isFileTypeSupported(fileType)) { + throw new IllegalArgumentException("file type is not supported."); + } + if (TDebug.TraceAudioFileWriter) + { + TDebug.out(">TAudioFileWriter.write(.., OutputStream): called"); + TDebug.out("class: "+getClass().getName()); + } + AudioFormat inputFormat = audioInputStream.getFormat(); + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); } + AudioFormat outputFormat = null; + boolean bNeedsConversion = false; + if (isAudioFormatSupportedImpl(inputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); } + outputFormat = inputFormat; + bNeedsConversion = false; + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); } + outputFormat = findConvertableFormat(inputFormat, fileType); + if (outputFormat != null) + { + bNeedsConversion = true; + // $$fb 2000-08-16 made consistent with new conversion trials + // if 8 bit and only endianness changed, don't convert ! + if (outputFormat.getSampleSizeInBits()==8 + && outputFormat.getEncoding().equals(inputFormat.getEncoding())) { + bNeedsConversion = false; + } + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< format is not supported"); } + throw new IllegalArgumentException("format not supported and not convertable"); + } + } + long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream); + TDataOutputStream dataOutputStream = new TNonSeekableDataOutputStream(outputStream); + AudioOutputStream audioOutputStream = + getAudioOutputStream( + outputFormat, + lLengthInBytes, + fileType, + dataOutputStream); + int written=writeImpl(audioInputStream, + audioOutputStream, + bNeedsConversion); + if (TDebug.TraceAudioFileWriter) { TDebug.out("< wrote "+written+" bytes."); } + return written; + } + + + + protected int writeImpl( + AudioInputStream audioInputStream, + AudioOutputStream audioOutputStream, + boolean bNeedsConversion) + throws IOException + { + if (TDebug.TraceAudioFileWriter) + { + TDebug.out(">TAudioFileWriter.writeImpl(): called"); + TDebug.out("class: "+getClass().getName()); + } + int nTotalWritten = 0; + AudioFormat inputFormat = audioInputStream.getFormat(); + AudioFormat outputFormat = audioOutputStream.getFormat(); + + // TODO: handle case when frame size is unknown ? + int nBytesPerSample = outputFormat.getFrameSize() / outputFormat.getChannels(); + + //$$fb 2000-07-18: BUFFER_LENGTH must be a multiple of frame size... + int nBufferSize=((int)BUFFER_LENGTH/outputFormat.getFrameSize())*outputFormat.getFrameSize(); + byte[] abBuffer = new byte[nBufferSize]; + while (true) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("trying to read (bytes): " + abBuffer.length); } + int nBytesRead = audioInputStream.read(abBuffer); + if (TDebug.TraceAudioFileWriter) { TDebug.out("read (bytes): " + nBytesRead); } + if (nBytesRead == -1) + { + break; + } + if (bNeedsConversion) + { + TConversionTool.changeOrderOrSign(abBuffer, 0, + nBytesRead, nBytesPerSample); + } + int nWritten = audioOutputStream.write(abBuffer, 0, nBytesRead); + nTotalWritten += nWritten; + } + if (TDebug.TraceAudioFileWriter) { TDebug.out(" getSupportedAudioFormats(AudioFileFormat.Type fileType) + { + return m_audioFormats.iterator(); + } + + + /** Checks whether the passed AudioFormat can be handled. + * In this simple implementation, it is only checked if the + * passed AudioFormat matches one of the generally handled + * formats (i.e. the fileType argument is ignored). If the + * handled AudioFormats depend on the file type, this method + * or getSupportedAudioFormats() (on which this method relies) + * has to be overwritten by subclasses. + *

+ * This is the central method for checking if a FORMAT is supported. + * Inheriting classes can overwrite this for performance + * or to exclude/include special type/format combinations. + *

+ * This method is only called when the fileType + * is in the list of supported file types ! Overriding + * classes need not check this. + */ + //$$fb 2000-08-16 changed name, changed documentation. Semantics ! + protected boolean isAudioFormatSupportedImpl( + AudioFormat audioFormat, + AudioFileFormat.Type fileType) + { + if (TDebug.TraceAudioFileWriter) + { + TDebug.out("> TAudioFileWriter.isAudioFormatSupportedImpl(): format to test: " + audioFormat); + TDebug.out("class: "+getClass().getName()); + } + Iterator audioFormats = getSupportedAudioFormats(fileType); + while (audioFormats.hasNext()) + { + AudioFormat handledFormat = (AudioFormat) audioFormats.next(); + if (TDebug.TraceAudioFileWriter) { TDebug.out("matching against format : " + handledFormat); } + if (AudioFormats.matches(handledFormat, audioFormat)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("<...succeeded."); } + return true; + } + } + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); } + return false; + } + + + + protected abstract AudioOutputStream getAudioOutputStream( + AudioFormat audioFormat, + long lLengthInBytes, + AudioFileFormat.Type fileType, + TDataOutputStream dataOutputStream) + throws IOException; + + private AudioFormat findConvertableFormat( + AudioFormat inputFormat, + AudioFileFormat.Type fileType) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.findConvertableFormat(): input format: " + inputFormat); } + if (!isFileTypeSupported(fileType)) { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< input file type is not supported."); } + return null; + } + AudioFormat.Encoding inputEncoding = inputFormat.getEncoding(); + if ((inputEncoding.equals(PCM_SIGNED) || inputEncoding.equals(PCM_UNSIGNED)) + && inputFormat.getSampleSizeInBits() == 8) + { + AudioFormat outputFormat = convertFormat(inputFormat, true, false); + if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); } + if (isAudioFormatSupportedImpl(outputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); } + return outputFormat; + } + //$$fb 2000-08-16: added trial of other endianness for 8bit. We try harder ! + outputFormat = convertFormat(inputFormat, false, true); + if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); } + if (isAudioFormatSupportedImpl(outputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); } + return outputFormat; + } + outputFormat = convertFormat(inputFormat, true, true); + if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); } + if (isAudioFormatSupportedImpl(outputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); } + return outputFormat; + } + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); } + return null; + } + else if (inputEncoding.equals(PCM_SIGNED) && + (inputFormat.getSampleSizeInBits() == 16 || + inputFormat.getSampleSizeInBits() == 24 || + inputFormat.getSampleSizeInBits() == 32) ) + { + // TODO: possible to allow all sample sized > 8 bit? + // $$ fb: don't think that this is necessary. Well, let's talk about that in 5 years :) + AudioFormat outputFormat = convertFormat(inputFormat, false, true); + if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); } + if (isAudioFormatSupportedImpl(outputFormat, fileType)) + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); } + return outputFormat; + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); } + return null; + } + } + else + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); } + return null; + } + } + + // $$fb 2000-08-16: added convenience method + private AudioFormat convertFormat(AudioFormat format, boolean changeSign, boolean changeEndian) { + AudioFormat.Encoding enc=PCM_SIGNED; + if (format.getEncoding().equals(PCM_UNSIGNED)!=changeSign) { + enc=PCM_UNSIGNED; + } + return new AudioFormat( + enc, + format.getSampleRate(), + format.getSampleSizeInBits(), + format.getChannels(), + format.getFrameSize(), + format.getFrameRate(), + format.isBigEndian() ^ changeEndian); + } + +} + + + +/*** TAudioFileWriter.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java new file mode 100644 index 0000000000..e54316c0a6 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java @@ -0,0 +1,197 @@ +/* + * TAudioOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; + +import org.tritonus.share.TDebug; + + +/** + * Base class for classes implementing AudioOutputStream. + * + * @author Matthias Pfisterer + */ + +public abstract class TAudioOutputStream +implements AudioOutputStream +{ + private AudioFormat m_audioFormat; + private long m_lLength; // in bytes + private long m_lCalculatedLength; + private TDataOutputStream m_dataOutputStream; + private boolean m_bDoBackPatching; + private boolean m_bHeaderWritten; + + + + protected TAudioOutputStream(AudioFormat audioFormat, + long lLength, + TDataOutputStream dataOutputStream, + boolean bDoBackPatching) + { + m_audioFormat = audioFormat; + m_lLength = lLength; + m_lCalculatedLength = 0; + m_dataOutputStream = dataOutputStream; + m_bDoBackPatching = bDoBackPatching; + m_bHeaderWritten = false; + } + + + + public AudioFormat getFormat() + { + return m_audioFormat; + } + + + + /** Gives length of the stream. + * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED + * to express that the length is unknown. + */ + public long getLength() + { + return m_lLength; + } + + + + /** Gives number of bytes already written. + */ + // IDEA: rename this to BytesWritten or something like that ? + public long getCalculatedLength() + { + return m_lCalculatedLength; + } + + protected TDataOutputStream getDataOutputStream() + { + return m_dataOutputStream; + } + + + /** Writes audio data to the destination (file or output stream). + */ + // IDEA: use long? + public int write(byte[] abData, int nOffset, int nLength) + throws IOException + { + if (TDebug.TraceAudioOutputStream) + { + TDebug.out("TAudioOutputStream.write(): wanted length: " + nLength); + } + if (! m_bHeaderWritten) + { + writeHeader(); + m_bHeaderWritten = true; + } + // $$fb added + // check that total writes do not exceed specified length + long lTotalLength=getLength(); + if (lTotalLength!=AudioSystem.NOT_SPECIFIED && (m_lCalculatedLength+nLength)>lTotalLength) { + if (TDebug.TraceAudioOutputStream) { + TDebug.out("TAudioOutputStream.write(): requested more bytes to write than possible."); + } + nLength=(int) (lTotalLength-m_lCalculatedLength); + // sanity + if (nLength<0) { + nLength=0; + } + } + // TODO: throw an exception if nLength==0 ? (to indicate end of file ?) + if (nLength>0) { + m_dataOutputStream.write(abData, nOffset, nLength); + m_lCalculatedLength += nLength; + } + if (TDebug.TraceAudioOutputStream) + { + TDebug.out("TAudioOutputStream.write(): calculated (total) length: " + m_lCalculatedLength+" bytes = "+(m_lCalculatedLength/getFormat().getFrameSize())+" frames"); + } + return nLength; + } + + + + /** Writes the header of the audio file. + */ + protected abstract void writeHeader() + throws IOException; + + + + /** Closes the stream. + * This does write remaining buffered data to the destination, + * backpatch the header, if necessary, and closes the destination. + */ + public void close() + throws IOException + { + if (TDebug.TraceAudioOutputStream) + { + TDebug.out("TAudioOutputStream.close(): called"); + } + // flush? + if (m_bDoBackPatching) + { + if (TDebug.TraceAudioOutputStream) + { + TDebug.out("TAudioOutputStream.close(): patching header"); + } + patchHeader(); + } + m_dataOutputStream.close(); + } + + + + protected void patchHeader() + throws IOException + { + TDebug.out("TAudioOutputStream.patchHeader(): called"); + // DO NOTHING + } + + + + protected void setLengthFromCalculatedLength() + { + m_lLength = m_lCalculatedLength; + } +} + + + +/*** TAudioOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java new file mode 100644 index 0000000000..eacc00a2e2 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java @@ -0,0 +1,79 @@ +/* + * TDataOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Florian Bomers + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.DataOutput; +import java.io.IOException; +import java.io.InputStream; + + +/** + * Interface for the file writing classes. + *

Like that it is possible to write to a file without knowing + * the length before. + * + * @author Florian Bomers + */ +public interface TDataOutputStream +extends DataOutput +{ + public boolean supportsSeek(); + + + + public void seek(long position) + throws IOException; + + + + public long getFilePointer() + throws IOException; + + + + public long length() + throws IOException; + + + public void writeLittleEndian32(int value) + throws IOException; + + + public void writeLittleEndian16(short value) + throws IOException; + + public void close() + throws IOException; +} + + + +/*** TDataOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java new file mode 100644 index 0000000000..a9d76de505 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java @@ -0,0 +1,84 @@ +/* + * THeaderlessAudioFileWriter.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 2000 by Florian Bomers + * Copyright (c) 2000 - 2002 by Matthias Pfisterer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.IOException; +import java.util.Collection; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; + +import org.tritonus.share.TDebug; + + + +/** Base class for formats without extra header. + This AudioFileWriter is typically used for compressed formats + where the encoder puts a header into the encoded stream. In this + case, the AudioFileWriter needs not to add a header. This is why + THeaderlessAudioOutputStream is used here. + + @author Florian Bomers + @author Matthias Pfisterer +*/ +public class THeaderlessAudioFileWriter +extends TAudioFileWriter +{ + protected THeaderlessAudioFileWriter(Collection fileTypes, + Collection audioFormats) + { + super(fileTypes, audioFormats); + if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.(): begin"); } + if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.(): end"); } + } + + + + protected AudioOutputStream getAudioOutputStream( + AudioFormat audioFormat, + long lLengthInBytes, + AudioFileFormat.Type fileType, + TDataOutputStream dataOutputStream) + throws IOException + { + if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): begin"); } + AudioOutputStream aos = new HeaderlessAudioOutputStream( + audioFormat, + lLengthInBytes, + dataOutputStream); + if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): end"); } + return aos; + } + +} + + + +/*** THeaderlessAudioFileWriter.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java new file mode 100644 index 0000000000..2e9704ed10 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java @@ -0,0 +1,109 @@ +/* + * TNonSeekableDataOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Florian Bomers + * Copyright (c) 2000 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.DataOutputStream; + + + +/** + * A TDataOutputStream that does not allow seeking. + * + * @author Florian Bomers + * @author Matthias Pfisterer + */ +public class TNonSeekableDataOutputStream +extends DataOutputStream +implements TDataOutputStream +{ + public TNonSeekableDataOutputStream(OutputStream outputStream) + { + super(outputStream); + } + + + + public boolean supportsSeek() + { + return false; + } + + + + public void seek(long position) + throws IOException + { + throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to seek not allowed."); + } + + + + public long getFilePointer() + throws IOException + { + throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to getFilePointer not allowed."); + } + + + + public long length() + throws IOException + { + throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to length not allowed."); + } + + + + public void writeLittleEndian32(int value) + throws IOException + { + writeByte(value & 0xFF); + writeByte((value >> 8) & 0xFF); + writeByte((value >> 16) & 0xFF); + writeByte((value >> 24) & 0xFF); + } + + + + public void writeLittleEndian16(short value) + throws IOException + { + writeByte(value & 0xFF); + writeByte((value >> 8) & 0xFF); + } +} + + + +/*** TNonSeekableDataOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java new file mode 100644 index 0000000000..6f688c5b2e --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java @@ -0,0 +1,86 @@ +/* + * TSeekableDataOutputStream.java + * + * This file is part of Tritonus: http://www.tritonus.org/ + */ + +/* + * Copyright (c) 1999 by Florian Bomers + * Copyright (c) 2000 by Matthias Pfisterer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* +|<--- this code is formatted to fit into 80 columns --->| +*/ + +package org.tritonus.share.sampled.file; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.IOException; + + + +/** + * A TDataOutputStream that allows seeking. + * + * @author Florian Bomers + * @author Matthias Pfisterer + */ +public class TSeekableDataOutputStream +extends RandomAccessFile +implements TDataOutputStream +{ + public TSeekableDataOutputStream(File file) + throws IOException + { + super(file, "rw"); + } + + + + public boolean supportsSeek() + { + return true; + } + + + + public void writeLittleEndian32(int value) + throws IOException + { + writeByte(value & 0xFF); + writeByte((value >> 8) & 0xFF); + writeByte((value >> 16) & 0xFF); + writeByte((value >> 24) & 0xFF); + } + + + + public void writeLittleEndian16(short value) + throws IOException + { + writeByte(value & 0xFF); + writeByte((value >> 8) & 0xFF); + } +} + + + +/*** TSeekableDataOutputStream.java ***/ diff --git a/songdbj/org/tritonus/share/sampled/file/package.html b/songdbj/org/tritonus/share/sampled/file/package.html new file mode 100644 index 0000000000..a79274048c --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/package.html @@ -0,0 +1,18 @@ + + + + + + +

Base classes for the implementation of AudioFileReaders and AudioFileWriters. + The classes provided here .

+ + @see javax.sound.sampled.spi.AudioFileReader + @see javax.sound.sampled.spi.AudioFileWriter + @see org.tritonus.sampled.file + @see org.tritonus.sampled.file.gsm + @see org.tritonus.sampled.file.jorbis + @see org.tritonus.sampled.file.mpeg + @see org.tritonus.sampled.file.vorbis + + -- cgit v1.2.3