Edinburgh Speech Tools  2.1-release
linux_sound.cc
Go to the documentation of this file.
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 <iostream>
54 #include <sys/stat.h>
55 #include "EST_cutils.h"
56 #include "EST_walloc.h"
57 #include "EST_Wave.h"
58 #include "EST_wave_aux.h"
59 #include "EST_Option.h"
60 #include "audioP.h"
61 #include "EST_io_aux.h"
62 #include "EST_error.h"
63 
64 using namespace std;
65 
66 #ifdef SUPPORT_FREEBSD16
67 #include <sys/soundcard.h>
68 #include <fcntl.h>
71 static char *aud_sys_name = "FreeBSD";
72 #endif /*SUPPORT_FREEBSD16 */
73 
74 #ifdef SUPPORT_VOXWARE
75 
76 #include <sys/ioctl.h>
77 #include <sys/soundcard.h>
78 #include <sys/types.h>
79 #include <sys/stat.h>
80 #include <fcntl.h>
83 static const char *aud_sys_name = "Linux";
84 static int stereo_only = 0;
85 
86 // Code to block signals while sound is playing.
87 // Needed inside Java on (at least some) linux systems
88 // as scheduling interrupts seem to break the writes.
89 
90 #if defined(SUPPORT_LINUX16) || defined(SUPPORT_FREEBSD16)
91 
92 #include <csignal>
93 #include <pthread.h>
94 
95 #define THREAD_DECS() \
96  sigset_t oldmask \
97 
98 #define THREAD_PROTECT() do { \
99  sigset_t newmask; \
100  \
101  sigfillset(&newmask); \
102  \
103  pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
104  } while(0)
105 
106 #define THREAD_UNPROTECT() do { \
107  pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
108  } while (0)
109 
110 #else
111 #define THREAD_DECS() //empty
112 #define THREAD_PROTECT() //empty
113 #define THREAD_UNPROTECT() //empty
114 #endif /* LINUX_16/FREEBSD16 */
115 
116 static int sb_set_sample_rate(int sbdevice, int samp_rate)
117 {
118  int fmt;
119  int sfmts;
120  int stereo=0;
121  int sstereo;
122  int channels=1;
123 
124  ioctl(sbdevice,SNDCTL_DSP_RESET,0);
125  ioctl(sbdevice,SNDCTL_DSP_SPEED,&samp_rate);
126  sstereo = stereo;
127  ioctl(sbdevice,SNDCTL_DSP_STEREO,&sstereo);
128  /* Some devices don't do mono even when you ask them nicely */
129  if (sstereo != stereo)
130  stereo_only = 1;
131  ioctl(sbdevice,SNDCTL_DSP_CHANNELS,&channels);
132  ioctl(sbdevice,SNDCTL_DSP_GETFMTS,&sfmts);
133 
134  if (sfmts == AFMT_U8)
135  fmt = AFMT_U8; // its really an 8 bit only device
136  else if (EST_LITTLE_ENDIAN)
137  fmt = AFMT_S16_LE;
138  else
139  fmt = AFMT_S16_BE;
140 
141  ioctl(sbdevice,SNDCTL_DSP_SETFMT,&fmt);
142 
143  return fmt;
144 }
145 
146 #define AUDIOBUFFSIZE 256
147 // #define AUDIOBUFFSIZE 20480
148 
149 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
150 {
151  int sample_rate;
152  short *waveform;
153  short *waveform2 = 0;
154  int num_samples;
155  int audio,actual_fmt;
156  int i,r,n;
157  const char *audiodevice;
158 
159  if (al.present("-audiodevice"))
160  audiodevice = al.val("-audiodevice");
161  else
162  audiodevice = "/dev/dsp";
163 
164  if ((audio = open(audiodevice,O_WRONLY)) == -1)
165  {
166  cerr << aud_sys_name << ": can't open " << audiodevice << endl;
167  return -1;
168  }
169 
170  // int tmp=open("/tmp/vox_play_wave",O_WRONLY|O_CREAT);
171 
172  waveform = inwave.values().memory();
173  num_samples = inwave.num_samples();
174  sample_rate = inwave.sample_rate();
175 
176  actual_fmt = sb_set_sample_rate(audio,sample_rate);
177 
178  if (stereo_only)
179  {
180  waveform2 = walloc(short,num_samples*2);
181  for (i=0; i<num_samples; i++)
182  {
183  waveform2[i*2] = inwave.a(i);
184  waveform2[(i*2)+1] = inwave.a(i);
185  }
186  waveform = waveform2;
187  num_samples *= 2;
188  }
189 
190  THREAD_DECS();
191  THREAD_PROTECT();
192 
193  if (sb_set_sample_rate(audio,sample_rate) == AFMT_U8)
194  {
195  // Its actually 8bit unsigned so convert the buffer;
196  unsigned char *uchars = walloc(unsigned char,num_samples);
197  for (i=0; i < num_samples; i++)
198  uchars[i] = waveform[i]/256+128;
199  for (i=0; i < num_samples; i += r)
200  {
201  if (num_samples > i+AUDIOBUFFSIZE)
202  n = AUDIOBUFFSIZE;
203  else
204  n = num_samples-i;
205  // r = write(tmp,&uchars[i], n);
206  r = write(audio,&uchars[i], n);
207  if (r == 0)
208  {
209  THREAD_UNPROTECT();
210  cerr << aud_sys_name << ": failed to write to buffer" <<
211  sample_rate << endl;
212  close(audio);
213  return -1;
214  }
215  }
216  wfree(uchars);
217  }
218  else if ((actual_fmt == AFMT_S16_LE) ||
219  (actual_fmt == AFMT_S16_BE))
220  {
221  int blksize, nbuf, c;
222  short *buf;
223 
224  ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &blksize);
225  nbuf=blksize;
226  buf=new short[nbuf];
227 
228  for (i=0; i < num_samples; i += r/2)
229  {
230  if (num_samples > i+nbuf)
231  n = nbuf;
232  else
233  n = num_samples-i;
234 
235  for(c=0; c<n;c++)
236  buf[c]=waveform[c+i];
237 
238  for(; c<nbuf;c++)
239  buf[c]=waveform[n-1];
240 
241  // r = write(tmp,&waveform[i], n*2);
242  // r = write(audio,&waveform[i], n*2);
243  r=write(audio, buf, nbuf*2);
244  if (r <= 0)
245  {
246  THREAD_UNPROTECT();
247  EST_warning("%s: failed to write to buffer (sr=%d)",aud_sys_name, sample_rate );
248  close(audio);
249  delete[] buf;
250  return -1;
251  }
252  // ioctl(audio, SNDCTL_DSP_SYNC, 0);
253  // fprintf(stderr,"[%d]", r);
254  }
255  delete [] buf;
256  }
257  else
258  {
259  THREAD_UNPROTECT();
260  cerr << aud_sys_name << ": unable to set sample rate " <<
261  sample_rate << endl;
262  close(audio);
263  if (waveform2 != waveform)
264  wfree(waveform2);
265  wfree(waveform);
266  return -1;
267  }
268 
269  // ioctl(audio, SNDCTL_DSP_SYNC, 0);
270 // fprintf(stderr, "End Play\n");
271 
272  // close(tmp);
273  close(audio);
274  if (waveform2)
275  wfree(waveform2);
276  THREAD_UNPROTECT();
277  return 1;
278 }
279 
280 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
281 {
282  int sample_rate=16000; // egcs needs the initialized for some reason
283  short *waveform;
284  short *waveform2=0;
285  int num_samples;
286  int audio=-1,actual_fmt;
287  int i,r,n;
288  const char *audiodevice;
289 
290  if (al.present("-audiodevice"))
291  audiodevice = al.val("-audiodevice");
292  else
293  audiodevice = "/dev/dsp";
294 
295  sample_rate = al.ival("-sample_rate");
296 
297  if ((audio = open(audiodevice,O_RDONLY)) == -1)
298  {
299  cerr << aud_sys_name << ": can't open " << audiodevice
300  << "for reading" << endl;
301  return -1;
302  }
303 
304  actual_fmt = sb_set_sample_rate(audio,sample_rate);
305 
306  if ((actual_fmt == AFMT_S16_LE) ||
307  (actual_fmt == AFMT_S16_BE))
308  {
309  // We assume that the device returns audio in native byte order
310  // by default
311  inwave.resize((int)(sample_rate*al.fval("-time")));
312  inwave.set_sample_rate(sample_rate);
313  num_samples = inwave.num_samples();
314  waveform = inwave.values().memory();
315 
316  if (stereo_only)
317  {
318  waveform2 = walloc(short,num_samples*2);
319  num_samples *= 2;
320  }
321  else
322  waveform2 = waveform;
323 
324  for (i=0; i < num_samples; i+= r)
325  {
326  if (num_samples > i+AUDIOBUFFSIZE)
327  n = AUDIOBUFFSIZE;
328  else
329  n = num_samples-i;
330  r = read(audio,&waveform2[i], n*2);
331  r /= 2;
332  if (r <= 0)
333  {
334  cerr << aud_sys_name << ": failed to read from audio device"
335  << endl;
336  close(audio);
337  wfree(waveform2);
338  return -1;
339  }
340  }
341 
342  }
343  else if (actual_fmt == AFMT_U8)
344  {
345  inwave.resize((int)(sample_rate*al.fval("-time")));
346  inwave.set_sample_rate(sample_rate);
347  num_samples = inwave.num_samples();
348  waveform = inwave.values().memory();
349  unsigned char *u8wave = walloc(unsigned char,num_samples);
350 
351  for (i=0; i < num_samples; i+= r)
352  {
353  if (num_samples > i+AUDIOBUFFSIZE)
354  n = AUDIOBUFFSIZE;
355  else
356  n = num_samples-i;
357  r = read(audio,&u8wave[i],n);
358  if (r <= 0)
359  {
360  cerr << aud_sys_name << ": failed to read from audio device"
361  << endl;
362  close(audio);
363  wfree(u8wave);
364  return -1;
365  }
366 
367  }
368  uchar_to_short(u8wave,waveform,num_samples);
369  wfree(u8wave);
370  }
371  else
372  {
373  cerr << aud_sys_name << ": unknown audio format from device: " <<
374  actual_fmt << endl;
375  close(audio);
376  return -1;
377  }
378 
379  if (stereo_only)
380  {
381  for (i=0; i<num_samples; i+=2)
382  waveform[i/2] = waveform2[i];
383  wfree(waveform2);
384  }
385 
386  close(audio);
387  return 0;
388 }
389 
390 #else
391 
392 /*-----------------------------------------------------------------------*/
393 /* Support for alsa, the voxware stuff just doesn't work on most */
394 /* machines now. This code is a modification of the vanilla voxware */
395 /* support */
396 /* */
397 /* Based on the alsa support in Flite provided by Lukas Loehrer */
398 /* */
399 /*=======================================================================*/
400 
401 #ifdef SUPPORT_ALSALINUX
402 #include <sys/ioctl.h>
403 #include <alsa/asoundlib.h>
404 #include <sys/types.h>
405 #include <sys/stat.h>
406 #include <fcntl.h>
407 /*static const char *aud_sys_name = "ALSALINUX";*/
408 
409 // Code to block signals while sound is playing.
410 // Needed inside Java on (at least some) linux systems
411 // as scheduling interrupts seem to break the writes.
412 
413 int linux16_supported = TRUE;
415 
416 #ifdef THREAD_SAFETY
417 #include <csignal>
418 #include <pthread.h>
419 
420 #define THREAD_DECS() \
421  sigset_t oldmask \
422 
423 #define THREAD_PROTECT() do { \
424  sigset_t newmask; \
425  \
426  sigfillset(&newmask); \
427  \
428  pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
429  } while(0)
430 
431 #define THREAD_UNPROTECT() do { \
432  pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
433  } while (0)
434 
435 #else
436 #define THREAD_DECS() //empty
437 #define THREAD_PROTECT() //empty
438 #define THREAD_UNPROTECT() //empty
439 #endif /* THREAD_SAFETY */
440 
441 static const char *pcm_dev_name ="default";
442 
443 typedef enum {
444  CST_AUDIO_LINEAR16 = 0,
445  CST_AUDIO_LINEAR8,
446  CST_AUDIO_MULAW
447 } cst_audiofmt;
448 
449 typedef struct cst_audiodev_struct {
450  int sps, real_sps;
451  int channels, real_channels;
452  cst_audiofmt fmt, real_fmt;
453  int byteswap;
454  /* cst_rateconv *rateconv; */
455  void *platform_data;
456 } cst_audiodev;
457 
458 static int audio_bps(cst_audiofmt fmt)
459 {
460  switch (fmt)
461  {
462  case CST_AUDIO_LINEAR16:
463  return 2;
464  case CST_AUDIO_LINEAR8:
465  case CST_AUDIO_MULAW:
466  return 1;
467  }
468  return 0;
469 }
470 
471 static inline void print_pcm_state(snd_pcm_t *handle, char *msg)
472 {
473  fprintf(stderr, "PCM state at %s = %s\n", msg,
474  snd_pcm_state_name(snd_pcm_state(handle)));
475 }
476 
477 cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt)
478 {
479  cst_audiodev *ad;
480  unsigned int real_rate;
481  int err;
482 
483  /* alsa specific stuff */
484  snd_pcm_t *pcm_handle;
485  snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
486  snd_pcm_hw_params_t *hwparams;
487  snd_pcm_format_t format;
488  snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
489 
490  /* Allocate the snd_pcm_hw_params_t structure on the stack. */
491  snd_pcm_hw_params_alloca(&hwparams);
492 
493  /* Open pcm device */
494  err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0);
495  if (err < 0)
496  {
497  EST_warning("audio_open_alsa: failed to open audio device %s. %s\n",
498  pcm_dev_name, snd_strerror(err));
499  return NULL;
500  }
501 
502  /* Init hwparams with full configuration space */
503  err = snd_pcm_hw_params_any(pcm_handle, hwparams);
504  if (err < 0)
505  {
506  snd_pcm_close(pcm_handle);
507  EST_warning("audio_open_alsa: failed to get hardware parameters from audio device. %s\n", snd_strerror(err));
508  return NULL;
509  }
510 
511  /* Set access mode */
512  err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access);
513  if (err < 0)
514  {
515  snd_pcm_close(pcm_handle);
516  EST_warning("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err));
517  return NULL;
518  }
519 
520  /* Determine matching alsa sample format */
521  /* This could be implemented in a more */
522  /* flexible way (byte order conversion). */
523  switch (fmt)
524  {
525  case CST_AUDIO_LINEAR16:
526  if (EST_LITTLE_ENDIAN)
527  format = SND_PCM_FORMAT_S16_LE;
528  else
529  format = SND_PCM_FORMAT_S16_BE;
530  break;
531  case CST_AUDIO_LINEAR8:
532  format = SND_PCM_FORMAT_U8;
533  break;
534  case CST_AUDIO_MULAW:
535  format = SND_PCM_FORMAT_MU_LAW;
536  break;
537  default:
538  snd_pcm_close(pcm_handle);
539  EST_warning("audio_open_alsa: failed to find suitable format.\n");
540  return NULL;
541  break;
542  }
543 
544  /* Set samble format */
545  err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format);
546  if (err <0)
547  {
548  snd_pcm_close(pcm_handle);
549  EST_warning("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err));
550  return NULL;
551  }
552 
553  /* Set sample rate near the disired rate */
554  real_rate = sps;
555  err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0);
556  if (err < 0)
557  {
558  snd_pcm_close(pcm_handle);
559  EST_warning("audio_open_alsa: failed to set sample rate near %d. %s.\n", sps, snd_strerror(err));
560  return NULL;
561  }
562 
563  /* Set number of channels */
564  assert(channels >0);
565  err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels);
566  if (err < 0)
567  {
568  snd_pcm_close(pcm_handle);
569  EST_warning("audio_open_alsa: failed to set number of channels to %d. %s.\n", channels, snd_strerror(err));
570  return NULL;
571  }
572 
573  /* Commit hardware parameters */
574  err = snd_pcm_hw_params(pcm_handle, hwparams);
575  if (err < 0)
576  {
577  snd_pcm_close(pcm_handle);
578  EST_warning("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err));
579  return NULL;
580  }
581 
582  /* Make sure the device is ready to accept data */
583  assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
584 
585  /* Write hardware parameters to flite audio device data structure */
586  ad = walloc(cst_audiodev, 1);
587  assert(ad != NULL);
588  ad->real_sps = ad->sps = sps;
589  ad->real_channels = ad->channels = channels;
590  ad->real_fmt = ad->fmt = fmt;
591  ad->platform_data = (void *) pcm_handle;
592 
593  return ad;
594 }
595 
596 int audio_close_alsa(cst_audiodev *ad)
597 {
598  int result;
599  snd_pcm_t *pcm_handle;
600 
601  if (ad == NULL)
602  return 0;
603 
604  pcm_handle = (snd_pcm_t *) ad->platform_data;
605 
606  snd_pcm_drain(pcm_handle); /* wait for current stuff in buffer to finish */
607 
608  result = snd_pcm_close(pcm_handle);
609  if (result < 0)
610  {
611  EST_warning("audio_close_alsa: Error: %s.\n", snd_strerror(result));
612  }
613  wfree(ad);
614  return result;
615 }
616 
617 /* Returns zero if recovery was successful. */
618 static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
619 {
620  if (res == -EPIPE) /* xrun */
621  {
622  EST_warning("xrun has occured. This suggests ALSA buffer is "
623  "underflowing. Possibly change audio output methods "
624  "or use a faster or more lightly loaded device");
625  res = snd_pcm_prepare(pcm_handle);
626  if (res < 0)
627  {
628  /* Failed to recover from xrun */
629  EST_warning("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
630  return res;
631  }
632  }
633  else if (res == -ESTRPIPE) /* Suspend */
634  {
635  while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN)
636  {
637  snd_pcm_wait(pcm_handle, 1000);
638  }
639  if (res < 0)
640  {
641  res = snd_pcm_prepare(pcm_handle);
642  if (res <0)
643  {
644  /* Resume failed */
645  EST_warning("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
646  return res;
647  }
648  }
649  }
650  else if (res < 0)
651  {
652  /* Unknown failure */
653  EST_warning("audio_recover_from_write_error: %s.\n", snd_strerror(res));
654  return res;
655  }
656  return 0;
657 }
658 
659 int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
660 {
661  size_t frame_size;
662  ssize_t num_frames, res;
663  snd_pcm_t *pcm_handle;
664  char *buf = (char *) samples;
665 
666  /* Determine frame size in bytes */
667  frame_size = audio_bps(ad->real_fmt) * ad->real_channels;
668  /* Require that only complete frames are handed in */
669  assert((num_bytes % frame_size) == 0);
670  num_frames = num_bytes / frame_size;
671  pcm_handle = (snd_pcm_t *) ad->platform_data;
672 
673  while (num_frames > 0)
674  {
675  res = snd_pcm_writei(pcm_handle, buf, num_frames);
676  if (res != num_frames)
677  {
678  if (res == -EAGAIN || (res > 0 && res < num_frames))
679  {
680  snd_pcm_wait(pcm_handle, 100);
681  }
682  else if (recover_from_error(pcm_handle, res) < 0)
683  {
684  return -1;
685  }
686  }
687 
688  if (res >0)
689  {
690  num_frames -= res;
691  buf += res * frame_size;
692  }
693  }
694  return num_bytes;
695 }
696 
697 int audio_flush_alsa(cst_audiodev *ad)
698 {
699  int result;
700  result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
701  if (result < 0)
702  {
703  EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
704  }
705  /* Prepare device for more data */
706  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
707 if (result < 0)
708  {
709  EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
710  }
711  return result;
712 }
713 
714 int audio_drain_alsa(cst_audiodev *ad)
715 {
716  int result;
717  result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
718  if (result < 0)
719  {
720  EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
721  }
722 /* Prepare device for more data */
723  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
724 if (result < 0)
725  {
726  EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
727  }
728  return result;
729 }
730 
731 #define AUDIOBUFFSIZE 256
732 // #define AUDIOBUFFSIZE 20480
733 
734 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
735 {
736  int sample_rate;
737  short *waveform;
738  int num_samples;
739  /*const char *audiodevice;*/
740  cst_audiodev *ad;
741  (void) al;
742  /*
743  if (al.present("-audiodevice"))
744  audiodevice = al.val("-audiodevice");
745  else
746  audiodevice = "/dev/dsp";
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 #else /* if 0 */
873  (void) inwave;
874  (void) al;
875 #endif /* 0 */
876  return 0;
877 }
878 
879 #else /* not supported */
880 
881 int freebsd16_supported = FALSE;
882 int linux16_supported = FALSE;
883 
885 {
886  (void)inwave;
887  (void)al;
888  cerr << "ALSA audio support not compiled." << endl;
889  return -1;
890 }
892 {
893  (void)inwave;
894  (void)al;
895  cerr << "ALSA audio support not compiled." << endl;
896  return -1;
897 }
898 
899 #endif /* ALSALINUX */
900 
901 #endif /* VOXWARE */
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
#define walloc(TYPE, SIZE)
Definition: EST_walloc.h:52
int linux16_supported
Definition: linux_sound.cc:882
Utility IO Function header file.
void uchar_to_short(const unsigned char *chars, short *data, int length)
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:82
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:104
ssize_t num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143
int ssize_t
short & a(ssize_t i, ssize_t channel=0)
Definition: EST_Wave.cc:128
int freebsd16_supported
Definition: linux_sound.cc:881
void err(const char *message, LISP x) EST_NORETURN
Definition: slib.cc:608
const EST_SMatrix & values() const
Definition: EST_Wave.h:177
#define FALSE
Definition: EST_bool.h:119
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
Definition: linux_sound.cc:884
NULL
Definition: EST_WFST.cc:55
#define EST_LITTLE_ENDIAN
Definition: EST_cutils.h:71
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
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:238
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
Definition: linux_sound.cc:891
#define EST_warning
Definition: EST_error.h:106
int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
FILE16 *(* open)(const char *, const char *, int, const char *, const char *)
Definition: url.c:107
void wfree(void *p)
Definition: walloc.c:131
#define TRUE
Definition: EST_bool.h:118