"Fossies" - the Fresh Open Source Software Archive 
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
877
878 #ifdef SUPPORT_PULSEAUDIO
879 #include <pulse/simple.h>
880
881 int freebsd16_supported = FALSE;
882 int linux16_supported = TRUE;
883
884 static const char *aud_sys_name = "PULSEAUDIO";
885
886 #define AUDIOBUFFSIZE 256
887 // #define AUDIOBUFFSIZE 20480
888
889 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
890 {
891 pa_sample_spec *ss;
892 pa_simple *s;
893 short *waveform;
894 int num_samples;
895 int err=0, i, r;
896
897 ss = walloc(pa_sample_spec,1);
898 ss->rate = inwave.sample_rate();
899 ss->channels = inwave.num_channels();
900
901 if (EST_BIG_ENDIAN)
902 ss->format = PA_SAMPLE_S16BE;
903 else
904 ss->format = PA_SAMPLE_S16LE;
905
906 s = pa_simple_new(
907 NULL, /* use default server */
908 "festival",
909 PA_STREAM_PLAYBACK,
910 NULL, /* use default device */
911 "Speech",
912 ss,
913 NULL, /* default channel map */
914 NULL, /* default buffering attributes */
915 &err);
916 if (err < 0)
917 return NULL;
918
919 waveform = inwave.values().memory();
920 num_samples = inwave.num_samples();
921
922 for (i=0; i < num_samples; i += AUDIOBUFFSIZE/2)
923 {
924 if (i + AUDIOBUFFSIZE/2 < num_samples)
925 pa_simple_write(s,&waveform[i],(size_t)AUDIOBUFFSIZE,&err);
926 else
927 pa_simple_write(s,&waveform[i],(size_t)(num_samples-i)*2,&err);
928 }
929
930 pa_simple_drain(s,&err);
931 pa_simple_free(s);
932 wfree(ss);
933
934 return 1;
935 }
936
937 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
938 {
939 return -1;
940 }
941
942 #else /* not supported */
943
944 int freebsd16_supported = FALSE;
945 int linux16_supported = FALSE;
946
947 int play_linux_wave(EST_Wave &inwave, EST_Option &al)
948 {
949 (void)inwave;
950 (void)al;
951 cerr << "MacOS X audio support not compiled." << endl;
952 return -1;
953 }
954 int record_linux_wave(EST_Wave &inwave, EST_Option &al)
955 {
956 (void)inwave;
957 (void)al;
958 cerr << "MacOS X audio support not compiled." << endl;
959 return -1;
960 }
961
962 #endif /* ALSA */
963 #endif /* PULSEAUDIO */
964 #endif /* VOXWARE */
965