-
Type:
Bug
-
Resolution: Fixed
-
Priority:
P4
-
Affects Version/s: 1.3.0
-
Component/s: client-libs
-
1.3
-
generic, x86
-
generic, windows_nt
-
Verified
Name: rlT66838 Date: 12/06/99
java version "1.3beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3beta-O)
Java(TM) HotSpot Client VM (build 1.3beta-O, mixed mode)
I've detected that .au files written with AudioSystem.write(..) are
written with the header magic bytes reversed. According to the
specification, they should be 2e 73 6e 64 (".snd"), but in JS 0.90, they
are written as 64 6e 73 2e. The resulting files are rejected by the
Windows Media Player (NT4.0/SP3) as well as JS itself (tested with
Player). Everything else in the header seems to be ok. I used the
attached program AudioFileTypeConverter to convert the file welcome.wav
from the JavaSoundDemo distribution to a .au file.
Matthias
---
/*
* AudioFileTypeConverter.java
*/
/*
* 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.
*
*/
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.util.Arrays;
import javax.media.sound.sampled.AudioFileFormat;
import javax.media.sound.sampled.AudioFormat;
import javax.media.sound.sampled.AudioInputStream;
import javax.media.sound.sampled.AudioSystem;
import javax.media.sound.sampled.Mixer;
import javax.media.sound.sampled.LineUnavailableException;
import javax.media.sound.sampled.SourceDataLine;
import javax.media.sound.sampled.DataLine;
import javax.media.sound.sampled.Line;
import javax.media.sound.sampled.LineListener;
import javax.media.sound.sampled.LineEvent;
import javax.media.sound.sampled.Type;
public class AudioFileTypeConverter
{
public static void main(String[] args)
{
if (args.length != 3)
{
usage();
}
if (! args[0].equals("-t"))
{
usage();
}
Type targetType = new Type(args[1]);
String strFilename = args[2];
File file = new File(strFilename);
AudioInputStream ais = null;
try
{
ais = AudioSystem.getAudioInputStream(file);
}
catch (Exception e)
{
e.printStackTrace();
}
if (ais == null)
{
System.out.println("cannot open audio file");
System.exit(1);
}
else
{
Type[] aAvailableTypes =
AudioSystem.getAudioFileTypes(ais);
boolean bTypeIsSupported = false;
for (int i = 0; i < aAvailableTypes.length; i++)
{
// System.out.println("type: " +
aAvailableTypes[i]);
/*
* In JS 0.90, the equals() method of Type
* is not overwritten correctely. It
* compares with Object.equals() instead
* of comparing the string content of
* the Type objects. The following code
* should really be:
* if
(aAvailableTypes[i].equals(targetType))
* And the targetType = aAvailableTypes[i]
should not be necessary.
*/
if
(aAvailableTypes[i].getName().equals(targetType.getName()))
{
bTypeIsSupported = true;
targetType = aAvailableTypes[i];
break;
}
}
if (! bTypeIsSupported)
{
System.out.println("Requested target type is not
supported.");
System.exit(1);
}
String strExtension = "." +
targetType.getName().toLowerCase();
int nDotPosition = strFilename.lastIndexOf('.');
String strOutputFilename = null;
if (nDotPosition == -1)
{
strOutputFilename = strFilename + strExtension;
}
else
{
strOutputFilename = strFilename.substring(0,
nDotPosition) + strExtension;
}
System.out.println("Output filename: " +
strOutputFilename);
AudioFileFormat outFileFormat = new
AudioFileFormat(targetType, ais.getFormat(), (int) ais.getLength());
int nWrittenFrames = 0;
try
{
nWrittenFrames = AudioSystem.write(ais,
outFileFormat, new File(strOutputFilename));
}
catch (IOException e)
{
e.printStackTrace();
}
System.out.println("Written frames: " + nWrittenFrames);
}
System.exit(0);
}
public static void usage()
{
System.out.println("AudioFileTypeConverter: usage:");
System.out.println("\tjava AudioFileTypeConverter -t
<targettype> <soundfile>");
System.out.println("possible values for <targettype>
(jdk1.3beta, Tritonus 0.81): WAVE, AU, AIFF, AIFF-C, SND");
System.exit(1);
}
}
/*** AudioFileTypeConverter.java ***/
---
/*
* Player.java
*
* Plays a single soundfile.
* This file is part of the JavaSound Examples
*/
/*
* 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.
*
*/
import java.io.File;
import java.io.IOException;
import javax.media.sound.sampled.AudioFormat;
import javax.media.sound.sampled.AudioInputStream;
import javax.media.sound.sampled.AudioSystem;
import javax.media.sound.sampled.DataLine;
import javax.media.sound.sampled.LineUnavailableException;
import javax.media.sound.sampled.SourceDataLine;
public class Player
{
private static final int EXTERNAL_BUFFER_SIZE = 44000 * 4;
public static void main(String[] args)
{
/*
* We check that there is exactely one command-line
* argument. If not, we display the usage message and exit.
*/
if (args.length != 1)
{
System.out.println("Player: usage:");
System.out.println("\tjava Player <soundfile>");
System.exit(1);
}
/*
* Now, that we're shure there is an argument, we take it
as
* the filename of the soundfile we want to play.
*/
String strFilename = args[0];
File soundFile = new File(strFilename);
/*
* We have to read in the sound file.
*/
AudioInputStream audioInputStream = null;
try
{
audioInputStream =
AudioSystem.getAudioInputStream(soundFile);
}
catch (Exception e)
{
/*
* In case of an exception, we dump the exception
* including the stack trace to the console output.
* Then, we exit the program.
*/
e.printStackTrace();
System.exit(1);
}
/*
* From the AudioInputStream, i.e. from the sound file, we
* fetch information about the format of the audio data.
These
* information include the sampling frequency, the number
of
* channels and the size of the samples. There information
* are needed to ask JavaSound for a suitable output line
* for this audio file.
*/
AudioFormat audioFormat = audioInputStream.getFormat();
System.out.println("format: " + audioFormat);
/*
* Compressed audio data cannot be fed directely to
* JavaSound. It has to be converted explicitely.
* To do this, we create a new AudioFormat that
* says to which format we want to convert to. Then,
* we try to get a converted AudioInputStream.
* Furthermore, we use the new format and the converted
* stream.
*
* Note that the technique shown here is partly non-
* portable.. It is used here to keep the example
* simple. A more advanced, more portable technique
* will (hopefully) show up in AudioStream.java soon.
*
* Thanks to Christoph Hecker for finding out that this
* was missing.
*/
if ((audioFormat.getEncoding() == AudioFormat.ULAW) ||
(audioFormat.getEncoding() == AudioFormat.ALAW))
{
AudioFormat newFormat = new AudioFormat(
AudioFormat.PCM_SIGNED,
audioFormat.getSampleRate(),
audioFormat.getSampleSizeInBits() * 2,
audioFormat.getChannels(),
audioFormat.getFrameSize() * 2,
audioFormat.getFrameRate(),
true);
AudioInputStream newStream =
AudioSystem.getAudioInputStream(newFormat, audioInputStream);
audioFormat = newFormat;
audioInputStream = newStream;
}
/*
* Asking for a line is a rather tricky thing.
* First, we have to say which kind of line we want. The
* possibilities are: SourceDataLine (for playback), Clip
* and TargetDataLine (for recording). Here, we want to do
* normal playback, so we ask for a SourceDataLine.
* The next three parameters are for advanced
* applications. We just supply default values here.
* Then, we have to pass an AudioFormat object, so that
* the Line knows which format the data passed to it
* will have.
* Furthermore, we have to give JavaSound a hint about how
* big the internal buffer for the line should be. Here,
* we say AudioSystem.NOT_SPECIFIED, signaling that we
* don't care about the exact size. JavaSound will use
* some default value for the buffer size.
*/
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
null, null, new Class[0], audioFormat, AudioSystem.NOT_SPECIFIED);
try
{
line = (SourceDataLine) AudioSystem.getLine(info);
/*
* The line is there, but it is not yet ready to
* receive audio data. We have to open the line.
*/
line.open(audioFormat, line.getBufferSize());
}
catch (LineUnavailableException e)
{
e.printStackTrace();
System.exit(1);
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
/*
* Still not enough. The line now can receive data,
* but will not pass them on to the audio output device
* (which means to your sound card). This has to be
* activated.
*/
line.start();
/*
* Ok, finally the line is prepared. Now comes the real
job:
* we have to write data to the line. We do this in a loop.
* First, we read data from the AudioInputStream to a
buffer.
* Then, we write from this buffer to the Line.
* Note that the the read function of AudioInputStream
returns
* the number of bytes read. From this number, the number
of
* frames has to be calculated. The frame includes the
sample
* values of all channels. If you have stereo (two
channels)
* and 16 bit samples, a frame takes four bytes. The number
of
* frames is then passed to the write method of the line.
* This is done until the end of the file is reached, which
* is detected by a return value of -1 from the read method
* of the AudioInputStream.
*/
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
while (nBytesRead != -1)
{
try
{
nBytesRead = audioInputStream.read(abData, 0,
abData.length);
}
catch (IOException e)
{
e.printStackTrace();
}
if (nBytesRead >= 0)
{
int nFramesToWrite = nBytesRead /
audioFormat.getFrameSize();
int nFramesWritten = line.write(abData, 0,
nFramesToWrite);
}
}
/*
* Wait until all data are played.
* This is only necessary because of the bug noted below.
* (If we do not wait, we would interrupt the playback by
* prematurely closing the line and exiting the VM.)
*
* Thanks to Margie Fitch for bringing me on the right
* path to this solution.
*/
line.drain();
/*
* All data are played. We can close the shop.
*/
line.close();
/*
* There is a bug in JavaSound 0.90 (jdk1.3beta).
* It prevents correct termination of the VM.
* So we have to exit ourselves.
*/
System.exit(0);
}
}
/*** Player.java ***/
---
(Review ID: 98658)
======================================================================
Name: yyT116575 Date: 11/20/2000
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)
This code should convert the input file and write as an ulaw encoded AU file:
AudioInputStream ais = AudioSystem.getAudioInputStream(new File("pcm.wav"));
ais = AudioSystem.getAudioInputStream(AudioFormat.Encoding.ULAW, ais);
AudioSystem.write(ais, AudioFileFormat.Type.AU, new File("ulaw.au"));
However, an exception is thrown. The problem can be traced to
com.sun.media.sound.AuFileWriter:271 and following lines: when the input format
is not big endian, it is tried to convert it to some PCM format, which doesn't
make any sense, as the input stream is ulaw and with ulaw, endianness doesn't
matter. Constructing an output AudioFormat instance with bigendian=true and
using AudioSystem.getAudioInputStream(AudioFormat, AudioInputStream) doesn't
throw an exception (as no conversion is tried in AuFileWriter), but the
resulting file is not properly transformed to ulaw. This is another bug.
(Review ID: 112555)
======================================================================