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