1
/*************************************************************************/
3
/* Centre for Speech Technology Research */
4
/* University of Edinburgh, UK */
5
/* Copyright (c) 1997,1998 */
6
/* All Rights Reserved. */
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 */
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 */
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 */
43
/* Combined FreeBSD and Voxware code Feb 98 */
45
/* This may work on NetBSD and OpenBSD but I haven't tried it */
47
/*=======================================================================*/
54
#include "EST_cutils.h"
55
#include "EST_walloc.h"
57
#include "EST_wave_aux.h"
58
#include "EST_Option.h"
60
#include "EST_io_aux.h"
61
#include "EST_error.h"
63
#ifdef SUPPORT_FREEBSD16
64
#include <sys/soundcard.h>
66
int freebsd16_supported = TRUE;
67
int linux16_supported = FALSE;
68
static char *aud_sys_name = "FreeBSD";
69
#endif /*SUPPORT_FREEBSD16 */
71
#ifdef SUPPORT_VOXWARE
73
#include <sys/ioctl.h>
74
#include <sys/soundcard.h>
75
#include <sys/types.h>
78
int linux16_supported = TRUE;
79
int freebsd16_supported = FALSE;
80
static char *aud_sys_name = "Linux";
81
static int stereo_only = 0;
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.
87
#if defined(SUPPORT_LINUX16) || defined(SUPPORT_FREEBSD16)
92
#define THREAD_DECS() \
95
#define THREAD_PROTECT() do { \
98
sigfillset(&newmask); \
100
pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
103
#define THREAD_UNPROTECT() do { \
104
pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
108
#define THREAD_DECS() //empty
109
#define THREAD_PROTECT() //empty
110
#define THREAD_UNPROTECT() //empty
111
#endif /* LINUX_16/FREEBSD16 */
113
static int sb_set_sample_rate(int sbdevice, int samp_rate)
121
ioctl(sbdevice,SNDCTL_DSP_RESET,0);
122
ioctl(sbdevice,SNDCTL_DSP_SPEED,&samp_rate);
124
ioctl(sbdevice,SNDCTL_DSP_STEREO,&sstereo);
125
/* Some devices don't do mono even when you ask them nicely */
126
if (sstereo != stereo)
128
ioctl(sbdevice,SNDCTL_DSP_CHANNELS,&channels);
129
ioctl(sbdevice,SNDCTL_DSP_GETFMTS,&sfmts);
131
if (sfmts == AFMT_U8)
132
fmt = AFMT_U8; // its really an 8 bit only device
133
else if (EST_LITTLE_ENDIAN)
138
ioctl(sbdevice,SNDCTL_DSP_SETFMT,&fmt);
143
#define AUDIOBUFFSIZE 256
144
// #define AUDIOBUFFSIZE 20480
146
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
150
short *waveform2 = 0;
152
int audio,actual_fmt;
156
if (al.present("-audiodevice"))
157
audiodevice = al.val("-audiodevice");
159
audiodevice = "/dev/dsp";
161
if ((audio = open(audiodevice,O_WRONLY)) == -1)
163
cerr << aud_sys_name << ": can't open " << audiodevice << endl;
167
// int tmp=open("/tmp/vox_play_wave",O_WRONLY|O_CREAT);
169
waveform = inwave.values().memory();
170
num_samples = inwave.num_samples();
171
sample_rate = inwave.sample_rate();
173
actual_fmt = sb_set_sample_rate(audio,sample_rate);
177
waveform2 = walloc(short,num_samples*2);
178
for (i=0; i<num_samples; i++)
180
waveform2[i*2] = inwave.a(i);
181
waveform2[(i*2)+1] = inwave.a(i);
183
waveform = waveform2;
190
if (sb_set_sample_rate(audio,sample_rate) == AFMT_U8)
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)
198
if (num_samples > i+AUDIOBUFFSIZE)
202
// r = write(tmp,&uchars[i], n);
203
r = write(audio,&uchars[i], n);
207
cerr << aud_sys_name << ": failed to write to buffer" <<
215
else if ((actual_fmt == AFMT_S16_LE) ||
216
(actual_fmt == AFMT_S16_BE))
218
int blksize, nbuf, c;
221
ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &blksize);
225
for (i=0; i < num_samples; i += r/2)
227
if (num_samples > i+nbuf)
233
buf[c]=waveform[c+i];
236
buf[c]=waveform[n-1];
238
// r = write(tmp,&waveform[i], n*2);
239
// r = write(audio,&waveform[i], n*2);
240
r=write(audio, buf, nbuf*2);
244
EST_warning("%s: failed to write to buffer (sr=%d)",aud_sys_name, sample_rate );
248
// ioctl(audio, SNDCTL_DSP_SYNC, 0);
249
// fprintf(stderr,"[%d]", r);
256
cerr << aud_sys_name << ": unable to set sample rate " <<
262
// ioctl(audio, SNDCTL_DSP_SYNC, 0);
263
// fprintf(stderr, "End Play\n");
273
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
275
int sample_rate=16000; // egcs needs the initialized for some reason
279
int audio=-1,actual_fmt;
283
if (al.present("-audiodevice"))
284
audiodevice = al.val("-audiodevice");
286
audiodevice = "/dev/dsp";
288
sample_rate = al.ival("-sample_rate");
290
if ((audio = open(audiodevice,O_RDONLY)) == -1)
292
cerr << aud_sys_name << ": can't open " << audiodevice
293
<< "for reading" << endl;
297
actual_fmt = sb_set_sample_rate(audio,sample_rate);
299
if ((actual_fmt == AFMT_S16_LE) ||
300
(actual_fmt == AFMT_S16_BE))
302
// We assume that the device returns audio in native byte order
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();
311
waveform2 = walloc(short,num_samples*2);
315
waveform2 = waveform;
317
for (i=0; i < num_samples; i+= r)
319
if (num_samples > i+AUDIOBUFFSIZE)
323
r = read(audio,&waveform2[i], n*2);
327
cerr << aud_sys_name << ": failed to read from audio device"
335
else if (actual_fmt == AFMT_U8)
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);
343
for (i=0; i < num_samples; i+= r)
345
if (num_samples > i+AUDIOBUFFSIZE)
349
r = read(audio,&u8wave[i],n);
352
cerr << aud_sys_name << ": failed to read from audio device"
360
uchar_to_short(u8wave,waveform,num_samples);
365
cerr << aud_sys_name << ": unknown audio format from device: " <<
373
for (i=0; i<num_samples; i+=2)
374
waveform[i/2] = waveform2[i];
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 */
389
/* Based on the alsa support in Flite provided by Lukas Loehrer */
391
/*=======================================================================*/
393
#ifdef SUPPORT_ALSALINUX
394
#include <sys/ioctl.h>
395
#include <alsa/asoundlib.h>
396
#include <sys/types.h>
397
#include <sys/stat.h>
399
static const char *aud_sys_name = "ALSALINUX";
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.
405
int linux16_supported = TRUE;
406
int freebsd16_supported = FALSE;
412
#define THREAD_DECS() \
415
#define THREAD_PROTECT() do { \
418
sigfillset(&newmask); \
420
pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
423
#define THREAD_UNPROTECT() do { \
424
pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
428
#define THREAD_DECS() //empty
429
#define THREAD_PROTECT() //empty
430
#define THREAD_UNPROTECT() //empty
431
#endif /* THREAD_SAFETY */
433
static const char *pcm_dev_name ="default";
436
CST_AUDIO_LINEAR16 = 0,
441
typedef struct cst_audiodev_struct {
443
int channels, real_channels;
444
cst_audiofmt fmt, real_fmt;
446
/* cst_rateconv *rateconv; */
450
static int audio_bps(cst_audiofmt fmt)
454
case CST_AUDIO_LINEAR16:
456
case CST_AUDIO_LINEAR8:
457
case CST_AUDIO_MULAW:
463
static inline void print_pcm_state(snd_pcm_t *handle, char *msg)
465
fprintf(stderr, "PCM state at %s = %s\n", msg,
466
snd_pcm_state_name(snd_pcm_state(handle)));
469
cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt)
472
unsigned int real_rate;
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;
482
/* Allocate the snd_pcm_hw_params_t structure on the stack. */
483
snd_pcm_hw_params_alloca(&hwparams);
485
/* Open pcm device */
486
err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0);
489
EST_warning("audio_open_alsa: failed to open audio device %s. %s\n",
490
pcm_dev_name, snd_strerror(err));
494
/* Init hwparams with full configuration space */
495
err = snd_pcm_hw_params_any(pcm_handle, hwparams);
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));
503
/* Set access mode */
504
err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access);
507
snd_pcm_close(pcm_handle);
508
EST_warning("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err));
512
/* Determine matching alsa sample format */
513
/* This could be implemented in a more */
514
/* flexible way (byte order conversion). */
517
case CST_AUDIO_LINEAR16:
518
if (EST_LITTLE_ENDIAN)
519
format = SND_PCM_FORMAT_S16_LE;
521
format = SND_PCM_FORMAT_S16_BE;
523
case CST_AUDIO_LINEAR8:
524
format = SND_PCM_FORMAT_U8;
526
case CST_AUDIO_MULAW:
527
format = SND_PCM_FORMAT_MU_LAW;
530
snd_pcm_close(pcm_handle);
531
EST_warning("audio_open_alsa: failed to find suitable format.\n");
536
/* Set samble format */
537
err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format);
540
snd_pcm_close(pcm_handle);
541
EST_warning("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err));
545
/* Set sample rate near the disired rate */
547
err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0);
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));
555
/* Set number of channels */
557
err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels);
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));
565
/* Commit hardware parameters */
566
err = snd_pcm_hw_params(pcm_handle, hwparams);
569
snd_pcm_close(pcm_handle);
570
EST_warning("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err));
574
/* Make sure the device is ready to accept data */
575
assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
577
/* Write hardware parameters to flite audio device data structure */
578
ad = walloc(cst_audiodev, 1);
580
ad->real_sps = ad->sps = sps;
581
ad->real_channels = ad->channels = channels;
582
ad->real_fmt = ad->fmt = fmt;
583
ad->platform_data = (void *) pcm_handle;
588
int audio_close_alsa(cst_audiodev *ad)
591
snd_pcm_t *pcm_handle;
596
pcm_handle = (snd_pcm_t *) ad->platform_data;
598
snd_pcm_drain(pcm_handle); /* wait for current stuff in buffer to finish */
600
result = snd_pcm_close(pcm_handle);
603
EST_warning("audio_close_alsa: Error: %s.\n", snd_strerror(result));
609
/* Returns zero if recovery was successful. */
610
static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
612
if (res == -EPIPE) /* xrun */
614
res = snd_pcm_prepare(pcm_handle);
617
/* Failed to recover from xrun */
618
EST_warning("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
622
else if (res == -ESTRPIPE) /* Suspend */
624
while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN)
626
snd_pcm_wait(pcm_handle, 1000);
630
res = snd_pcm_prepare(pcm_handle);
634
EST_warning("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
641
/* Unknown failure */
642
EST_warning("audio_recover_from_write_error: %s.\n", snd_strerror(res));
648
int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
651
ssize_t num_frames, res;
652
snd_pcm_t *pcm_handle;
653
char *buf = (char *) samples;
655
/* Determine frame size in bytes */
656
frame_size = audio_bps(ad->real_fmt) * ad->real_channels;
657
/* Require that only complete frames are handed in */
658
assert((num_bytes % frame_size) == 0);
659
num_frames = num_bytes / frame_size;
660
pcm_handle = (snd_pcm_t *) ad->platform_data;
662
while (num_frames > 0)
664
res = snd_pcm_writei(pcm_handle, buf, num_frames);
665
if (res != num_frames)
667
if (res == -EAGAIN || (res > 0 && res < num_frames))
669
snd_pcm_wait(pcm_handle, 100);
671
else if (recover_from_error(pcm_handle, res) < 0)
680
buf += res * frame_size;
686
int audio_flush_alsa(cst_audiodev *ad)
689
result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
692
EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
694
/* Prepare device for more data */
695
result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
698
EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
703
int audio_drain_alsa(cst_audiodev *ad)
706
result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
709
EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
711
/* Prepare device for more data */
712
result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
715
EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
720
#define AUDIOBUFFSIZE 256
721
// #define AUDIOBUFFSIZE 20480
723
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
728
const char *audiodevice;
731
if (al.present("-audiodevice"))
732
audiodevice = al.val("-audiodevice");
734
audiodevice = "/dev/dsp";
736
waveform = inwave.values().memory();
737
num_samples = inwave.num_samples();
738
sample_rate = inwave.sample_rate();
740
ad = audio_open_alsa(sample_rate,1,CST_AUDIO_LINEAR16);
745
audio_write_alsa(ad,waveform,num_samples*sizeof(short));
747
audio_close_alsa(ad);
753
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
756
int sample_rate=16000; // egcs needs the initialized for some reason
760
int audio=-1,actual_fmt;
764
if (al.present("-audiodevice"))
765
audiodevice = al.val("-audiodevice");
767
audiodevice = "/dev/dsp";
769
sample_rate = al.ival("-sample_rate");
771
if ((audio = open(audiodevice,O_RDONLY)) == -1)
773
cerr << aud_sys_name << ": can't open " << audiodevice
774
<< "for reading" << endl;
778
actual_fmt = sb_set_sample_rate(audio,sample_rate);
780
if ((actual_fmt == AFMT_S16_LE) ||
781
(actual_fmt == AFMT_S16_BE))
783
// We assume that the device returns audio in native byte order
785
inwave.resize((int)(sample_rate*al.fval("-time")));
786
inwave.set_sample_rate(sample_rate);
787
num_samples = inwave.num_samples();
788
waveform = inwave.values().memory();
792
waveform2 = walloc(short,num_samples*2);
796
waveform2 = waveform;
798
for (i=0; i < num_samples; i+= r)
800
if (num_samples > i+AUDIOBUFFSIZE)
804
r = read(audio,&waveform2[i], n*2);
808
cerr << aud_sys_name << ": failed to read from audio device"
816
else if (actual_fmt == AFMT_U8)
818
inwave.resize((int)(sample_rate*al.fval("-time")));
819
inwave.set_sample_rate(sample_rate);
820
num_samples = inwave.num_samples();
821
waveform = inwave.values().memory();
822
unsigned char *u8wave = walloc(unsigned char,num_samples);
824
for (i=0; i < num_samples; i+= r)
826
if (num_samples > i+AUDIOBUFFSIZE)
830
r = read(audio,&u8wave[i],n);
833
cerr << aud_sys_name << ": failed to read from audio device"
841
uchar_to_short(u8wave,waveform,num_samples);
846
cerr << aud_sys_name << ": unknown audio format from device: " <<
854
for (i=0; i<num_samples; i+=2)
855
waveform[i/2] = waveform2[i];
864
#else /* not supported */
866
int freebsd16_supported = FALSE;
867
int linux16_supported = FALSE;
869
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
873
cerr << "MacOS X audio support not compiled." << endl;
876
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
880
cerr << "MacOS X audio support not compiled." << endl;
884
#endif /* ALSALINUX */