2 * Copyright 2001 Sun Microsystems, Inc.
4 * See the file "license.terms" for information on usage and
5 * redistribution of this file, and for a DISCLAIMER OF ALL
8 package com.sun.speech.freetts.audio;
10 import java.io.ByteArrayInputStream;
12 import java.io.IOException;
14 import javax.sound.sampled.AudioFileFormat;
15 import javax.sound.sampled.AudioFormat;
16 import javax.sound.sampled.AudioInputStream;
17 import javax.sound.sampled.AudioSystem;
19 import com.sun.speech.freetts.util.Utilities;
22 * Streams audio to multiple files as 8-bit samples, one per utterance.
23 * Currently, FreeTTS always outputs 16-bit samples, and this
24 * MultiFile8BitAudioPlayer will convert them to 8-bit before outputting
27 public class MultiFile8BitAudioPlayer implements AudioPlayer {
28 // 8-bit unsigned little-endian mono audio
29 private AudioFormat currentFormat = new AudioFormat
30 (8000, 8, 1, false, false);
32 private int fileCount = 0;
33 private String baseName;
34 private byte[] outputData;
35 private int curIndex = 0;
36 private AudioFileFormat.Type outputType;
40 * Creates a default audio player for an AudioFileFormat of type
41 * WAVE. Reads the "com.sun.speech.freetts.AudioPlayer.baseName"
42 * property for the base filename to use, and will produce files
43 * of the form <baseName>1.wav. The default value for the
44 * base name is "freetts".
46 public MultiFile8BitAudioPlayer() {
47 this(Utilities.getProperty(
48 "com.sun.speech.freetts.AudioPlayer.baseName", "freetts"),
49 AudioFileFormat.Type.WAVE);
53 * Constructs a MultiFile8BitAudioPlayer
55 * @param baseName the base name of the audio file
56 * @param type the type of audio output
59 public MultiFile8BitAudioPlayer(String baseName,
60 AudioFileFormat.Type type) {
61 this.baseName = baseName;
62 this.outputType = type;
67 * Sets the audio format for this player
69 * @param format the audio format
71 * @throws UnsupportedOperationException if the line cannot be opened with
74 public synchronized void setAudioFormat(AudioFormat format) {
79 * Gets the audio format for this player
81 * @return format the audio format
83 public AudioFormat getAudioFormat() {
95 * Resumes audio output
97 public synchronized void resume() {
101 * Starts the first sample timer
103 public void startFirstSampleTimer() {
108 * Cancels currently playing audio
110 public synchronized void cancel() {
114 * Prepares for another batch of output. Larger groups of output
115 * (such as all output associated with a single FreeTTSSpeakable)
116 * should be grouped between a reset/drain pair.
118 public synchronized void reset() {
122 * Closes this audio player
124 public synchronized void close() {
128 * Returns the current volume.
130 * @return the current volume (between 0 and 1)
132 public float getVolume() {
137 * Sets the current volume.
139 * @param volume the current volume (between 0 and 1)
141 public void setVolume(float volume) {
146 * Starts the output of a set of data. Audio data for a single
147 * utterance should be grouped between begin/end pairs.
149 * @param size the size of data between now and the end
151 public void begin(int size) {
152 outputData = new byte[size/2];
157 * Marks the end of a set of data. Audio data for a single
158 * utterance should be groupd between begin/end pairs.
160 * @return true if the audio was output properly, false if the
161 * output was cancelled or interrupted.
164 public boolean end() {
165 ByteArrayInputStream bais = new ByteArrayInputStream(outputData);
166 AudioInputStream ais = new AudioInputStream
167 (bais, currentFormat,
168 outputData.length/currentFormat.getFrameSize());
169 String name = baseName;
170 name = name + fileCount;
171 name = name + "." + outputType.getExtension();
172 File file = new File(name);
174 AudioSystem.write(ais, outputType, file);
175 System.out.println("Wrote synthesized speech to " + name);
176 } catch (IOException ioe) {
177 System.err.println("Can't write audio to " + file);
179 } catch (IllegalArgumentException iae) {
180 System.err.println("Can't write audio type " + outputType);
189 * Waits for all queued audio to be played
191 * @return true if the audio played to completion, false if
192 * the audio was stopped
194 public boolean drain() {
199 * Gets the amount of played since the last mark
201 * @return the amount of audio in milliseconds
203 public synchronized long getTime() {
209 * Resets the audio clock
211 public synchronized void resetTime() {
217 * Writes the given bytes to the audio stream
219 * @param audioData audio data to write to the device
221 * @return <code>true</code> of the write completed successfully,
222 * <code> false </code>if the write was cancelled.
224 public boolean write(byte[] audioData) {
225 return write(audioData, 0, audioData.length);
230 * Writes the given bytes to the audio stream
232 * @param bytes audio data to write to the device
233 * @param offset the offset into the buffer
234 * @param size the size into the buffer
236 * @return <code>true</code> of the write completed successfully,
237 * <code> false </code>if the write was cancelled.
239 public boolean write(byte[] bytes, int offset, int size) {
240 bytes = convert16To8Bits(bytes);
242 System.arraycopy(bytes, offset, outputData, curIndex, size);
249 * Converts an array of signed 16-bit audio data to unsigned 8-bit
252 * @param samples16Bit the signed 16-bit audio data to convert
254 * @return unsigned 8-bit audio data
256 private static byte[] convert16To8Bits(byte[] samples16Bit) {
257 byte[] samples8Bit = new byte[samples16Bit.length/2];
258 for (int i = 0, j = 0; i < samples16Bit.length; i += 2, j++) {
259 int sample = (0x000000FF & samples16Bit[i]);
260 samples8Bit[j] = (byte) (sample + 128);
267 * Returns the name of this audioplayer
269 * @return the name of the audio player
271 public String toString() {
272 return "MultiFile8BitAudioPlayer";
276 * Shows metrics for this audio player
278 public void showMetrics() {