Edinburgh Speech Tools  2.1-release
gen_audio.cc
Go to the documentation of this file.
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 using namespace std;
55 
56 static int play_sunau_wave(EST_Wave &inwave, EST_Option &al);
57 static int play_socket_wave(EST_Wave &inwave, EST_Option &al);
58 static int play_aucomm_wave(EST_Wave &inwave, EST_Option &al);
59 
60 static int record_sunau_wave(EST_Wave &wave, EST_Option &al);
61 
62 int play_wave(EST_Wave &inwave, EST_Option &al)
63 {
64  EST_String protocol;
65  EST_Wave wtmp;
66  EST_Wave *toplay;
67  char *quality;
68  char *sr;
69 
70  if ((sr = getenv("NA_PLAY_HOST")) != NULL)
71  if (!al.present("-display"))
72  al.add_item("-display", sr);
73 
74  if ((quality = getenv("NA_PLAY_QUALITY")) != NULL)
75  if (!al.present("-quality"))
76  al.add_item("-quality", quality);
77 
78  if (al.present("-p"))
79  protocol = al.val("-p");
80  else if ((sr=getenv("NA_PLAY_PROTOCOL")) != NULL)
81  protocol = sr;
82  else if (protocol == "")
83  {
84  if (nas_supported)
85  protocol = "netaudio"; // the default protocol
86  else if (pulse_supported)
87  protocol = "pulseaudio";
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) == "SUNAUDIO")
120  return play_sunau_wave(*toplay,al);
121  else if (upcase(protocol) == "SUN16AUDIO")
122  return play_sun16_wave(*toplay,al);
123  else if ((upcase(protocol) == "FREEBSD16AUDIO") ||
124  (upcase(protocol) == "LINUX16AUDIO"))
125  return play_linux_wave(*toplay,al);
126  else if (upcase(protocol) == "IRIXAUDIO")
127  return play_irix_wave(*toplay,al);
128  else if (upcase(protocol) == "MACOSXAUDIO")
129  return play_macosx_wave(*toplay,al);
130  else if (upcase(protocol) == "MPLAYERAUDIO")
131  return play_mplayer_wave(*toplay,al);
132  else if (upcase(protocol) == "WIN32AUDIO")
133  return play_win32audio_wave(*toplay,al);
134  else if (upcase(protocol) == "AUDIO_COMMAND")
135  return play_aucomm_wave(*toplay,al);
136  else if (upcase(protocol) == "SOCKET")
137  return play_socket_wave(*toplay,al);
138  else
139  {
140  cerr << "Unknown audio server protocol " << protocol << endl;
141  return -1;
142  }
143 }
144 
145 static int play_socket_wave(EST_Wave &inwave, EST_Option &al)
146 {
147  // Send inwave down the given fd (a socket)
148  SOCKET_FD fd;
149  EST_String otype;
150  EST_String tmpfile = make_tmp_filename();
151 
152  if (al.present("socket_fd"))
153  fd = al.ival("socket_fd");
154  else
155  {
156  cerr << "Socket audio mode: no socket_fd specified" << endl;
157  return -1;
158  }
159 
160  if (al.present("socket_otype"))
161  otype = al.val("socket_otype"); // file type to send to client
162  else
163  otype = "riff";
164 
165  inwave.save(tmpfile,otype);
166 
167  // Because the client may receive many different types of file
168  // I send WV\n to it before the file itself
169  if (send(fd,"WV\n",3,0) != 3) {
170  cerr << "Socket: Error sending 'WV\\n' to the client" << endl;
171  return -1;
172  }
173  socket_send_file(fd,tmpfile);
174  unlink(tmpfile);
175 
176  return 0;
177 }
178 
179 static int play_aucomm_wave(EST_Wave &inwave, EST_Option &al)
180 {
181  // Play wave by specified command
182  EST_String usrcommand, otype, finalcommand;
183  char tmpfile[2048];
184  char pref[2048];
185  int system_result;
186 
187  if (al.present("-command"))
188  usrcommand = al.val("-command");
189  else if (getenv("NA_PLAY_COMMAND") != NULL)
190  usrcommand = getenv("NA_PLAY_COMMAND");
191  else
192  {
193  cerr << "Audio protocol set to COMMAND but no command specified\n";
194  return -1;
195  }
196 
197  sprintf(tmpfile,"/tmp/audiofile_%05ld",(long)getpid());
198 
199  if (al.present("-rate"))
200  inwave.resample(al.ival("-rate"));
201  if (al.present("-otype"))
202  otype = al.val("-otype");
203  else
204  otype = "raw";
205 
206  if (inwave.save(tmpfile,otype) != write_ok)
207  {
208  cerr << "Audio writing file \"" << tmpfile << "\" in type \"" <<
209  otype << " failed " << endl;
210  return -1;
211  }
212 
213  sprintf(pref,"FILE=%s;SR=%d;",tmpfile,inwave.sample_rate());
214 
215  finalcommand = (EST_String)pref+usrcommand.unquote('"');
216  system_result = system(finalcommand);
217  if (system_result != 0)
218  {
219  cerr << "Command \"" << finalcommand << "\" returned error " <<
220  system_result << endl;
221  }
222  unlink(tmpfile); // so we don't fill up /tmp
223 
224  return system_result;
225 }
226 
227 static int play_sunau_wave(EST_Wave &inwave, EST_Option &al)
228 {
229  // Play wave through /dev/audio using 8K ulaw encoding
230  // works for Suns as well as Linux and FreeBSD machines
231  int rcode;
232  const char *audiodevice;
233 
234  inwave.resample(8000);
235 
236  if (al.present("-audiodevice"))
237  audiodevice = al.val("-audiodevice");
238  else
239  audiodevice = "/dev/audio";
240 
241  // Should really do something cute about checking if /dev/audio
242  // is not in use
243  rcode = inwave.save(audiodevice,"ulaw");
244 
245  return rcode;
246 
247 }
248 
250 {
251  // returns list of supported audio types
252  EST_String audios = "";
253 
254  audios += "sunaudio"; // we always support this in spite of the hardware
255 
256  audios += " audio_command";
257  if (nas_supported)
258  audios += " netaudio";
259  if (sun16_supported)
260  audios += " sun16audio";
261  if (pulse_supported)
262  audios += " pulseaudio";
264  audios += " freebsd16audio";
265  if (linux16_supported)
266  audios += " linux16audio";
267  if (irix_supported)
268  audios += " irixaudio";
269  if (mplayer_supported)
270  audios += " mplayeraudio";
271  if (macosx_supported)
272  audios += "macosxaudio";
274  audios += " win32audio";
275  if (os2audio_supported)
276  audios += " os2audio";
277 
278  return audios;
279 }
280 
282 {
283  // Record wave from audio device
284  char *sr;
285  EST_String protocol;
286 
287  // For archaic reasons, if you are using NAS use DISPLAY or
288  // AUDIOSERVER
289  if ((sr = getenv("NA_PLAY_HOST")) != NULL)
290  if (!al.present("-display"))
291  al.add_item("-display", sr);
292 
293  if (al.present("-p"))
294  protocol = al.val("-p");
295  else if ((sr=getenv("NA_PLAY_PROTOCOL")) != NULL)
296  protocol = sr;
297  else if (protocol == "")
298  {
299  if (pulse_supported)
300  protocol = "pulseaudio";
301  else if (sun16_supported)
302  protocol = "sun16audio";
303  else if (freebsd16_supported)
304  protocol = "freebsd16audio";
305  else if (linux16_supported)
306  protocol = "linux16audio";
307  else if (irix_supported)
308  protocol = "irixaudio";
309  else if (win32audio_supported)
310  protocol = "win32audio";
311  else if (mplayer_supported)
312  protocol = "mplayeraudio";
313  else
314  protocol = "sunaudio";
315  }
316 
317  if (upcase(protocol) == "NETAUDIO")
318  return record_nas_wave(wave,al);
319  else if (upcase(protocol) == "PULSEAUDIO")
320  return record_pulse_wave(wave,al);
321  else if (upcase(protocol) == "SUN16AUDIO")
322  return record_sun16_wave(wave,al);
323  else if ((upcase(protocol) == "FREEBSD16AUDIO") ||
324  (upcase(protocol) == "LINUX16AUDIO"))
325  return record_linux_wave(wave,al);
326  else if (upcase(protocol) == "SUNAUDIO")
327  return record_sunau_wave(wave,al);
328  else
329  {
330  cerr << "NA_RECORD: \"" << protocol <<
331  "\" EST current has no record support" << endl;
332  return -1;
333  }
334 }
335 
336 static int record_sunau_wave(EST_Wave &wave, EST_Option &al)
337 {
338  int num_samples,i,r,n;
339  int audio;
340  unsigned char *ulawwave;
341  short *waveform;
342  const int AUDIOBUFFSIZE = 256;
343  const char *audiodevice;
344 
345  if (al.present("-audiodevice"))
346  audiodevice = al.val("-audiodevice");
347  else
348  audiodevice = "/dev/audio";
349 
350  if ((audio = open(audiodevice, O_RDONLY)) == -1)
351  {
352  cerr << "SUN16: can't open " << audiodevice << " for reading" << endl;
353  return -1;
354  }
355 
356  num_samples = (int)(8000*al.fval("-time"));
357  ulawwave = walloc(unsigned char,num_samples);
358 
359  for (r=i=0; i < num_samples; i+= r)
360  {
361  if (num_samples > i+AUDIOBUFFSIZE)
362  n = AUDIOBUFFSIZE;
363  else
364  n = num_samples-i;
365  r = read(audio,&ulawwave[i], n);
366  if (r <= 0)
367  {
368  cerr << "sunaudio: failed to read from audio device" << endl;
369  close(audio);
370  wfree(ulawwave);
371  return -1;
372  }
373  }
374 
375  wave.resize(num_samples);
376  wave.set_sample_rate(8000);
377  waveform = wave.values().memory();
378 
379  ulaw_to_short(ulawwave,waveform,num_samples);
380  wave.resample(al.ival("-sample_rate"));
381 
382  close(audio);
383  wfree(ulawwave);
384  return 0;
385 }
386 
A class for storing digital waveforms. The waveform is stored as an array of 16 bit shorts...
Definition: EST_Wave.h:64
int sun16_supported
Definition: sun16audio.cc:320
int pulse_supported
Definition: pulseaudio.cc:129
void set_sample_rate(const int n)
Set sampling rate to n
Definition: EST_Wave.h:149
#define walloc(TYPE, SIZE)
Definition: EST_walloc.h:52
int play_sun16_wave(EST_Wave &inwave, EST_Option &al)
Definition: sun16audio.cc:322
EST_String unquote(const char quotec) const
Remove quotes and unprotect internal quotes.
Definition: EST_String.cc:1029
int linux16_supported
Definition: linux_sound.cc:882
Utility IO Function header file.
int record_pulse_wave(EST_Wave &inwave, EST_Option &al)
Definition: pulseaudio.cc:139
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:82
int mplayer_supported
Definition: mplayer.cc:98
int record_wave(EST_Wave &wave, EST_Option &al)
Definition: gen_audio.cc:281
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:104
int play_win32audio_wave(EST_Wave &inwave, EST_Option &al)
Definition: win32audio.cc:124
EST_String make_tmp_filename()
Make a unique temporary filename.
Definition: util_io.cc:56
int play_nas_wave(EST_Wave &inwave, EST_Option &al)
Definition: nas.cc:172
char * getenv()
int freebsd16_supported
Definition: linux_sound.cc:881
EST_write_status save(const EST_String filename, const EST_String EST_filetype="")
Definition: EST_Wave.cc:355
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
Definition: linux_sound.cc:891
EST_String upcase(const EST_String &s)
Definition: EST_String.cc:955
int macosx_supported
Definition: macosxaudio.cc:220
int socket_send_file(SOCKET_FD fd, const EST_String &filename)
Definition: filetrans.cc:112
int os2audio_supported
Definition: os2audio.cc:258
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
Definition: linux_sound.cc:884
int irix_supported
Definition: irixaudio.cc:88
int play_macosx_wave(EST_Wave &inwave, EST_Option &al)
Definition: macosxaudio.cc:222
void ulaw_to_short(const unsigned char *ulaw, short *data, int length)
int play_pulse_wave(EST_Wave &inwave, EST_Option &al)
Definition: pulseaudio.cc:131
const EST_SMatrix & values() const
Definition: EST_Wave.h:177
The file was written successfully.
int play_irix_wave(EST_Wave &inwave, EST_Option &al)
Definition: irixaudio.cc:90
NULL
Definition: EST_WFST.cc:55
int play_mplayer_wave(EST_Wave &inwave, EST_Option &al)
Definition: mplayer.cc:100
getString int
Definition: EST_item_aux.cc:50
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
int win32audio_supported
Definition: win32audio.cc:122
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
void wave_combine_channels(EST_Wave &combined, const EST_Wave &multi)
const T * memory() const
Definition: EST_TVector.h:238
int SOCKET_FD
Definition: EST_io_aux.h:104
int record_nas_wave(EST_Wave &inwave, EST_Option &al)
Definition: nas.cc:181
int nas_supported
Definition: nas.cc:170
int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
ssize_t num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
FILE16 *(* open)(const char *, const char *, int, const char *, const char *)
Definition: url.c:107
EST_String options_supported_audio(void)
Definition: gen_audio.cc:249
void resample(int rate)
Resample waveform to rate
Definition: EST_Wave.cc:492
EST_String
void wfree(void *p)
Definition: walloc.c:131
int record_sun16_wave(EST_Wave &inwave, EST_Option &al)
Definition: sun16audio.cc:330
int play_wave(EST_Wave &inwave, EST_Option &al)
Definition: gen_audio.cc:62