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>
66int freebsd16_supported = TRUE;
67int linux16_supported = FALSE;
68static 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>
78int linux16_supported = TRUE;
79int freebsd16_supported = FALSE;
80static const char *aud_sys_name = "Linux";
81static 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
113static 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
146int 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
273int 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
405int linux16_supported = TRUE;
406int 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
433static const char *pcm_dev_name ="default";
434
435typedef enum {
436 CST_AUDIO_LINEAR16 = 0,
437 CST_AUDIO_LINEAR8,
438 CST_AUDIO_MULAW
439} cst_audiofmt;
440
441typedef 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
450static 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
463static 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
469cst_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
598int 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. */
620static 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
658int 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
696int 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
713int 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
733int 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
765int 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 */
877int freebsd16_supported = FALSE;
878int linux16_supported = FALSE;
879
880int 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}
887int 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
902int pulse_supported = TRUE;
903
904#define AUDIOBUFFSIZE 256
905// #define AUDIOBUFFSIZE 20480
906
907int 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
955int record_pulse_wave(EST_Wave &inwave, EST_Option &al)
956{
957 return -1;
958}
959
960#else /* not supported */
961
962int pulse_supported = FALSE;
963
964int 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}
971int 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
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:98
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:76
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
const int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
const T * memory() const
Definition: EST_TVector.h:241
short & a(int i, int channel=0)
Definition: EST_Wave.cc:128
int num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
void resize(int num_samples, int num_channels=EST_ALL, int set=1)
resize the waveform
Definition: EST_Wave.h:184
int num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143
void set_sample_rate(const int n)
Set sampling rate to n
Definition: EST_Wave.h:149