Edinburgh Speech Tools  2.4-release
gen_audio.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Paul Taylor */
34 /* Date : March 95 */
35 /*-----------------------------------------------------------------------*/
36 /* Generalised playback function */
37 /* */
38 /*=======================================================================*/
39 
40 #include <cstdlib>
41 #include <iostream>
42 #include <cstring>
43 #include <cmath>
44 #include <fcntl.h>
45 #include "EST_system.h"
46 #include "EST_socket.h"
47 #include "EST_Option.h"
48 #include "EST_Wave.h"
49 #include "EST_io_aux.h"
50 #include "audioP.h"
51 #include "EST_audio.h"
52 #include "EST_wave_aux.h"
53 
54 static int play_sunau_wave(EST_Wave &inwave, EST_Option &al);
55 static int play_socket_wave(EST_Wave &inwave, EST_Option &al);
56 static int play_aucomm_wave(EST_Wave &inwave, EST_Option &al);
57 
58 static int record_sunau_wave(EST_Wave &wave, EST_Option &al);
59 
60 int play_wave(EST_Wave &inwave, EST_Option &al)
61 {
62  EST_String protocol;
63  EST_Wave wtmp;
64  EST_Wave *toplay;
65  char *quality;
66  char *sr;
67 
68  if ((sr = getenv("NA_PLAY_HOST")) != NULL)
69  if (!al.present("-display"))
70  al.add_item("-display", sr);
71 
72  if ((quality = getenv("NA_PLAY_QUALITY")) != NULL)
73  if (!al.present("-quality"))
74  al.add_item("-quality", quality);
75 
76  if (al.present("-p"))
77  protocol = al.val("-p");
78  else if ((sr=getenv("NA_PLAY_PROTOCOL")) != NULL)
79  protocol = sr;
80  else if (protocol == "")
81  {
82  if (nas_supported)
83  protocol = "netaudio"; // the default protocol
84  else if (pulse_supported)
85  protocol = "pulseaudio";
86  else if (esd_supported)
87  protocol = "esdaudio";
88  else if (sun16_supported)
89  protocol = "sun16audio";
90  else if (freebsd16_supported)
91  protocol = "freebsd16audio";
92  else if (linux16_supported)
93  protocol = "linux16audio";
94  else if (irix_supported)
95  protocol = "irixaudio";
96  else if (macosx_supported)
97  protocol = "macosxaudio";
98  else if (win32audio_supported)
99  protocol = "win32audio";
100  else if (mplayer_supported)
101  protocol = "mplayeraudio";
102  else
103  protocol = "sunaudio";
104  }
105 
106  // OS X can handle multichannel audio, don't know about other systems.
107  if (inwave.num_channels() > 1 && upcase(protocol) != "MACOSXAUDIO" )
108  {
109  wave_combine_channels(wtmp,inwave);
110  toplay = &wtmp;
111  }
112  else
113  toplay = &inwave;
114 
115  if (upcase(protocol) == "NETAUDIO")
116  return play_nas_wave(*toplay,al);
117  else if (upcase(protocol) == "PULSEAUDIO")
118  return play_pulse_wave(*toplay,al);
119  else if (upcase(protocol) == "ESDAUDIO")
120  return play_esd_wave(*toplay,al);
121  else if (upcase(protocol) == "SUNAUDIO")
122  return play_sunau_wave(*toplay,al);
123  else if (upcase(protocol) == "SUN16AUDIO")
124  return play_sun16_wave(*toplay,al);
125  else if ((upcase(protocol) == "FREEBSD16AUDIO") ||
126  (upcase(protocol) == "LINUX16AUDIO"))
127  return play_linux_wave(*toplay,al);
128  else if (upcase(protocol) == "IRIXAUDIO")
129  return play_irix_wave(*toplay,al);
130  else if (upcase(protocol) == "MACOSXAUDIO")
131  return play_macosx_wave(*toplay,al);
132  else if (upcase(protocol) == "MPLAYERAUDIO")
133  return play_mplayer_wave(*toplay,al);
134  else if (upcase(protocol) == "WIN32AUDIO")
135  return play_win32audio_wave(*toplay,al);
136  else if (upcase(protocol) == "AUDIO_COMMAND")
137  return play_aucomm_wave(*toplay,al);
138  else if (upcase(protocol) == "SOCKET")
139  return play_socket_wave(*toplay,al);
140  else
141  {
142  cerr << "Unknown audio server protocol " << protocol << endl;
143  return -1;
144  }
145 }
146 
147 static int play_socket_wave(EST_Wave &inwave, EST_Option &al)
148 {
149  // Send inwave down the given fd (a socket)
150  SOCKET_FD fd;
151  EST_String otype;
152  EST_String tmpfile = make_tmp_filename();
153 
154  if (al.present("socket_fd"))
155  fd = al.ival("socket_fd");
156  else
157  {
158  cerr << "Socket audio mode: no socket_fd specified" << endl;
159  return -1;
160  }
161 
162  if (al.present("socket_otype"))
163  otype = al.val("socket_otype"); // file type to send to client
164  else
165  otype = "riff";
166 
167  inwave.save(tmpfile,otype);
168 
169  // Because the client may receive many different types of file
170  // I send WV\n to it before the file itself
171  send(fd,"WV\n",3,0);
172  socket_send_file(fd,tmpfile);
173  unlink(tmpfile);
174 
175  return 0;
176 }
177 
178 static int play_aucomm_wave(EST_Wave &inwave, EST_Option &al)
179 {
180  // Play wave by specified command
181  EST_String usrcommand, otype;
182  char tmpfile[2048];
183  char pref[2048];
184 
185  if (al.present("-command"))
186  usrcommand = al.val("-command");
187  else if (getenv("NA_PLAY_COMMAND") != NULL)
188  usrcommand = getenv("NA_PLAY_COMMAND");
189  else
190  {
191  cerr << "Audio protocol set to COMMAND but no command specified\n";
192  return -1;
193  }
194 
195  sprintf(tmpfile,"/tmp/audiofile_%05ld",(long)getpid());
196 
197  if (al.present("-rate"))
198  inwave.resample(al.ival("-rate"));
199  if (al.present("-otype"))
200  otype = al.val("-otype");
201  else
202  otype = "raw";
203 
204  if (inwave.save(tmpfile,otype) != write_ok)
205  {
206  cerr << "Audio writing file \"" << tmpfile << "\" in type \"" <<
207  otype << " failed " << endl;
208  return -1;
209  }
210 
211  sprintf(pref,"FILE=%s;SR=%d;",tmpfile,inwave.sample_rate());
212 
213  system((EST_String)pref+usrcommand.unquote('"'));
214 
215  unlink(tmpfile); // so we don't fill up /tmp
216 
217  return 0;
218 }
219 
220 static int play_sunau_wave(EST_Wave &inwave, EST_Option &al)
221 {
222  // Play wave through /dev/audio using 8K ulaw encoding
223  // works for Suns as well as Linux and FreeBSD machines
224  int rcode;
225  const char *audiodevice;
226 
227  inwave.resample(8000);
228 
229  if (al.present("-audiodevice"))
230  audiodevice = al.val("-audiodevice");
231  else
232  audiodevice = "/dev/audio";
233 
234  // Should really do something cute about checking if /dev/audio
235  // is not in use
236  rcode = inwave.save(audiodevice,"ulaw");
237 
238  return rcode;
239 
240 }
241 
242 EST_String options_supported_audio(void)
243 {
244  // returns list of supported audio types
245  EST_String audios = "";
246 
247  audios += "sunaudio"; // we always support this in spite of the hardware
248 
249  audios += " audio_command";
250  if (nas_supported)
251  audios += " netaudio";
252  else if (esd_supported)
253  audios += " esdaudio";
254  if (sun16_supported)
255  audios += " sun16audio";
256  if (pulse_supported)
257  audios += " pulseaudio";
258  if (freebsd16_supported)
259  audios += " freebsd16audio";
260  if (linux16_supported)
261  audios += " linux16audio";
262  if (irix_supported)
263  audios += " irixaudio";
264  if (mplayer_supported)
265  audios += " mplayeraudio";
266  if (macosx_supported)
267  audios += "macosxaudio";
268  if (win32audio_supported)
269  audios += " win32audio";
270  if (os2audio_supported)
271  audios += " os2audio";
272 
273  return audios;
274 }
275 
276 int record_wave(EST_Wave &wave, EST_Option &al)
277 {
278  // Record wave from audio device
279  char *sr;
280  EST_String protocol;
281 
282  // For archaic reasons, if you are using NAS use DISPLAY or
283  // AUDIOSERVER
284  if ((sr = getenv("NA_PLAY_HOST")) != NULL)
285  if (!al.present("-display"))
286  al.add_item("-display", sr);
287 
288  if (al.present("-p"))
289  protocol = al.val("-p");
290  else if ((sr=getenv("NA_PLAY_PROTOCOL")) != NULL)
291  protocol = sr;
292  else if (protocol == "")
293  {
294  if (pulse_supported)
295  protocol = "pulseaudio";
296  else if (nas_supported)
297  protocol = "netaudio"; // the default protocol
298  else if (esd_supported)
299  protocol = "esdaudio"; // the default protocol
300  else if (sun16_supported)
301  protocol = "sun16audio";
302  else if (freebsd16_supported)
303  protocol = "freebsd16audio";
304  else if (linux16_supported)
305  protocol = "linux16audio";
306  else if (irix_supported)
307  protocol = "irixaudio";
308  else if (win32audio_supported)
309  protocol = "win32audio";
310  else if (mplayer_supported)
311  protocol = "mplayeraudio";
312  else
313  protocol = "sunaudio";
314  }
315 
316  if (upcase(protocol) == "NETAUDIO")
317  return record_nas_wave(wave,al);
318  else if (upcase(protocol) == "PULSEAUDIO")
319  return record_pulse_wave(wave,al);
320  else if (upcase(protocol) == "ESDAUDIO")
321  return record_esd_wave(wave,al);
322  else if (upcase(protocol) == "SUN16AUDIO")
323  return record_sun16_wave(wave,al);
324  else if ((upcase(protocol) == "FREEBSD16AUDIO") ||
325  (upcase(protocol) == "LINUX16AUDIO"))
326  return record_linux_wave(wave,al);
327  else if (upcase(protocol) == "SUNAUDIO")
328  return record_sunau_wave(wave,al);
329  else
330  {
331  cerr << "NA_RECORD: \"" << protocol <<
332  "\" EST current has no record support" << endl;
333  return -1;
334  }
335 }
336 
337 static int record_sunau_wave(EST_Wave &wave, EST_Option &al)
338 {
339  int num_samples,i,r,n;
340  int audio;
341  unsigned char *ulawwave;
342  short *waveform;
343  const int AUDIOBUFFSIZE = 256;
344  const char *audiodevice;
345 
346  if (al.present("-audiodevice"))
347  audiodevice = al.val("-audiodevice");
348  else
349  audiodevice = "/dev/audio";
350 
351  if ((audio = open(audiodevice, O_RDONLY)) == -1)
352  {
353  cerr << "SUN16: can't open " << audiodevice << " for reading" << endl;
354  return -1;
355  }
356 
357  num_samples = (int)(8000*al.fval("-time"));
358  ulawwave = walloc(unsigned char,num_samples);
359 
360  for (r=i=0; i < num_samples; i+= r)
361  {
362  if (num_samples > i+AUDIOBUFFSIZE)
363  n = AUDIOBUFFSIZE;
364  else
365  n = num_samples-i;
366  r = read(audio,&ulawwave[i], n);
367  if (r <= 0)
368  {
369  cerr << "sunaudio: failed to read from audio device" << endl;
370  close(audio);
371  wfree(ulawwave);
372  return -1;
373  }
374  }
375 
376  wave.resize(num_samples);
377  wave.set_sample_rate(8000);
378  waveform = wave.values().memory();
379 
380  ulaw_to_short(ulawwave,waveform,num_samples);
381  wave.resample(al.ival("-sample_rate"));
382 
383  close(audio);
384  wfree(ulawwave);
385  return 0;
386 }
387 
EST_Option
Definition: EST_Option.h:50
EST_Wave::sample_rate
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
EST_Wave
Definition: EST_Wave.h:64
EST_Wave::num_channels
int num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
EST_Wave::resize
void resize(int num_samples, int num_channels=EST_ALL, int set=1)
resize the waveform
Definition: EST_Wave.h:184
EST_TKVL::present
const int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
EST_Option::fval
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:98
EST_String::unquote
EST_String unquote(const char quotec) const
Remove quotes and unprotect internal quotes.
Definition: EST_String.cc:1041
EST_String
Definition: EST_String.h:70
EST_Wave::set_sample_rate
void set_sample_rate(const int n)
Set sampling rate to n
Definition: EST_Wave.h:149
EST_TVector::memory
const T * memory() const
Definition: EST_TVector.h:241
EST_Option::ival
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:76
EST_TKVL::add_item
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition: EST_TKVL.cc:248
EST_Wave::resample
void resample(int rate)
Resample waveform to rate
Definition: EST_Wave.cc:489
EST_TKVL::val
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145