1 package org.wcb.plugins.speech;
2 /***
3 * Copyright (C) 1999 Walter Bogaardt
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 *
19 * Project: Home Automation Interface
20 * Filename: $Id: Talker.java,v 1.2 2004/07/22 03:17:56 wbogaardt Exp $
21 *
22 */
23 import javax.sound.sampled.SourceDataLine;
24 import javax.sound.sampled.AudioSystem;
25 import javax.sound.sampled.DataLine;
26 import javax.sound.sampled.Clip;
27 import javax.sound.sampled.AudioFormat;
28 import javax.sound.sampled.AudioInputStream;
29 import java.util.StringTokenizer;
30 import java.net.URL;
31
32 public class Talker {
33 private SourceDataLine line = null;
34
35 /***
36 * This method speaks a phonetic word specified on the command line.
37 */
38 public static void main(String args[]) {
39 Talker player=new Talker();
40 if (args.length>0) player.sayPhoneWord(args[0]);
41 System.exit(0);
42 }
43 /***
44 * This method speaks the given phonetic word.
45 */
46 public void sayPhoneWord(String word) {
47
48 byte[] previousSound=null;
49
50 StringTokenizer st=new StringTokenizer(word,"|",false);
51 while (st.hasMoreTokens()) {
52
53 String thisPhoneFile=st.nextToken();
54 thisPhoneFile="/allophones/"+thisPhoneFile+".au";
55
56 byte[] thisSound=getSound(thisPhoneFile);
57 if (previousSound!=null) {
58
59 int mergeCount=0;
60 if (previousSound.length>=500 && thisSound.length>=500)
61 mergeCount=500;
62 for (int i=0; i<mergeCount;i++) {
63 previousSound[previousSound.length-mergeCount+i]
64 =(byte)((previousSound[previousSound.length
65 -mergeCount+i]+thisSound[i])/2);
66 }
67
68 playSound(previousSound);
69
70 byte[] newSound=new byte[thisSound.length-mergeCount];
71 for (int ii=0; ii<newSound.length; ii++)
72 newSound[ii]=thisSound[ii+mergeCount];
73 previousSound=newSound;
74 }
75 else
76 previousSound=thisSound;
77 }
78
79 playSound(previousSound);
80 drain();
81 }
82 /***
83 * This method plays a sound sample.
84 */
85 private void playSound(byte[] data) {
86 if (data.length>0) line.write(data, 0, data.length);
87 }
88
89 /***
90 * This method flushes the sound channel.
91 */
92 private void drain() {
93 if (line!=null) line.drain();
94 try {Thread.sleep(100);} catch (Exception e) {}
95 }
96 /***
97 * This method reads the file for a single allophone and
98 * constructs a byte vector.
99 */
100 private byte[] getSound(String fileName) {
101 try {
102 URL url=Talker.class.getResource(fileName);
103 AudioInputStream stream = AudioSystem.getAudioInputStream(url);
104 AudioFormat format = stream.getFormat();
105
106 if ((format.getEncoding() == AudioFormat.Encoding.ULAW) ||
107 (format.getEncoding() == AudioFormat.Encoding.ALAW)) {
108 AudioFormat tmpFormat = new AudioFormat(
109 AudioFormat.Encoding.PCM_SIGNED,
110 format.getSampleRate(),
111 format.getSampleSizeInBits() * 2,
112 format.getChannels(),
113 format.getFrameSize() * 2,
114 format.getFrameRate(),
115 true);
116 stream = AudioSystem.getAudioInputStream(tmpFormat, stream);
117 format = tmpFormat;
118 }
119 DataLine.Info info = new DataLine.Info(
120 Clip.class,
121 format,
122 ((int) stream.getFrameLength() * format.getFrameSize()));
123 if (line==null) {
124
125
126 DataLine.Info outInfo = new DataLine.Info(SourceDataLine.class,
127 format);
128 if (!AudioSystem.isLineSupported(outInfo)) {
129 System.out.println("Line matching " + outInfo + " not supported.");
130 throw new Exception("Line matching " + outInfo + " not supported.");
131 }
132
133 line = (SourceDataLine) AudioSystem.getLine(outInfo);
134 line.open(format, 50000);
135 line.start();
136 }
137
138 int frameSizeInBytes = format.getFrameSize();
139 int bufferLengthInFrames = line.getBufferSize() / 8;
140 int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
141 byte[] data=new byte[bufferLengthInBytes];
142
143 int numBytesRead = 0;
144 if ((numBytesRead = stream.read(data)) != -1) {
145 int numBytesRemaining = numBytesRead;
146 }
147
148 byte[] newData=new byte[numBytesRead];
149 for (int i=0; i<numBytesRead;i++)
150 newData[i]=data[i];
151 return newData;
152 }catch (Exception e) {
153 return new byte[0];
154 }
155 }
156 }