001/**
002 * Copyright 2001 Sun Microsystems, Inc.
003 * 
004 * See the file "license.terms" for information on usage and
005 * redistribution of this file, and for a DISCLAIMER OF ALL 
006 * WARRANTIES.
007 */
008package com.sun.speech.freetts.audio;
009
010import java.io.ByteArrayInputStream;
011import java.io.File;
012import java.io.IOException;
013
014import javax.sound.sampled.AudioFileFormat;
015import javax.sound.sampled.AudioFormat;
016import javax.sound.sampled.AudioInputStream;
017import javax.sound.sampled.AudioSystem;
018
019import com.sun.speech.freetts.util.Utilities;
020
021/**
022 * Streams audio to multiple files, one per utterance. 
023 *
024 *
025 */
026public class MultiFileAudioPlayer implements AudioPlayer {
027    private AudioFormat currentFormat = null;
028    private int fileCount = 0;
029    private String baseName;
030    private byte[] outputData;
031    private int curIndex = 0;
032    private AudioFileFormat.Type outputType;
033
034    /**
035     * Creates a default audio player for an AudioFileFormat of type
036     * WAVE.  Reads the "com.sun.speech.freetts.AudioPlayer.baseName"
037     * property for the base filename to use, and will produce files
038     * of the form <baseName>1.wav.  The default value for the
039     * base name is "freetts".
040     */
041    public MultiFileAudioPlayer() {
042        this(Utilities.getProperty(
043                 "com.sun.speech.freetts.AudioPlayer.baseName", "freetts"),
044             AudioFileFormat.Type.WAVE);
045    }       
046
047    /**
048     * Constructs a MultiFileAudioPlayer 
049     *
050     * @param baseName the base name of the audio file
051     * @param type the type of audio output
052     *
053     */
054    public MultiFileAudioPlayer(String baseName, AudioFileFormat.Type type) {
055        this.baseName = baseName;
056        this.outputType = type;
057    }
058
059    /**
060     * Sets the audio format for this player
061     *
062     * @param format the audio format
063     *
064     * @throws UnsupportedOperationException if the line cannot be opened with
065     *     the given format
066     */
067    public synchronized void setAudioFormat(AudioFormat format) {
068        currentFormat = format;
069    }
070
071
072    /**
073     * Gets the audio format for this player
074     *
075     * @return format the audio format
076     */
077    public AudioFormat getAudioFormat() {
078        return currentFormat;
079    }
080
081
082    /**
083     * Pauses audio output
084     */
085    public void pause() {
086    }
087
088    /**
089     * Resumes audio output
090     */
091    public synchronized void resume() {
092    }
093        
094    /**
095     * Starts the first sample timer
096     */
097    public void startFirstSampleTimer() {
098    }
099
100
101    /**
102     * Cancels currently playing audio
103     */
104    public synchronized void cancel() {
105    }
106
107    /**
108     * Prepares for another batch of output. Larger groups of output
109     * (such as all output associated with a single FreeTTSSpeakable)
110     * should be grouped between a reset/drain pair.
111     */
112    public synchronized void reset() {
113    }
114
115    /**
116     * Closes this audio player
117     */
118    public synchronized void close() {
119    }
120
121    /**
122     * Returns the current volume.
123     *
124     * @return the current volume (between 0 and 1)
125     */
126    public float getVolume() {
127        return 1.0f;
128    }         
129
130    /**
131     * Sets the current volume.
132     *
133     * @param volume  the current volume (between 0 and 1)
134     */
135    public void setVolume(float volume) {
136    }         
137
138
139
140
141    /**
142     *  Starts the output of a set of data. Audio data for a single
143     *  utterance should be grouped between begin/end pairs.
144     *
145     * @param size the size of data between now and the end
146     */
147    public void begin(int size) {
148        outputData = new byte[size];
149        curIndex = 0;
150    }
151
152    /**
153     * {@inheritDoc}
154     */
155    public boolean  end() throws IOException {
156        ByteArrayInputStream bais = new ByteArrayInputStream(outputData);
157        AudioInputStream ais = new AudioInputStream(bais,
158                currentFormat, outputData.length/currentFormat.getFrameSize());
159        String name = baseName;
160        name = name + fileCount;
161        name = name + "." + outputType.getExtension();
162        File file = new File(name);
163        try {
164            AudioSystem.write(ais, outputType, file);
165            System.out.println("Wrote synthesized speech to " + name);
166        } catch (IllegalArgumentException iae) {
167            throw new IOException("Can't write audio type " + outputType, iae);
168        }
169        fileCount++;
170        return true;
171    }
172
173    /**
174     * Waits for all queued audio to be played
175     *
176     * @return true if the audio played to completion, false if
177     *   the audio was stopped
178     */
179    public boolean drain()  {
180        return true;
181    }
182
183    /**
184     * Gets the amount of played since the last mark
185     *
186     * @return the amount of audio in milliseconds
187     */
188    public synchronized long getTime()  {
189        return -1L;
190    }
191
192
193    /**
194     * Resets the audio clock
195     */
196    public synchronized void resetTime() {
197    }
198    
199
200    
201    /**
202     * Writes the given bytes to the audio stream
203     *
204     * @param audioData audio data to write to the device
205     *
206     * @return <code>true</code> of the write completed successfully, 
207     *          <code> false </code>if the write was cancelled.
208     */
209    public boolean write(byte[] audioData) {
210        return write(audioData, 0, audioData.length);
211    }
212    
213    /**
214     * Writes the given bytes to the audio stream
215     *
216     * @param bytes audio data to write to the device
217     * @param offset the offset into the buffer
218     * @param size the size into the buffer
219     *
220     * @return <code>true</code> of the write completed successfully, 
221     *          <code> false </code>if the write was cancelled.
222     */
223    public boolean write(byte[] bytes, int offset, int size) {
224        System.arraycopy(bytes, offset, outputData, curIndex, size);
225        curIndex += size;
226        return true;
227    }
228
229    /**
230     * Returns the name of this audioplayer
231     *
232     * @return the name of the audio player
233     */
234    public String toString() {
235        return "FileAudioPlayer";
236    }
237
238
239    /**
240     * Shows metrics for this audio player
241     */
242    public void showMetrics() {
243    }
244}