Edinburgh Speech Tools  2.1-release
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 (sun16_supported)
251  audios += " sun16audio";
252  if (pulse_supported)
253  audios += " pulseaudio";
254  if (freebsd16_supported)
255  audios += " freebsd16audio";
256  if (linux16_supported)
257  audios += " linux16audio";
258  if (irix_supported)
259  audios += " irixaudio";
260  if (mplayer_supported)
261  audios += " mplayeraudio";
262  if (macosx_supported)
263  audios += "macosxaudio";
264  if (win32audio_supported)
265  audios += " win32audio";
266  if (os2audio_supported)
267  audios += " os2audio";
268 
269  return audios;
270 }
271 
272 int record_wave(EST_Wave &wave, EST_Option &al)
273 {
274  // Record wave from audio device
275  char *sr;
276  EST_String protocol;
277 
278  // For archaic reasons, if you are using NAS use DISPLAY or
279  // AUDIOSERVER
280  if ((sr = getenv("NA_PLAY_HOST")) != NULL)
281  if (!al.present("-display"))
282  al.add_item("-display", sr);
283 
284  if (al.present("-p"))
285  protocol = al.val("-p");
286  else if ((sr=getenv("NA_PLAY_PROTOCOL")) != NULL)
287  protocol = sr;
288  else if (protocol == "")
289  {
290  if (pulse_supported)
291  protocol = "pulseaudio";
292  else if (sun16_supported)
293  protocol = "sun16audio";
294  else if (freebsd16_supported)
295  protocol = "freebsd16audio";
296  else if (linux16_supported)
297  protocol = "linux16audio";
298  else if (irix_supported)
299  protocol = "irixaudio";
300  else if (win32audio_supported)
301  protocol = "win32audio";
302  else if (esd_supported)
303  protocol = "esdaudio";
304  else if (nas_supported)
305  protocol = "netaudio";
306  else if (mplayer_supported)
307  protocol = "mplayeraudio";
308  else
309  protocol = "sunaudio";
310  }
311 
312  if (upcase(protocol) == "NETAUDIO")
313  return record_nas_wave(wave,al);
314  else if (upcase(protocol) == "PULSEAUDIO")
315  return record_pulse_wave(wave,al);
316  else if (upcase(protocol) == "ESDAUDIO")
317  return record_esd_wave(wave,al);
318  else if (upcase(protocol) == "SUN16AUDIO")
319  return record_sun16_wave(wave,al);
320  else if ((upcase(protocol) == "FREEBSD16AUDIO") ||
321  (upcase(protocol) == "LINUX16AUDIO"))
322  return record_linux_wave(wave,al);
323  else if (upcase(protocol) == "SUNAUDIO")
324  return record_sunau_wave(wave,al);
325  else
326  {
327  cerr << "NA_RECORD: \"" << protocol <<
328  "\" EST current has no record support" << endl;
329  return -1;
330  }
331 }
332 
333 static int record_sunau_wave(EST_Wave &wave, EST_Option &al)
334 {
335  int num_samples,i,r,n;
336  int audio;
337  unsigned char *ulawwave;
338  short *waveform;
339  const int AUDIOBUFFSIZE = 256;
340  const char *audiodevice;
341 
342  if (al.present("-audiodevice"))
343  audiodevice = al.val("-audiodevice");
344  else
345  audiodevice = "/dev/audio";
346 
347  if ((audio = open(audiodevice, O_RDONLY)) == -1)
348  {
349  cerr << "SUN16: can't open " << audiodevice << " for reading" << endl;
350  return -1;
351  }
352 
353  num_samples = (int)(8000*al.fval("-time"));
354  ulawwave = walloc(unsigned char,num_samples);
355 
356  for (r=i=0; i < num_samples; i+= r)
357  {
358  if (num_samples > i+AUDIOBUFFSIZE)
359  n = AUDIOBUFFSIZE;
360  else
361  n = num_samples-i;
362  r = read(audio,&ulawwave[i], n);
363  if (r <= 0)
364  {
365  cerr << "sunaudio: failed to read from audio device" << endl;
366  close(audio);
367  wfree(ulawwave);
368  return -1;
369  }
370  }
371 
372  wave.resize(num_samples);
373  wave.set_sample_rate(8000);
374  waveform = wave.values().memory();
375 
376  ulaw_to_short(ulawwave,waveform,num_samples);
377  wave.resample(al.ival("-sample_rate"));
378 
379  close(audio);
380  wfree(ulawwave);
381  return 0;
382 }
383 
A class for storing digital waveforms. The waveform is stored as an array of 16 bit shorts...
Definition: EST_Wave.h:64
void set_sample_rate(const int n)
Set sampling rate to n
Definition: EST_Wave.h:149
EST_String unquote(const char quotec) const
Remove quotes and unprotect internal quotes.
Definition: EST_String.cc:1027
Utility IO Function header file.
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:76
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:98
EST_String make_tmp_filename()
Make a unique temporary filename.
Definition: util_io.cc:54
EST_write_status save(const EST_String filename, const EST_String EST_filetype="")
Definition: EST_Wave.cc:350
int num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
const int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition: EST_TKVL.cc:248
void resize(int num_samples, int num_channels=EST_ALL, int set=1)
resize the waveform
Definition: EST_Wave.h:184
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
const T * memory() const
Definition: EST_TVector.h:239
void resample(int rate)
Resample waveform to rate
Definition: EST_Wave.cc:487