Edinburgh Speech Tools  2.4-release
linux_sound.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1997,1998 */
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 : Alan W Black */
34 /* Date : July 1997 */
35 /*-----------------------------------------------------------------------*/
36 /* Optional support for /dev/dsp under FreeBSD and Linux */
37 /* These use the same underlying sound drivers (voxware). This uses */
38 /* 16bit linear if the device supports it otherwise it uses 8bit. The */
39 /* 8bit driver is still better than falling back to the "sunaudio" ulaw */
40 /* 8K as this driver can cope with various sample rates (and saves on */
41 /* resampling). */
42 /* */
43 /* Combined FreeBSD and Voxware code Feb 98 */
44 /* */
45 /* This may work on NetBSD and OpenBSD but I haven't tried it */
46 /* */
47 /*=======================================================================*/
48 
49 #include <cstdio>
50 #include <cstring>
51 #include <cstdlib>
52 #include <cctype>
53 #include <sys/stat.h>
54 #include "EST_cutils.h"
55 #include "EST_walloc.h"
56 #include "EST_Wave.h"
57 #include "EST_wave_aux.h"
58 #include "EST_Option.h"
59 #include "audioP.h"
60 #include "EST_io_aux.h"
61 #include "EST_error.h"
62 
63 #ifdef SUPPORT_FREEBSD16
64 #include <sys/soundcard.h>
65 #include <fcntl.h>
66 int freebsd16_supported = TRUE;
67 int linux16_supported = FALSE;
68 static char *aud_sys_name = "FreeBSD";
69 #endif /*SUPPORT_FREEBSD16 */
70 
71 #ifdef SUPPORT_VOXWARE
72 
73 #include <sys/ioctl.h>
74 #include <sys/soundcard.h>
75 #include <sys/types.h>
76 #include <sys/stat.h>
77 #include <fcntl.h>
78 int linux16_supported = TRUE;
79 int freebsd16_supported = FALSE;
80 static const char *aud_sys_name = "Linux";
81 static int stereo_only = 0;
82 
83 // Code to block signals while sound is playing.
84 // Needed inside Java on (at least some) linux systems
85 // as scheduling interrupts seem to break the writes.
86 
87 #if defined(SUPPORT_LINUX16) || defined(SUPPORT_FREEBSD16)
88 
89 #include <csignal>
90 #include <pthread.h>
91 
92 #define THREAD_DECS() \
93  sigset_t oldmask \
94 
95 #define THREAD_PROTECT() do { \
96  sigset_t newmask; \
97  \
98  sigfillset(&newmask); \
99  \
100  pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
101  } while(0)
102 
103 #define THREAD_UNPROTECT() do { \
104  pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
105  } while (0)
106 
107 #else
108 #define THREAD_DECS() //empty
109 #define THREAD_PROTECT() //empty
110 #define THREAD_UNPROTECT() //empty
111 #endif /* LINUX_16/FREEBSD16 */
112 
113 static int sb_set_sample_rate(int sbdevice, int samp_rate)
114 {
115  int fmt;
116  int sfmts;
117  int stereo=0;
118  int sstereo;
119  int channels=1;
120 
121  ioctl(sbdevice,SNDCTL_DSP_RESET,0);
122  ioctl(sbdevice,SNDCTL_DSP_SPEED,&samp_rate);
123  sstereo = stereo;
124  ioctl(sbdevice,SNDCTL_DSP_STEREO,&sstereo);
125  /* Some devices don't do mono even when you ask them nicely */
126  if (sstereo != stereo)
127  stereo_only = 1;
128  ioctl(sbdevice,SNDCTL_DSP_CHANNELS,&channels);
129  ioctl(sbdevice,SNDCTL_DSP_GETFMTS,&sfmts);
130 
131  if (sfmts == AFMT_U8)
132  fmt = AFMT_U8; // its really an 8 bit only device
133  else if (EST_LITTLE_ENDIAN)
134  fmt = AFMT_S16_LE;
135  else
136  fmt = AFMT_S16_BE;
137 
138  ioctl(sbdevice,SNDCTL_DSP_SETFMT,&fmt);
139 
140  return fmt;
141 }
142 
143 #define AUDIOBUFFSIZE 256
144 // #define AUDIOBUFFSIZE 20480
145 
146 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
147 {
148  int sample_rate;
149  short *waveform;
150  short *waveform2 = 0;
151  int num_samples;
152  int audio,actual_fmt;
153  int i,r,n;
154  const char *audiodevice;
155 
156  if (al.present("-audiodevice"))
157  audiodevice = al.val("-audiodevice");
158  else
159  audiodevice = "/dev/dsp";
160 
161  if ((audio = open(audiodevice,O_WRONLY)) == -1)
162  {
163  cerr << aud_sys_name << ": can't open " << audiodevice << endl;
164  return -1;
165  }
166 
167  // int tmp=open("/tmp/vox_play_wave",O_WRONLY|O_CREAT);
168 
169  waveform = inwave.values().memory();
170  num_samples = inwave.num_samples();
171  sample_rate = inwave.sample_rate();
172 
173  actual_fmt = sb_set_sample_rate(audio,sample_rate);
174 
175  if (stereo_only)
176  {
177  waveform2 = walloc(short,num_samples*2);
178  for (i=0; i<num_samples; i++)
179  {
180  waveform2[i*2] = inwave.a(i);
181  waveform2[(i*2)+1] = inwave.a(i);
182  }
183  waveform = waveform2;
184  num_samples *= 2;
185  }
186 
187  THREAD_DECS();
188  THREAD_PROTECT();
189 
190  if (sb_set_sample_rate(audio,sample_rate) == AFMT_U8)
191  {
192  // Its actually 8bit unsigned so convert the buffer;
193  unsigned char *uchars = walloc(unsigned char,num_samples);
194  for (i=0; i < num_samples; i++)
195  uchars[i] = waveform[i]/256+128;
196  for (i=0; i < num_samples; i += r)
197  {
198  if (num_samples > i+AUDIOBUFFSIZE)
199  n = AUDIOBUFFSIZE;
200  else
201  n = num_samples-i;
202  // r = write(tmp,&uchars[i], n);
203  r = write(audio,&uchars[i], n);
204  if (r == 0)
205  {
206  THREAD_UNPROTECT();
207  cerr << aud_sys_name << ": failed to write to buffer" <<
208  sample_rate << endl;
209  close(audio);
210  return -1;
211  }
212  }
213  wfree(uchars);
214  }
215  else if ((actual_fmt == AFMT_S16_LE) ||
216  (actual_fmt == AFMT_S16_BE))
217  {
218  int blksize, nbuf, c;
219  short *buf;
220 
221  ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &blksize);
222  nbuf=blksize;
223  buf=new short[nbuf];
224 
225  for (i=0; i < num_samples; i += r/2)
226  {
227  if (num_samples > i+nbuf)
228  n = nbuf;
229  else
230  n = num_samples-i;
231 
232  for(c=0; c<n;c++)
233  buf[c]=waveform[c+i];
234 
235  for(; c<nbuf;c++)
236  buf[c]=waveform[n-1];
237 
238  // r = write(tmp,&waveform[i], n*2);
239  // r = write(audio,&waveform[i], n*2);
240  r=write(audio, buf, nbuf*2);
241  if (r <= 0)
242  {
243  THREAD_UNPROTECT();
244  EST_warning("%s: failed to write to buffer (sr=%d)",aud_sys_name, sample_rate );
245  close(audio);
246  return -1;
247  }
248  // ioctl(audio, SNDCTL_DSP_SYNC, 0);
249  // fprintf(stderr,"[%d]", r);
250  }
251  delete [] buf;
252  }
253  else
254  {
255  THREAD_UNPROTECT();
256  cerr << aud_sys_name << ": unable to set sample rate " <<
257  sample_rate << endl;
258  close(audio);
259  return -1;
260  }
261 
262  // ioctl(audio, SNDCTL_DSP_SYNC, 0);
263 // fprintf(stderr, "End Play\n");
264 
265  // close(tmp);
266  close(audio);
267  if (waveform2)
268  wfree(waveform2);
269  THREAD_UNPROTECT();
270  return 1;
271 }
272 
273 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
274 {
275  int sample_rate=16000; // egcs needs the initialized for some reason
276  short *waveform;
277  short *waveform2=0;
278  int num_samples;
279  int audio=-1,actual_fmt;
280  int i,r,n;
281  const char *audiodevice;
282 
283  if (al.present("-audiodevice"))
284  audiodevice = al.val("-audiodevice");
285  else
286  audiodevice = "/dev/dsp";
287 
288  sample_rate = al.ival("-sample_rate");
289 
290  if ((audio = open(audiodevice,O_RDONLY)) == -1)
291  {
292  cerr << aud_sys_name << ": can't open " << audiodevice
293  << "for reading" << endl;
294  return -1;
295  }
296 
297  actual_fmt = sb_set_sample_rate(audio,sample_rate);
298 
299  if ((actual_fmt == AFMT_S16_LE) ||
300  (actual_fmt == AFMT_S16_BE))
301  {
302  // We assume that the device returns audio in native byte order
303  // by default
304  inwave.resize((int)(sample_rate*al.fval("-time")));
305  inwave.set_sample_rate(sample_rate);
306  num_samples = inwave.num_samples();
307  waveform = inwave.values().memory();
308 
309  if (stereo_only)
310  {
311  waveform2 = walloc(short,num_samples*2);
312  num_samples *= 2;
313  }
314  else
315  waveform2 = waveform;
316 
317  for (i=0; i < num_samples; i+= r)
318  {
319  if (num_samples > i+AUDIOBUFFSIZE)
320  n = AUDIOBUFFSIZE;
321  else
322  n = num_samples-i;
323  r = read(audio,&waveform2[i], n*2);
324  r /= 2;
325  if (r <= 0)
326  {
327  cerr << aud_sys_name << ": failed to read from audio device"
328  << endl;
329  close(audio);
330  return -1;
331  }
332  }
333 
334  }
335  else if (actual_fmt == AFMT_U8)
336  {
337  inwave.resize((int)(sample_rate*al.fval("-time")));
338  inwave.set_sample_rate(sample_rate);
339  num_samples = inwave.num_samples();
340  waveform = inwave.values().memory();
341  unsigned char *u8wave = walloc(unsigned char,num_samples);
342 
343  for (i=0; i < num_samples; i+= r)
344  {
345  if (num_samples > i+AUDIOBUFFSIZE)
346  n = AUDIOBUFFSIZE;
347  else
348  n = num_samples-i;
349  r = read(audio,&u8wave[i],n);
350  if (r <= 0)
351  {
352  cerr << aud_sys_name << ": failed to read from audio device"
353  << endl;
354  close(audio);
355  wfree(u8wave);
356  return -1;
357  }
358 
359  }
360  uchar_to_short(u8wave,waveform,num_samples);
361  wfree(u8wave);
362  }
363  else
364  {
365  cerr << aud_sys_name << ": unknown audio format from device: " <<
366  actual_fmt << endl;
367  close(audio);
368  return -1;
369  }
370 
371  if (stereo_only)
372  {
373  for (i=0; i<num_samples; i+=2)
374  waveform[i/2] = waveform2[i];
375  wfree(waveform2);
376  }
377 
378  close(audio);
379  return 0;
380 }
381 
382 #else
383 
384 /*-----------------------------------------------------------------------*/
385 /* Support for alsa, the voxware stuff just doesn't work on most */
386 /* machines now. This code is a modification of the vanilla voxware */
387 /* support */
388 /* */
389 /* Based on the alsa support in Flite provided by Lukas Loehrer */
390 /* */
391 /*=======================================================================*/
392 
393 #ifdef SUPPORT_ALSALINUX
394 #include <sys/ioctl.h>
395 #include <alsa/asoundlib.h>
396 #include <sys/types.h>
397 #include <sys/stat.h>
398 #include <fcntl.h>
399 #define aud_sys_name "ALSALINUX"
400 
401 // Code to block signals while sound is playing.
402 // Needed inside Java on (at least some) linux systems
403 // as scheduling interrupts seem to break the writes.
404 
405 int linux16_supported = TRUE;
406 int freebsd16_supported = FALSE;
407 
408 #ifdef THREAD_SAFETY
409 #include <csignal>
410 #include <pthread.h>
411 
412 #define THREAD_DECS() \
413  sigset_t oldmask \
414 
415 #define THREAD_PROTECT() do { \
416  sigset_t newmask; \
417  \
418  sigfillset(&newmask); \
419  \
420  pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
421  } while(0)
422 
423 #define THREAD_UNPROTECT() do { \
424  pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
425  } while (0)
426 
427 #else
428 #define THREAD_DECS() //empty
429 #define THREAD_PROTECT() //empty
430 #define THREAD_UNPROTECT() //empty
431 #endif /* THREAD_SAFETY */
432 
433 static const char *pcm_dev_name ="default";
434 
435 typedef enum {
436  CST_AUDIO_LINEAR16 = 0,
437  CST_AUDIO_LINEAR8,
438  CST_AUDIO_MULAW
439 } cst_audiofmt;
440 
441 typedef struct cst_audiodev_struct {
442  int sps, real_sps;
443  int channels, real_channels;
444  cst_audiofmt fmt, real_fmt;
445  int byteswap;
446  /* cst_rateconv *rateconv; */
447  void *platform_data;
448 } cst_audiodev;
449 
450 static int audio_bps(cst_audiofmt fmt)
451 {
452  switch (fmt)
453  {
454  case CST_AUDIO_LINEAR16:
455  return 2;
456  case CST_AUDIO_LINEAR8:
457  case CST_AUDIO_MULAW:
458  return 1;
459  }
460  return 0;
461 }
462 
463 static inline void print_pcm_state(snd_pcm_t *handle, char *msg)
464 {
465  fprintf(stderr, "PCM state at %s = %s\n", msg,
466  snd_pcm_state_name(snd_pcm_state(handle)));
467 }
468 
469 cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt)
470 {
471  cst_audiodev *ad;
472  unsigned int real_rate;
473  int err;
474 
475  /* alsa specific stuff */
476  snd_pcm_t *pcm_handle;
477  snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
478  snd_pcm_hw_params_t *hwparams;
479  snd_pcm_format_t format;
480  snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
481 
482  /* Allocate the snd_pcm_hw_params_t structure on the stack. */
483  snd_pcm_hw_params_alloca(&hwparams);
484 
485  /* Open pcm device */
486  err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0);
487  if (err < 0)
488  {
489  EST_warning("audio_open_alsa: failed to open audio device %s. %s\n",
490  pcm_dev_name, snd_strerror(err));
491  return NULL;
492  }
493 
494  /* Init hwparams with full configuration space */
495  err = snd_pcm_hw_params_any(pcm_handle, hwparams);
496  if (err < 0)
497  {
498  snd_pcm_close(pcm_handle);
499  EST_warning("audio_open_alsa: failed to get hardware parameters from audio device. %s\n", snd_strerror(err));
500  return NULL;
501  }
502 
503  /* Set access mode */
504  err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access);
505  if (err < 0)
506  {
507  snd_pcm_close(pcm_handle);
508  EST_warning("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err));
509  return NULL;
510  }
511 
512  /* Determine matching alsa sample format */
513  /* This could be implemented in a more */
514  /* flexible way (byte order conversion). */
515  switch (fmt)
516  {
517  case CST_AUDIO_LINEAR16:
518  if (EST_LITTLE_ENDIAN)
519  format = SND_PCM_FORMAT_S16_LE;
520  else
521  format = SND_PCM_FORMAT_S16_BE;
522  break;
523  case CST_AUDIO_LINEAR8:
524  format = SND_PCM_FORMAT_U8;
525  break;
526  case CST_AUDIO_MULAW:
527  format = SND_PCM_FORMAT_MU_LAW;
528  break;
529  default:
530  snd_pcm_close(pcm_handle);
531  EST_warning("audio_open_alsa: failed to find suitable format.\n");
532  return NULL;
533  break;
534  }
535 
536  /* Set samble format */
537  err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format);
538  if (err <0)
539  {
540  snd_pcm_close(pcm_handle);
541  EST_warning("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err));
542  return NULL;
543  }
544 
545  /* Set sample rate near the disired rate */
546  real_rate = sps;
547  err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0);
548  if (err < 0)
549  {
550  snd_pcm_close(pcm_handle);
551  EST_warning("audio_open_alsa: failed to set sample rate near %d. %s.\n", sps, snd_strerror(err));
552  return NULL;
553  }
554 
555  /* Set number of channels */
556  assert(channels >0);
557  err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels);
558  if (err < 0)
559  {
560  snd_pcm_close(pcm_handle);
561  EST_warning("audio_open_alsa: failed to set number of channels to %d. %s.\n", channels, snd_strerror(err));
562  return NULL;
563  }
564 
565  /* Commit hardware parameters */
566  err = snd_pcm_hw_params(pcm_handle, hwparams);
567  if (err < 0)
568  {
569  snd_pcm_close(pcm_handle);
570  EST_warning("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err));
571  return NULL;
572  }
573 
574  /* There doesn't seem to be another way to set the latency -- if done
575  here, it works, if not, it looses the first 2s or so */
576  snd_pcm_set_params(pcm_handle,
577  format,
578  SND_PCM_ACCESS_RW_INTERLEAVED,
579  1,
580  real_rate,
581  1,
582  50000);
583 
584  /* Make sure the device is ready to accept data */
585  assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
586 
587  /* Write hardware parameters to flite audio device data structure */
588  ad = walloc(cst_audiodev, 1);
589  assert(ad != NULL);
590  ad->real_sps = ad->sps = sps;
591  ad->real_channels = ad->channels = channels;
592  ad->real_fmt = ad->fmt = fmt;
593  ad->platform_data = (void *) pcm_handle;
594 
595  return ad;
596 }
597 
598 int audio_close_alsa(cst_audiodev *ad)
599 {
600  int result;
601  snd_pcm_t *pcm_handle;
602 
603  if (ad == NULL)
604  return 0;
605 
606  pcm_handle = (snd_pcm_t *) ad->platform_data;
607 
608  snd_pcm_drain(pcm_handle); /* wait for current stuff in buffer to finish */
609 
610  result = snd_pcm_close(pcm_handle);
611  if (result < 0)
612  {
613  EST_warning("audio_close_alsa: Error: %s.\n", snd_strerror(result));
614  }
615  wfree(ad);
616  return result;
617 }
618 
619 /* Returns zero if recovery was successful. */
620 static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
621 {
622  if (res == -EPIPE) /* xrun */
623  {
624  res = snd_pcm_prepare(pcm_handle);
625  if (res < 0)
626  {
627  /* Failed to recover from xrun */
628  EST_warning("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
629  return res;
630  }
631  }
632  else if (res == -ESTRPIPE) /* Suspend */
633  {
634  while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN)
635  {
636  snd_pcm_wait(pcm_handle, 1000);
637  }
638  if (res < 0)
639  {
640  res = snd_pcm_prepare(pcm_handle);
641  if (res <0)
642  {
643  /* Resume failed */
644  EST_warning("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
645  return res;
646  }
647  }
648  }
649  else if (res < 0)
650  {
651  /* Unknown failure */
652  EST_warning("audio_recover_from_write_error: %s.\n", snd_strerror(res));
653  return res;
654  }
655  return 0;
656 }
657 
658 int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
659 {
660  size_t frame_size;
661  ssize_t num_frames, res;
662  snd_pcm_t *pcm_handle;
663  char *buf = (char *) samples;
664 
665  /* Determine frame size in bytes */
666  frame_size = audio_bps(ad->real_fmt) * ad->real_channels;
667  /* Require that only complete frames are handed in */
668  assert((num_bytes % frame_size) == 0);
669  num_frames = num_bytes / frame_size;
670  pcm_handle = (snd_pcm_t *) ad->platform_data;
671 
672  while (num_frames > 0)
673  {
674  res = snd_pcm_writei(pcm_handle, buf, num_frames);
675  if (res != num_frames)
676  {
677  if (res == -EAGAIN || (res > 0 && res < num_frames))
678  {
679  snd_pcm_wait(pcm_handle, 100);
680  }
681  else if (recover_from_error(pcm_handle, res) < 0)
682  {
683  return -1;
684  }
685  }
686 
687  if (res >0)
688  {
689  num_frames -= res;
690  buf += res * frame_size;
691  }
692  }
693  return num_bytes;
694 }
695 
696 int audio_flush_alsa(cst_audiodev *ad)
697 {
698  int result;
699  result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
700  if (result < 0)
701  {
702  EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
703  }
704  /* Prepare device for more data */
705  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
706  if (result < 0)
707  {
708  EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
709  }
710  return result;
711 }
712 
713 int audio_drain_alsa(cst_audiodev *ad)
714 {
715  int result;
716  result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
717  if (result < 0)
718  {
719  EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
720  }
721  /* Prepare device for more data */
722  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
723  if (result < 0)
724  {
725  EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
726  }
727  return result;
728 }
729 
730 #define AUDIOBUFFSIZE 256
731 // #define AUDIOBUFFSIZE 20480
732 
733 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
734 {
735  int sample_rate;
736  short *waveform;
737  int num_samples;
738  cst_audiodev *ad;
739 
740 #if 0
741  const char *audiodevice;
742  if (al.present("-audiodevice"))
743  audiodevice = al.val("-audiodevice");
744  else
745  audiodevice = "/dev/dsp";
746 #endif
747 
748  waveform = inwave.values().memory();
749  num_samples = inwave.num_samples();
750  sample_rate = inwave.sample_rate();
751 
752  ad = audio_open_alsa(sample_rate,1,CST_AUDIO_LINEAR16);
753 
754  THREAD_DECS();
755  THREAD_PROTECT();
756 
757  audio_write_alsa(ad,waveform,num_samples*sizeof(short));
758 
759  audio_close_alsa(ad);
760 
761  THREAD_UNPROTECT();
762  return 1;
763 }
764 
765 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
766 {
767 #if 0
768  int sample_rate=16000; // egcs needs the initialized for some reason
769  short *waveform;
770  short *waveform2=0;
771  int num_samples;
772  int audio=-1,actual_fmt;
773  int i,r,n;
774  char *audiodevice;
775 
776  if (al.present("-audiodevice"))
777  audiodevice = al.val("-audiodevice");
778  else
779  audiodevice = "/dev/dsp";
780 
781  sample_rate = al.ival("-sample_rate");
782 
783  if ((audio = open(audiodevice,O_RDONLY)) == -1)
784  {
785  cerr << aud_sys_name << ": can't open " << audiodevice
786  << "for reading" << endl;
787  return -1;
788  }
789 
790  actual_fmt = sb_set_sample_rate(audio,sample_rate);
791 
792  if ((actual_fmt == AFMT_S16_LE) ||
793  (actual_fmt == AFMT_S16_BE))
794  {
795  // We assume that the device returns audio in native byte order
796  // by default
797  inwave.resize((int)(sample_rate*al.fval("-time")));
798  inwave.set_sample_rate(sample_rate);
799  num_samples = inwave.num_samples();
800  waveform = inwave.values().memory();
801 
802  if (stereo_only)
803  {
804  waveform2 = walloc(short,num_samples*2);
805  num_samples *= 2;
806  }
807  else
808  waveform2 = waveform;
809 
810  for (i=0; i < num_samples; i+= r)
811  {
812  if (num_samples > i+AUDIOBUFFSIZE)
813  n = AUDIOBUFFSIZE;
814  else
815  n = num_samples-i;
816  r = read(audio,&waveform2[i], n*2);
817  r /= 2;
818  if (r <= 0)
819  {
820  cerr << aud_sys_name << ": failed to read from audio device"
821  << endl;
822  close(audio);
823  return -1;
824  }
825  }
826 
827  }
828  else if (actual_fmt == AFMT_U8)
829  {
830  inwave.resize((int)(sample_rate*al.fval("-time")));
831  inwave.set_sample_rate(sample_rate);
832  num_samples = inwave.num_samples();
833  waveform = inwave.values().memory();
834  unsigned char *u8wave = walloc(unsigned char,num_samples);
835 
836  for (i=0; i < num_samples; i+= r)
837  {
838  if (num_samples > i+AUDIOBUFFSIZE)
839  n = AUDIOBUFFSIZE;
840  else
841  n = num_samples-i;
842  r = read(audio,&u8wave[i],n);
843  if (r <= 0)
844  {
845  cerr << aud_sys_name << ": failed to read from audio device"
846  << endl;
847  close(audio);
848  wfree(u8wave);
849  return -1;
850  }
851 
852  }
853  uchar_to_short(u8wave,waveform,num_samples);
854  wfree(u8wave);
855  }
856  else
857  {
858  cerr << aud_sys_name << ": unknown audio format from device: " <<
859  actual_fmt << endl;
860  close(audio);
861  return -1;
862  }
863 
864  if (stereo_only)
865  {
866  for (i=0; i<num_samples; i+=2)
867  waveform[i/2] = waveform2[i];
868  wfree(waveform2);
869  }
870 
871  close(audio);
872 #endif /* 0 */
873  return 0;
874 }
875 
876 #else /* ALSALINUX not supported */
877 int freebsd16_supported = FALSE;
878 int linux16_supported = FALSE;
879 
880 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
881 {
882  (void)inwave;
883  (void)al;
884  cerr << "ALSA audio support not compiled." << endl;
885  return -1;
886 }
887 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
888 {
889  (void)inwave;
890  (void)al;
891  cerr << "ALSA audio support not compiled." << endl;
892  return -1;
893 }
894 
895 #endif /* ALSALINUX */
896 #endif /* VOXWARE */
897 
898 
899 #ifdef SUPPORT_PULSEAUDIO
900 #include <pulse/simple.h>
901 
902 int pulse_supported = TRUE;
903 
904 #define AUDIOBUFFSIZE 256
905 // #define AUDIOBUFFSIZE 20480
906 
907 int play_pulse_wave(EST_Wave &inwave, EST_Option &al)
908 {
909  pa_sample_spec *ss;
910  pa_simple *s;
911  short *waveform;
912  int num_samples;
913  int err=0, i, r;
914 
915  ss = walloc(pa_sample_spec,1);
916  ss->rate = inwave.sample_rate();
917  ss->channels = inwave.num_channels();
918 
919  if (EST_BIG_ENDIAN)
920  ss->format = PA_SAMPLE_S16BE;
921  else
922  ss->format = PA_SAMPLE_S16LE;
923 
924  s = pa_simple_new(
925  NULL, /* use default server */
926  "festival",
927  PA_STREAM_PLAYBACK,
928  NULL, /* use default device */
929  "Speech",
930  ss,
931  NULL, /* default channel map */
932  NULL, /* default buffering attributes */
933  &err);
934  if (err < 0)
935  return NULL;
936 
937  waveform = inwave.values().memory();
938  num_samples = inwave.num_samples();
939 
940  for (i=0; i < num_samples; i += AUDIOBUFFSIZE/2)
941  {
942  if (i + AUDIOBUFFSIZE/2 < num_samples)
943  pa_simple_write(s,&waveform[i],(size_t)AUDIOBUFFSIZE,&err);
944  else
945  pa_simple_write(s,&waveform[i],(size_t)(num_samples-i)*2,&err);
946  }
947 
948  pa_simple_drain(s,&err);
949  pa_simple_free(s);
950  wfree(ss);
951 
952  return 1;
953 }
954 
955 int record_pulse_wave(EST_Wave &inwave, EST_Option &al)
956 {
957  return -1;
958 }
959 
960 #else /* not supported */
961 
962 int pulse_supported = FALSE;
963 
964 int play_pulse_wave(EST_Wave &inwave, EST_Option &al)
965 {
966  (void)inwave;
967  (void)al;
968  cerr << "PulseAudio audio support not compiled." << endl;
969  return -1;
970 }
971 int record_pulse_wave(EST_Wave &inwave, EST_Option &al)
972 {
973  (void)inwave;
974  (void)al;
975  cerr << "PulseAudio audio support not compiled." << endl;
976  return -1;
977 }
978 
979 #endif /* PULSEAUDIO */
980 
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_Wave::num_samples
int num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143
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_Wave::a
short & a(int i, int channel=0)
Definition: EST_Wave.cc:128
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::val
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145