/**
* Copyright 2000-2007 DFKI GmbH.
* All Rights Reserved. Use is subject to license terms.
*
* This file is part of MARY TTS.
*
* MARY TTS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package marytts.util.data.audio;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
/**
* This audio player is used by the example code MaryClientUser, but not by MaryClient, which uses a
* com.sun.speech.freetts.audio.AudioPlayer. Maybe change the example code?
*
* @author Marc Schröder
*/
public class AudioPlayer extends Thread {
public static final int MONO = 0;
public static final int STEREO = 3;
public static final int LEFT_ONLY = 1;
public static final int RIGHT_ONLY = 2;
public enum Status {
WAITING, PLAYING
};
private AudioInputStream ais;
private LineListener lineListener;
private SourceDataLine line;
private int outputMode;
private Status status = Status.WAITING;
private boolean exitRequested = false;
/**
* AudioPlayer which can be used if audio stream is to be set separately, using setAudio().
*
*/
public AudioPlayer() {
}
public AudioPlayer(File audioFile) throws IOException, UnsupportedAudioFileException {
this.ais = AudioSystem.getAudioInputStream(audioFile);
}
public AudioPlayer(AudioInputStream ais) {
this.ais = ais;
}
public AudioPlayer(File audioFile, LineListener lineListener) throws IOException, UnsupportedAudioFileException {
this.ais = AudioSystem.getAudioInputStream(audioFile);
this.lineListener = lineListener;
}
public AudioPlayer(AudioInputStream ais, LineListener lineListener) {
this.ais = ais;
this.lineListener = lineListener;
}
public AudioPlayer(File audioFile, SourceDataLine line, LineListener lineListener) throws IOException,
UnsupportedAudioFileException {
this.ais = AudioSystem.getAudioInputStream(audioFile);
this.line = line;
this.lineListener = lineListener;
}
public AudioPlayer(AudioInputStream ais, SourceDataLine line, LineListener lineListener) {
this.ais = ais;
this.line = line;
this.lineListener = lineListener;
}
/**
*
* @param audioFile
* audiofile
* @param line
* line
* @param lineListener
* lineListener
* @param outputMode
* if MONO, force output to be mono; if STEREO, force output to be STEREO; if LEFT_ONLY, play a mono signal over
* the left channel of a stereo output, or mute the right channel of a stereo signal; if RIGHT_ONLY, do the same
* with the right output channel.
* @throws IOException
* IOException
* @throws UnsupportedAudioFileException
* UnsupportedAudioFileException
*/
public AudioPlayer(File audioFile, SourceDataLine line, LineListener lineListener, int outputMode) throws IOException,
UnsupportedAudioFileException {
this.ais = AudioSystem.getAudioInputStream(audioFile);
this.line = line;
this.lineListener = lineListener;
this.outputMode = outputMode;
}
/**
*
* @param ais
* ais
* @param line
* line
* @param lineListener
* lineListener
* @param outputMode
* if MONO, force output to be mono; if STEREO, force output to be STEREO; if LEFT_ONLY, play a mono signal over
* the left channel of a stereo output, or mute the right channel of a stereo signal; if RIGHT_ONLY, do the same
* with the right output channel.
*/
public AudioPlayer(AudioInputStream ais, SourceDataLine line, LineListener lineListener, int outputMode) {
this.ais = ais;
this.line = line;
this.lineListener = lineListener;
this.outputMode = outputMode;
}
public void setAudio(AudioInputStream audio) {
if (status == Status.PLAYING) {
throw new IllegalStateException("Cannot set audio while playing");
}
this.ais = audio;
}
public void cancel() {
if (line != null)
line.stop();
exitRequested = true;
}
public SourceDataLine getLine() {
return line;
}
public void run() {
status = Status.PLAYING;
AudioFormat audioFormat = ais.getFormat();
if (audioFormat.getChannels() == 1) {
if (outputMode != MONO) { // mono -> convert to stereo
ais = new StereoAudioInputStream(ais, outputMode);
audioFormat = ais.getFormat();
}
} else { // 2 channels
assert audioFormat.getChannels() == 2 : "Unexpected number of channels: " + audioFormat.getChannels();
if (outputMode == MONO) {
ais = new MonoAudioInputStream(ais);
} else if (outputMode == LEFT_ONLY) {
ais = new StereoAudioInputStream(ais, outputMode);
} else if (outputMode == RIGHT_ONLY) {
ais = new StereoAudioInputStream(ais, outputMode);
} else {
assert outputMode == STEREO : "Unexpected output mode: " + outputMode;
}
}
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
if (line == null) {
boolean bIsSupportedDirectly = AudioSystem.isLineSupported(info);
if (!bIsSupportedDirectly) {
AudioFormat sourceFormat = audioFormat;
AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(),
sourceFormat.getSampleSizeInBits(), sourceFormat.getChannels(), sourceFormat.getChannels()
* (sourceFormat.getSampleSizeInBits() / 8), sourceFormat.getSampleRate(),
sourceFormat.isBigEndian());
ais = AudioSystem.getAudioInputStream(targetFormat, ais);
audioFormat = ais.getFormat();
}
info = new DataLine.Info(SourceDataLine.class, audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
}
if (lineListener != null)
line.addLineListener(lineListener);
line.open(audioFormat);
} catch (Exception e) {
e.printStackTrace();
return;
}
line.start();
int nRead = 0;
byte[] abData = new byte[65532]; // needs to be a multiple of 4 and 6, to support both 16 and 24 bit stereo
while (nRead != -1 && !exitRequested) {
try {
nRead = ais.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nRead >= 0) {
line.write(abData, 0, nRead);
}
}
if (!exitRequested) {
line.drain();
}
line.close();
}
public static void main(String[] args) throws Exception {
boolean listFilename = false;
if (args[0].equals("-l"))
listFilename = true;
for (int i = (listFilename ? 1 : 0); i < args.length; i++) {
AudioPlayer player = new AudioPlayer(new File(args[i]), null);
if (listFilename)
System.out.println(args[i]);
player.start();
player.join();
}
System.exit(0);
}
}