~ubuntu-branches/ubuntu/maverick/speech-tools/maverick

« back to all changes in this revision

Viewing changes to audio/linux_sound.cc

  • Committer: Bazaar Package Importer
  • Author(s): Kumar Appaiah, Kartik Mistry, Kumar Appaiah
  • Date: 2010-07-17 11:32:04 UTC
  • mfrom: (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100717113204-mnse3jo236j107q8
Tags: 1:2.0.95~beta-1
[ Kartik Mistry ]
* debian/control:
  + [Lintian] Added missing ${misc:Depends}
  + Updated Standards-Version to 3.8.4 (no changes needed)
* debian/patches/const_char.diff:
  + Added missing patch header
* Removed unused patch invalid_const_char_conversion_fixes.diff

[ Kumar Appaiah ]
* New upstream release.
* Standards Version is now 3.9.0 (No changes needed)
* Update debian/rules to specify version numbers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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
    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
    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
static const char *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
  /* Make sure the device is ready to accept data */
 
575
  assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
 
576
 
 
577
  /* Write hardware parameters to flite audio device data structure */
 
578
  ad = walloc(cst_audiodev, 1);
 
579
  assert(ad != NULL);
 
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;
 
584
 
 
585
  return ad;
 
586
}
 
587
 
 
588
int audio_close_alsa(cst_audiodev *ad)
 
589
{
 
590
  int result;
 
591
  snd_pcm_t *pcm_handle;
 
592
 
 
593
  if (ad == NULL)
 
594
      return 0;
 
595
 
 
596
  pcm_handle = (snd_pcm_t *) ad->platform_data;
 
597
 
 
598
  snd_pcm_drain(pcm_handle); /* wait for current stuff in buffer to finish */
 
599
 
 
600
  result = snd_pcm_close(pcm_handle);
 
601
  if (result < 0)
 
602
  {
 
603
        EST_warning("audio_close_alsa: Error: %s.\n", snd_strerror(result));
 
604
  }
 
605
  wfree(ad);
 
606
  return result;
 
607
}
 
608
 
 
609
/* Returns zero if recovery was successful. */
 
610
static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
 
611
{
 
612
  if (res == -EPIPE) /* xrun */
 
613
  {
 
614
        res = snd_pcm_prepare(pcm_handle);
 
615
        if (res < 0) 
 
616
        {
 
617
          /* Failed to recover from xrun */
 
618
          EST_warning("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
 
619
          return res;
 
620
        }
 
621
  } 
 
622
  else if (res == -ESTRPIPE) /* Suspend */
 
623
  {
 
624
        while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN) 
 
625
        {
 
626
          snd_pcm_wait(pcm_handle, 1000);
 
627
        }
 
628
        if (res < 0) 
 
629
        {
 
630
          res = snd_pcm_prepare(pcm_handle);
 
631
          if (res <0) 
 
632
          {
 
633
                /* Resume failed */
 
634
                EST_warning("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
 
635
                return res;
 
636
          }
 
637
        }
 
638
  } 
 
639
  else if (res < 0) 
 
640
  {
 
641
        /* Unknown failure */
 
642
        EST_warning("audio_recover_from_write_error: %s.\n", snd_strerror(res));
 
643
        return res;
 
644
  }
 
645
  return 0;
 
646
}
 
647
 
 
648
int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
 
649
{
 
650
  size_t frame_size;
 
651
  ssize_t num_frames, res;
 
652
  snd_pcm_t *pcm_handle;
 
653
  char *buf = (char *) samples;
 
654
 
 
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;
 
661
 
 
662
  while (num_frames > 0) 
 
663
  {
 
664
        res = snd_pcm_writei(pcm_handle, buf, num_frames);
 
665
        if (res != num_frames) 
 
666
        {
 
667
          if (res == -EAGAIN || (res > 0 && res < num_frames)) 
 
668
          {
 
669
                snd_pcm_wait(pcm_handle, 100);
 
670
          }
 
671
          else if (recover_from_error(pcm_handle, res) < 0) 
 
672
          {
 
673
                return -1;
 
674
          }
 
675
        }
 
676
 
 
677
        if (res >0) 
 
678
        {
 
679
          num_frames -= res;
 
680
          buf += res * frame_size;
 
681
        }
 
682
  }
 
683
  return num_bytes;
 
684
}
 
685
 
 
686
int audio_flush_alsa(cst_audiodev *ad)
 
687
{
 
688
  int result;
 
689
  result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
 
690
  if (result < 0)
 
691
  {
 
692
        EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
 
693
  }
 
694
        /* Prepare device for more data */
 
695
  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
 
696
if (result < 0)
 
697
  {
 
698
        EST_warning("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
 
699
  }
 
700
  return result;
 
701
}
 
702
 
 
703
int audio_drain_alsa(cst_audiodev *ad)
 
704
{
 
705
  int result;
 
706
  result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
 
707
  if (result < 0)
 
708
  {
 
709
        EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
 
710
  }
 
711
/* Prepare device for more data */
 
712
  result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
 
713
if (result < 0)
 
714
  {
 
715
        EST_warning("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
 
716
  }
 
717
  return result;
 
718
}
 
719
 
 
720
#define AUDIOBUFFSIZE 256
 
721
// #define AUDIOBUFFSIZE 20480
 
722
 
 
723
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
 
724
{
 
725
    int sample_rate;
 
726
    short *waveform;
 
727
    int num_samples;
 
728
    const char *audiodevice;
 
729
    cst_audiodev *ad;
 
730
 
 
731
    if (al.present("-audiodevice"))
 
732
        audiodevice = al.val("-audiodevice");
 
733
    else
 
734
        audiodevice = "/dev/dsp";
 
735
 
 
736
    waveform = inwave.values().memory();
 
737
    num_samples = inwave.num_samples();
 
738
    sample_rate = inwave.sample_rate();
 
739
 
 
740
    ad = audio_open_alsa(sample_rate,1,CST_AUDIO_LINEAR16);
 
741
 
 
742
    THREAD_DECS();
 
743
    THREAD_PROTECT();
 
744
 
 
745
    audio_write_alsa(ad,waveform,num_samples*sizeof(short));
 
746
    
 
747
    audio_close_alsa(ad);
 
748
 
 
749
    THREAD_UNPROTECT();
 
750
    return 1;
 
751
}
 
752
 
 
753
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
 
754
{
 
755
#if 0
 
756
    int sample_rate=16000;  // egcs needs the initialized for some reason
 
757
    short *waveform;
 
758
    short *waveform2=0;
 
759
    int num_samples;
 
760
    int audio=-1,actual_fmt;
 
761
    int i,r,n;
 
762
    char *audiodevice;
 
763
 
 
764
    if (al.present("-audiodevice"))
 
765
        audiodevice = al.val("-audiodevice");
 
766
    else
 
767
        audiodevice = "/dev/dsp";
 
768
 
 
769
    sample_rate = al.ival("-sample_rate");
 
770
    
 
771
    if ((audio = open(audiodevice,O_RDONLY)) == -1)
 
772
    {
 
773
        cerr << aud_sys_name << ": can't open " << audiodevice
 
774
             << "for reading" << endl;
 
775
        return -1;
 
776
    }
 
777
    
 
778
    actual_fmt = sb_set_sample_rate(audio,sample_rate);
 
779
 
 
780
    if ((actual_fmt == AFMT_S16_LE) || 
 
781
        (actual_fmt == AFMT_S16_BE))
 
782
    {
 
783
        // We assume that the device returns audio in native byte order
 
784
        // by default
 
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();
 
789
 
 
790
        if (stereo_only)
 
791
        {
 
792
            waveform2 = walloc(short,num_samples*2);
 
793
            num_samples *= 2;
 
794
        }
 
795
        else
 
796
            waveform2 = waveform;
 
797
 
 
798
        for (i=0; i < num_samples; i+= r)
 
799
        {
 
800
            if (num_samples > i+AUDIOBUFFSIZE)
 
801
                n = AUDIOBUFFSIZE;
 
802
            else
 
803
                n = num_samples-i;
 
804
            r = read(audio,&waveform2[i], n*2);
 
805
            r /= 2;
 
806
            if (r <= 0)
 
807
            {
 
808
                cerr << aud_sys_name << ": failed to read from audio device"
 
809
                    << endl;
 
810
                close(audio);
 
811
                return -1;
 
812
            }
 
813
        }
 
814
 
 
815
    }
 
816
    else if (actual_fmt == AFMT_U8)
 
817
    {
 
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);
 
823
 
 
824
        for (i=0; i < num_samples; i+= r)
 
825
        {
 
826
            if (num_samples > i+AUDIOBUFFSIZE)
 
827
                n = AUDIOBUFFSIZE;
 
828
            else
 
829
                n = num_samples-i;
 
830
            r = read(audio,&u8wave[i],n);
 
831
            if (r <= 0)
 
832
            {
 
833
                cerr << aud_sys_name << ": failed to read from audio device"
 
834
                    << endl;
 
835
                close(audio);
 
836
                wfree(u8wave);
 
837
                return -1;
 
838
            }
 
839
            
 
840
        }
 
841
        uchar_to_short(u8wave,waveform,num_samples);
 
842
        wfree(u8wave);
 
843
    }
 
844
    else
 
845
    {
 
846
        cerr << aud_sys_name << ": unknown audio format from device: " << 
 
847
            actual_fmt << endl;
 
848
        close(audio);
 
849
        return -1;
 
850
    }
 
851
 
 
852
    if (stereo_only)
 
853
    {
 
854
        for (i=0; i<num_samples; i+=2)
 
855
            waveform[i/2] = waveform2[i];
 
856
        wfree(waveform2);
 
857
    }
 
858
 
 
859
    close(audio);
 
860
#endif /* 0 */ 
 
861
    return 0;
 
862
}
 
863
 
 
864
#else /* not supported */
 
865
 
 
866
int freebsd16_supported = FALSE;
 
867
int linux16_supported = FALSE;
 
868
 
 
869
int play_linux_wave(EST_Wave &inwave, EST_Option &al)
 
870
{
 
871
    (void)inwave;
 
872
    (void)al;
 
873
    cerr << "MacOS X audio support not compiled." << endl;
 
874
    return -1;
 
875
}
 
876
int record_linux_wave(EST_Wave &inwave, EST_Option &al)
 
877
{
 
878
    (void)inwave;
 
879
    (void)al;
 
880
    cerr << "MacOS X audio support not compiled." << endl;
 
881
    return -1;
 
882
}
 
883
 
 
884
#endif /* ALSALINUX */
 
885
 
 
886
#endif /* VOXWARE */