~ubuntu-branches/ubuntu/gutsy/audacity/gutsy-backports

« back to all changes in this revision

Viewing changes to lib-src/libsndfile/examples/sndfile-play.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-18 21:58:19 UTC
  • mfrom: (13.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080218215819-tmbcf1rx238r8gdv
Tags: 1.3.4-1.1ubuntu1~gutsy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
3
 
**
4
 
** This program is free software; you can redistribute it and/or modify
5
 
** it under the terms of the GNU General Public License as published by
6
 
** the Free Software Foundation; either version 2 of the License, or
7
 
** (at your option) any later version.
8
 
**
9
 
** This program is distributed in the hope that it will be useful,
10
 
** but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
** GNU General Public License for more details.
13
 
**
14
 
** You should have received a copy of the GNU General Public License
15
 
** along with this program; if not, write to the Free Software
16
 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
 
*/
18
 
 
19
 
#include "sfconfig.h"
20
 
 
21
 
#include <stdio.h>
22
 
#include <stdlib.h>
23
 
#include <string.h>
24
 
#include <errno.h>
25
 
 
26
 
#if HAVE_UNISTD_H
27
 
#include <unistd.h>
28
 
#endif
29
 
 
30
 
#if HAVE_ALSA_ASOUNDLIB_H
31
 
        #define ALSA_PCM_NEW_HW_PARAMS_API
32
 
        #define ALSA_PCM_NEW_SW_PARAMS_API
33
 
        #include <alsa/asoundlib.h>
34
 
        #include <sys/time.h>
35
 
#endif
36
 
 
37
 
#if defined (__linux__)
38
 
        #include        <fcntl.h>
39
 
        #include        <sys/ioctl.h>
40
 
        #include        <sys/soundcard.h>
41
 
 
42
 
#elif (defined (__MACH__) && defined (__APPLE__))
43
 
        #include <Carbon.h>
44
 
        #include <CoreAudio/AudioHardware.h>
45
 
 
46
 
#elif (defined (sun) && defined (unix))
47
 
        #include <fcntl.h>
48
 
        #include <sys/ioctl.h>
49
 
        #include <sys/audioio.h>
50
 
 
51
 
#elif (OS_IS_WIN32 == 1)
52
 
        #include <windows.h>
53
 
        #include <mmsystem.h>
54
 
 
55
 
#endif
56
 
 
57
 
#include        <sndfile.h>
58
 
 
59
 
#define SIGNED_SIZEOF(x)        ((int) sizeof (x))
60
 
#define BUFFER_LEN                      (2048)
61
 
 
62
 
/*------------------------------------------------------------------------------
63
 
**      Linux/OSS functions for playing a sound.
64
 
*/
65
 
 
66
 
#if HAVE_ALSA_ASOUNDLIB_H
67
 
 
68
 
static snd_pcm_t * alsa_open (int channels, unsigned srate, int realtime) ;
69
 
static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ;
70
 
 
71
 
static void
72
 
alsa_play (int argc, char *argv [])
73
 
{       static float buffer [BUFFER_LEN] ;
74
 
        SNDFILE *sndfile ;
75
 
        SF_INFO sfinfo ;
76
 
        snd_pcm_t * alsa_dev ;
77
 
        int             k, readcount, subformat ;
78
 
 
79
 
        for (k = 1 ; k < argc ; k++)
80
 
        {       memset (&sfinfo, 0, sizeof (sfinfo)) ;
81
 
 
82
 
                printf ("Playing %s\n", argv [k]) ;
83
 
                if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
84
 
                {       puts (sf_strerror (NULL)) ;
85
 
                        continue ;
86
 
                        } ;
87
 
 
88
 
                if (sfinfo.channels < 1 || sfinfo.channels > 2)
89
 
                {       printf ("Error : channels = %d.\n", sfinfo.channels) ;
90
 
                        continue ;
91
 
                        } ;
92
 
 
93
 
                if ((alsa_dev = alsa_open (sfinfo.channels, (unsigned) sfinfo.samplerate, SF_FALSE)) == NULL)
94
 
                        continue ;
95
 
 
96
 
                subformat = sfinfo.format & SF_FORMAT_SUBMASK ;
97
 
 
98
 
                if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)
99
 
                {       double  scale ;
100
 
                        int     m ;
101
 
 
102
 
                        sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;
103
 
                        if (scale < 1e-10)
104
 
                                scale = 1.0 ;
105
 
                        else
106
 
                                scale = 32700.0 / scale ;
107
 
 
108
 
                        while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))
109
 
                        {       for (m = 0 ; m < readcount ; m++)
110
 
                                        buffer [m] *= scale ;
111
 
                                alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;
112
 
                                } ;
113
 
                        }
114
 
                else
115
 
                {       while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))
116
 
                                alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;
117
 
                        } ;
118
 
 
119
 
                snd_pcm_drain (alsa_dev) ;
120
 
                snd_pcm_close (alsa_dev) ;
121
 
 
122
 
                sf_close (sndfile) ;
123
 
                } ;
124
 
 
125
 
        return ;
126
 
} /* alsa_play */
127
 
 
128
 
static snd_pcm_t *
129
 
alsa_open (int channels, unsigned samplerate, int realtime)
130
 
{       const char * device = "plughw:0" ;
131
 
        snd_pcm_t *alsa_dev = NULL ;
132
 
        snd_pcm_hw_params_t *hw_params ;
133
 
        snd_pcm_uframes_t buffer_size, xfer_align, start_threshold ;
134
 
        snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
135
 
        snd_pcm_sw_params_t *sw_params ;
136
 
 
137
 
        int err ;
138
 
 
139
 
        if (realtime)
140
 
        {       alsa_period_size = 256 ;
141
 
                alsa_buffer_frames = 3 * alsa_period_size ;
142
 
                }
143
 
        else
144
 
        {       alsa_period_size = 1024 ;
145
 
                alsa_buffer_frames = 4 * alsa_period_size ;
146
 
                } ;
147
 
 
148
 
        if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
149
 
        {       fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
150
 
                goto catch_error ;
151
 
                } ;
152
 
 
153
 
        snd_pcm_nonblock (alsa_dev, 0) ;
154
 
 
155
 
        if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
156
 
        {       fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
157
 
                goto catch_error ;
158
 
                } ;
159
 
 
160
 
        if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0)
161
 
        {       fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
162
 
                goto catch_error ;
163
 
                } ;
164
 
 
165
 
        if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
166
 
        {       fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
167
 
                goto catch_error ;
168
 
                } ;
169
 
 
170
 
        if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
171
 
        {       fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
172
 
                goto catch_error ;
173
 
                } ;
174
 
 
175
 
        if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0)
176
 
        {       fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
177
 
                goto catch_error ;
178
 
                } ;
179
 
 
180
 
        if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0)
181
 
        {       fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
182
 
                goto catch_error ;
183
 
                } ;
184
 
 
185
 
        if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
186
 
        {       fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
187
 
                goto catch_error ;
188
 
                } ;
189
 
 
190
 
        if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
191
 
        {       fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
192
 
                goto catch_error ;
193
 
                } ;
194
 
 
195
 
        if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0)
196
 
        {       fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
197
 
                goto catch_error ;
198
 
                } ;
199
 
 
200
 
        /* extra check: if we have only one period, this code won't work */
201
 
        snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
202
 
        snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
203
 
        if (alsa_period_size == buffer_size)
204
 
        {       fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
205
 
                goto catch_error ;
206
 
                } ;
207
 
 
208
 
        snd_pcm_hw_params_free (hw_params) ;
209
 
 
210
 
        if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
211
 
        {       fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
212
 
                goto catch_error ;
213
 
                } ;
214
 
 
215
 
        if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0)
216
 
        {       fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
217
 
                goto catch_error ;
218
 
                } ;
219
 
 
220
 
        /* note: set start threshold to delay start until the ring buffer is full */
221
 
        snd_pcm_sw_params_current (alsa_dev, sw_params) ;
222
 
        if ((err = snd_pcm_sw_params_get_xfer_align (sw_params, &xfer_align)) < 0)
223
 
        {       fprintf (stderr, "cannot get xfer align (%s)\n", snd_strerror (err)) ;
224
 
                goto catch_error ;
225
 
                } ;
226
 
 
227
 
        /* round up to closest transfer boundary */
228
 
        start_threshold = (buffer_size / xfer_align) * xfer_align ;
229
 
        if (start_threshold < 1)
230
 
                start_threshold = 1 ;
231
 
        if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, start_threshold)) < 0)
232
 
        {       fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
233
 
                goto catch_error ;
234
 
                } ;
235
 
 
236
 
        if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0)
237
 
        {       fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
238
 
                goto catch_error ;
239
 
                } ;
240
 
 
241
 
        snd_pcm_sw_params_free (sw_params) ;
242
 
 
243
 
        snd_pcm_reset (alsa_dev) ;
244
 
 
245
 
catch_error :
246
 
 
247
 
        if (err < 0 && alsa_dev != NULL)
248
 
        {       snd_pcm_close (alsa_dev) ;
249
 
                return NULL ;
250
 
                } ;
251
 
 
252
 
        return alsa_dev ;
253
 
} /* alsa_open */
254
 
 
255
 
static int
256
 
alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels)
257
 
{       static  int epipe_count = 0 ;
258
 
 
259
 
        snd_pcm_status_t *status ;
260
 
        int total = 0 ;
261
 
        int retval ;
262
 
 
263
 
        if (epipe_count > 0)
264
 
                epipe_count -- ;
265
 
 
266
 
        while (total < frames)
267
 
        {       retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ;
268
 
 
269
 
                if (retval >= 0)
270
 
                {       total += retval ;
271
 
                        if (total == frames)
272
 
                                return total ;
273
 
 
274
 
                        continue ;
275
 
                        } ;
276
 
 
277
 
                switch (retval)
278
 
                {       case -EAGAIN :
279
 
                                        puts ("alsa_write_float: EAGAIN") ;
280
 
                                        continue ;
281
 
                                        break ;
282
 
 
283
 
                        case -EPIPE :
284
 
                                        if (epipe_count > 0)
285
 
                                        {       printf ("alsa_write_float: EPIPE %d\n", epipe_count) ;
286
 
                                                if (epipe_count > 140)
287
 
                                                        return retval ;
288
 
                                                } ;
289
 
                                        epipe_count += 100 ;
290
 
 
291
 
                                        if (0)
292
 
                                        {       snd_pcm_status_alloca (&status) ;
293
 
                                                if ((retval = snd_pcm_status (alsa_dev, status)) < 0)
294
 
                                                        fprintf (stderr, "alsa_out: xrun. can't determine length\n") ;
295
 
                                                else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN)
296
 
                                                {       struct timeval now, diff, tstamp ;
297
 
 
298
 
                                                        gettimeofday (&now, 0) ;
299
 
                                                        snd_pcm_status_get_trigger_tstamp (status, &tstamp) ;
300
 
                                                        timersub (&now, &tstamp, &diff) ;
301
 
 
302
 
                                                        fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",
303
 
                                                                        diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ;
304
 
                                                        }
305
 
                                                else
306
 
                                                        fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ;
307
 
                                                } ;
308
 
 
309
 
                                        snd_pcm_prepare (alsa_dev) ;
310
 
                                        break ;
311
 
 
312
 
                        case -EBADFD :
313
 
                                        fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;
314
 
                                        return 0 ;
315
 
                                        break ;
316
 
 
317
 
                        case -ESTRPIPE :
318
 
                                        fprintf (stderr, "alsa_write_float: Suspend event.n") ;
319
 
                                        return 0 ;
320
 
                                        break ;
321
 
 
322
 
                        case -EIO :
323
 
                                        puts ("alsa_write_float: EIO") ;
324
 
                                        return 0 ;
325
 
 
326
 
                        default :
327
 
                                        fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ;
328
 
                                        return 0 ;
329
 
                                        break ;
330
 
                        } ; /* switch */
331
 
                } ; /* while */
332
 
 
333
 
        return total ;
334
 
} /* alsa_write_float */
335
 
 
336
 
#endif /* HAVE_ALSA_ASOUNDLIB_H */
337
 
 
338
 
/*------------------------------------------------------------------------------
339
 
**      Linux/OSS functions for playing a sound.
340
 
*/
341
 
 
342
 
#if defined (__linux__)
343
 
 
344
 
static  int     linux_open_dsp_device (int channels, int srate) ;
345
 
 
346
 
static void
347
 
linux_play (int argc, char *argv [])
348
 
{       static short buffer [BUFFER_LEN] ;
349
 
        SNDFILE *sndfile ;
350
 
        SF_INFO sfinfo ;
351
 
        int             k, audio_device, readcount, subformat ;
352
 
 
353
 
        for (k = 1 ; k < argc ; k++)
354
 
        {       memset (&sfinfo, 0, sizeof (sfinfo)) ;
355
 
 
356
 
                printf ("Playing %s\n", argv [k]) ;
357
 
                if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
358
 
                {       puts (sf_strerror (NULL)) ;
359
 
                        continue ;
360
 
                        } ;
361
 
 
362
 
                if (sfinfo.channels < 1 || sfinfo.channels > 2)
363
 
                {       printf ("Error : channels = %d.\n", sfinfo.channels) ;
364
 
                        continue ;
365
 
                        } ;
366
 
 
367
 
                audio_device = linux_open_dsp_device (sfinfo.channels, sfinfo.samplerate) ;
368
 
 
369
 
                subformat = sfinfo.format & SF_FORMAT_SUBMASK ;
370
 
 
371
 
                if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)
372
 
                {       static float float_buffer [BUFFER_LEN] ;
373
 
                        double  scale ;
374
 
                        int     m ;
375
 
 
376
 
                        sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;
377
 
                        if (scale < 1e-10)
378
 
                                scale = 1.0 ;
379
 
                        else
380
 
                                scale = 32700.0 / scale ;
381
 
 
382
 
                        while ((readcount = sf_read_float (sndfile, float_buffer, BUFFER_LEN)))
383
 
                        {       for (m = 0 ; m < readcount ; m++)
384
 
                                        buffer [m] = scale * float_buffer [m] ;
385
 
                                write (audio_device, buffer, readcount * sizeof (short)) ;
386
 
                                } ;
387
 
                        }
388
 
                else
389
 
                {       while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN)))
390
 
                                write (audio_device, buffer, readcount * sizeof (short)) ;
391
 
                        } ;
392
 
 
393
 
                if (ioctl (audio_device, SNDCTL_DSP_POST, 0) == -1)
394
 
                        perror ("ioctl (SNDCTL_DSP_POST) ") ;
395
 
 
396
 
                if (ioctl (audio_device, SNDCTL_DSP_SYNC, 0) == -1)
397
 
                        perror ("ioctl (SNDCTL_DSP_SYNC) ") ;
398
 
 
399
 
                close (audio_device) ;
400
 
 
401
 
                sf_close (sndfile) ;
402
 
                } ;
403
 
 
404
 
        return ;
405
 
} /* linux_play */
406
 
 
407
 
static int
408
 
linux_open_dsp_device (int channels, int srate)
409
 
{       int fd, stereo, temp, error ;
410
 
 
411
 
        if ((fd = open ("/dev/dsp", O_WRONLY, 0)) == -1 &&
412
 
                (fd = open ("/dev/sound/dsp", O_WRONLY, 0)) == -1)
413
 
        {       perror ("linux_open_dsp_device : open ") ;
414
 
                exit (1) ;
415
 
                } ;
416
 
 
417
 
        stereo = 0 ;
418
 
        if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1)
419
 
        {       /* Fatal error */
420
 
                perror ("linux_open_dsp_device : stereo ") ;
421
 
                exit (1) ;
422
 
                } ;
423
 
 
424
 
        if (ioctl (fd, SNDCTL_DSP_RESET, 0))
425
 
        {       perror ("linux_open_dsp_device : reset ") ;
426
 
                exit (1) ;
427
 
                } ;
428
 
 
429
 
        temp = 16 ;
430
 
        if ((error = ioctl (fd, SOUND_PCM_WRITE_BITS, &temp)) != 0)
431
 
        {       perror ("linux_open_dsp_device : bitwidth ") ;
432
 
                exit (1) ;
433
 
                } ;
434
 
 
435
 
        if ((error = ioctl (fd, SOUND_PCM_WRITE_CHANNELS, &channels)) != 0)
436
 
        {       perror ("linux_open_dsp_device : channels ") ;
437
 
                exit (1) ;
438
 
                } ;
439
 
 
440
 
        if ((error = ioctl (fd, SOUND_PCM_WRITE_RATE, &srate)) != 0)
441
 
        {       perror ("linux_open_dsp_device : sample rate ") ;
442
 
                exit (1) ;
443
 
                } ;
444
 
 
445
 
        if ((error = ioctl (fd, SNDCTL_DSP_SYNC, 0)) != 0)
446
 
        {       perror ("linux_open_dsp_device : sync ") ;
447
 
                exit (1) ;
448
 
                } ;
449
 
 
450
 
        return  fd ;
451
 
} /* linux_open_dsp_device */
452
 
 
453
 
#endif /* __linux__ */
454
 
 
455
 
/*------------------------------------------------------------------------------
456
 
**      Mac OS X functions for playing a sound.
457
 
*/
458
 
 
459
 
#if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
460
 
 
461
 
typedef struct
462
 
{       AudioStreamBasicDescription             format ;
463
 
 
464
 
        UInt32                  buf_size ;
465
 
        AudioDeviceID   device ;
466
 
 
467
 
        SNDFILE                 *sndfile ;
468
 
        SF_INFO                 sfinfo ;
469
 
 
470
 
        int                             fake_stereo ;
471
 
        int                             done_playing ;
472
 
} MacOSXAudioData ;
473
 
 
474
 
#include <math.h>
475
 
 
476
 
static OSStatus
477
 
macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
478
 
        const AudioBufferList* data_in, const AudioTimeStamp* time_in,
479
 
        AudioBufferList*        data_out, const AudioTimeStamp* time_out,
480
 
        void* client_data)
481
 
{       MacOSXAudioData *audio_data ;
482
 
        int             size, sample_count, read_count, k ;
483
 
        float   *buffer ;
484
 
 
485
 
        /* Prevent compiler warnings. */
486
 
        device = device ;
487
 
        current_time = current_time ;
488
 
        data_in = data_in ;
489
 
        time_in = time_in ;
490
 
        time_out = time_out ;
491
 
 
492
 
        audio_data = (MacOSXAudioData*) client_data ;
493
 
 
494
 
        size = data_out->mBuffers [0].mDataByteSize ;
495
 
        sample_count = size / sizeof (float) ;
496
 
 
497
 
        buffer = (float*) data_out->mBuffers [0].mData ;
498
 
 
499
 
        if (audio_data->fake_stereo != 0)
500
 
        {       read_count = sf_read_float (audio_data->sndfile, buffer, sample_count / 2) ;
501
 
 
502
 
                for (k = read_count - 1 ; k >= 0 ; k--)
503
 
                {       buffer [2 * k   ] = buffer [k] ;
504
 
                        buffer [2 * k + 1] = buffer [k] ;
505
 
                        } ;
506
 
                read_count *= 2 ;
507
 
                }
508
 
        else
509
 
                read_count = sf_read_float (audio_data->sndfile, buffer, sample_count) ;
510
 
 
511
 
        /* Fill the remainder with zeroes. */
512
 
        if (read_count < sample_count)
513
 
        {       if (audio_data->fake_stereo == 0)
514
 
                        memset (&(buffer [read_count]), 0, (sample_count - read_count) * sizeof (float)) ;
515
 
                /* Tell the main application to terminate. */
516
 
                audio_data->done_playing = SF_TRUE ;
517
 
                } ;
518
 
 
519
 
        return noErr ;
520
 
} /* macosx_audio_out_callback */
521
 
 
522
 
static void
523
 
macosx_play (int argc, char *argv [])
524
 
{       MacOSXAudioData         audio_data ;
525
 
        OSStatus        err ;
526
 
        UInt32          count, buffer_size ;
527
 
        int             k ;
528
 
 
529
 
        audio_data.fake_stereo = 0 ;
530
 
        audio_data.device = kAudioDeviceUnknown ;
531
 
 
532
 
        /*  get the default output device for the HAL */
533
 
        count = sizeof (AudioDeviceID) ;
534
 
        if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
535
 
                                &count, (void *) &(audio_data.device))) != noErr)
536
 
        {       printf ("AudioHardwareGetProperty (kAudioDevicePropertyDefaultOutputDevice) failed.\n") ;
537
 
                return ;
538
 
                } ;
539
 
 
540
 
        /*  get the buffersize that the default device uses for IO */
541
 
        count = sizeof (UInt32) ;
542
 
        if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyBufferSize,
543
 
                                &count, &buffer_size)) != noErr)
544
 
        {       printf ("AudioDeviceGetProperty (kAudioDevicePropertyBufferSize) failed.\n") ;
545
 
                return ;
546
 
                } ;
547
 
 
548
 
        /*  get a description of the data format used by the default device */
549
 
        count = sizeof (AudioStreamBasicDescription) ;
550
 
        if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyStreamFormat,
551
 
                                &count, &(audio_data.format))) != noErr)
552
 
        {       printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
553
 
                return ;
554
 
                } ;
555
 
 
556
 
        /* Base setup completed. Now play files. */
557
 
        for (k = 1 ; k < argc ; k++)
558
 
        {       printf ("Playing %s\n", argv [k]) ;
559
 
                if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo))))
560
 
                {       puts (sf_strerror (NULL)) ;
561
 
                        continue ;
562
 
                        } ;
563
 
 
564
 
                if (audio_data.sfinfo.channels < 1 || audio_data.sfinfo.channels > 2)
565
 
                {       printf ("Error : channels = %d.\n", audio_data.sfinfo.channels) ;
566
 
                        continue ;
567
 
                        } ;
568
 
 
569
 
                audio_data.format.mSampleRate = audio_data.sfinfo.samplerate ;
570
 
 
571
 
                if (audio_data.sfinfo.channels == 1)
572
 
                {       audio_data.format.mChannelsPerFrame = 2 ;
573
 
                        audio_data.fake_stereo = 1 ;
574
 
                        }
575
 
                else
576
 
                audio_data.format.mChannelsPerFrame = audio_data.sfinfo.channels ;
577
 
 
578
 
                if ((err = AudioDeviceSetProperty (audio_data.device, NULL, 0, false, kAudioDevicePropertyStreamFormat,
579
 
                                        sizeof (AudioStreamBasicDescription), &(audio_data.format))) != noErr)
580
 
                {       printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
581
 
                        return ;
582
 
                        } ;
583
 
 
584
 
                /*  we want linear pcm */
585
 
                if (audio_data.format.mFormatID != kAudioFormatLinearPCM)
586
 
                        return ;
587
 
 
588
 
                /* Fire off the device. */
589
 
                if ((err = AudioDeviceAddIOProc (audio_data.device, macosx_audio_out_callback,
590
 
                                (void *) &audio_data)) != noErr)
591
 
                {       printf ("AudioDeviceAddIOProc failed.\n") ;
592
 
                        return ;
593
 
                        } ;
594
 
 
595
 
                err = AudioDeviceStart (audio_data.device, macosx_audio_out_callback) ;
596
 
                if      (err != noErr)
597
 
                        return ;
598
 
 
599
 
                audio_data.done_playing = SF_FALSE ;
600
 
 
601
 
                while (audio_data.done_playing == SF_FALSE)
602
 
                        usleep (10 * 1000) ; /* 10 000 milliseconds. */
603
 
 
604
 
                if ((err = AudioDeviceStop (audio_data.device, macosx_audio_out_callback)) != noErr)
605
 
                {       printf ("AudioDeviceStop failed.\n") ;
606
 
                        return ;
607
 
                        } ;
608
 
 
609
 
                err = AudioDeviceRemoveIOProc (audio_data.device, macosx_audio_out_callback) ;
610
 
                if (err != noErr)
611
 
                {       printf ("AudioDeviceRemoveIOProc failed.\n") ;
612
 
                        return ;
613
 
                        } ;
614
 
 
615
 
                sf_close (audio_data.sndfile) ;
616
 
                } ;
617
 
 
618
 
        return ;
619
 
} /* macosx_play */
620
 
 
621
 
#endif /* MacOSX */
622
 
 
623
 
 
624
 
/*------------------------------------------------------------------------------
625
 
**      Win32 functions for playing a sound.
626
 
**
627
 
**      This API sucks. Its needlessly complicated and is *WAY* too loose with
628
 
**      passing pointers arounf in integers and and using char* pointers to
629
 
**  point to data instead of short*. It plain sucks!
630
 
*/
631
 
 
632
 
#if (OS_IS_WIN32 == 1)
633
 
 
634
 
#define WIN32_BUFFER_LEN        (1<<15)
635
 
 
636
 
typedef struct
637
 
{       HWAVEOUT        hwave ;
638
 
        WAVEHDR         whdr [2] ;
639
 
 
640
 
        CRITICAL_SECTION        mutex ;         /* to control access to BuffersInUSe */
641
 
        HANDLE          Event ;                 /* signal that a buffer is free */
642
 
 
643
 
        short           buffer [WIN32_BUFFER_LEN / sizeof (short)] ;
644
 
        int                     current, bufferlen ;
645
 
        int                     BuffersInUse ;
646
 
 
647
 
        SNDFILE         *sndfile ;
648
 
        SF_INFO         sfinfo ;
649
 
 
650
 
        sf_count_t      remaining ;
651
 
} Win32_Audio_Data ;
652
 
 
653
 
 
654
 
static void
655
 
win32_play_data (Win32_Audio_Data *audio_data)
656
 
{       int thisread, readcount ;
657
 
 
658
 
        /* fill a buffer if there is more data and we can read it sucessfully */
659
 
        readcount = (audio_data->remaining > audio_data->bufferlen) ? audio_data->bufferlen : (int) audio_data->remaining ;
660
 
 
661
 
        thisread = (int) sf_read_short (audio_data->sndfile, (short *) (audio_data->whdr [audio_data->current].lpData), readcount) ;
662
 
 
663
 
        audio_data->remaining -= thisread ;
664
 
 
665
 
        if (thisread > 0)
666
 
        {       /* Fix buffer length if this is only a partial block. */
667
 
                if (thisread < audio_data->bufferlen)
668
 
                        audio_data->whdr [audio_data->current].dwBufferLength = thisread * sizeof (short) ;
669
 
 
670
 
                /* Queue the WAVEHDR */
671
 
                waveOutWrite (audio_data->hwave, (LPWAVEHDR) &(audio_data->whdr [audio_data->current]), sizeof (WAVEHDR)) ;
672
 
 
673
 
                /* count another buffer in use */
674
 
                EnterCriticalSection (&audio_data->mutex) ;
675
 
                audio_data->BuffersInUse ++ ;
676
 
                LeaveCriticalSection (&audio_data->mutex) ;
677
 
 
678
 
                /* use the other buffer next time */
679
 
                audio_data->current = (audio_data->current + 1) % 2 ;
680
 
                } ;
681
 
 
682
 
        return ;
683
 
} /* win32_play_data */
684
 
 
685
 
static void CALLBACK
686
 
win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2)
687
 
{       Win32_Audio_Data        *audio_data ;
688
 
 
689
 
        /* Prevent compiler warnings. */
690
 
        hwave = hwave ;
691
 
        param1 = param2 ;
692
 
 
693
 
        if (data == 0)
694
 
                return ;
695
 
 
696
 
        /*
697
 
        ** I consider this technique of passing a pointer via an integer as
698
 
        ** fundamentally broken but thats the way microsoft has defined the
699
 
        ** interface.
700
 
        */
701
 
        audio_data = (Win32_Audio_Data*) data ;
702
 
 
703
 
        /* let main loop know a buffer is free */
704
 
        if (msg == MM_WOM_DONE)
705
 
        {       EnterCriticalSection (&audio_data->mutex) ;
706
 
                audio_data->BuffersInUse -- ;
707
 
                LeaveCriticalSection (&audio_data->mutex) ;
708
 
                SetEvent (audio_data->Event) ;
709
 
                } ;
710
 
 
711
 
        return ;
712
 
} /* win32_audio_out_callback */
713
 
 
714
 
/* This is needed for earlier versions of the M$ development tools. */
715
 
#ifndef DWORD_PTR
716
 
#define DWORD_PTR DWORD
717
 
#endif
718
 
 
719
 
static void
720
 
win32_play (int argc, char *argv [])
721
 
{       Win32_Audio_Data        audio_data ;
722
 
 
723
 
        WAVEFORMATEX wf ;
724
 
        int     k, error ;
725
 
 
726
 
        audio_data.sndfile = NULL ;
727
 
        audio_data.hwave = 0 ;
728
 
 
729
 
        for (k = 1 ; k < argc ; k++)
730
 
        {       printf ("Playing %s\n", argv [k]) ;
731
 
 
732
 
                if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo))))
733
 
                {       puts (sf_strerror (NULL)) ;
734
 
                        continue ;
735
 
                        } ;
736
 
 
737
 
                audio_data.remaining = audio_data.sfinfo.frames * audio_data.sfinfo.channels ;
738
 
                audio_data.current = 0 ;
739
 
 
740
 
                InitializeCriticalSection (&audio_data.mutex) ;
741
 
                audio_data.Event = CreateEvent (0, FALSE, FALSE, 0) ;
742
 
 
743
 
                wf.nChannels = audio_data.sfinfo.channels ;
744
 
                wf.wFormatTag = WAVE_FORMAT_PCM ;
745
 
                wf.cbSize = 0 ;
746
 
                wf.wBitsPerSample = 16 ;
747
 
 
748
 
                wf.nSamplesPerSec = audio_data.sfinfo.samplerate ;
749
 
 
750
 
                wf.nBlockAlign = audio_data.sfinfo.channels * sizeof (short) ;
751
 
 
752
 
                wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ;
753
 
 
754
 
                error = waveOutOpen (&(audio_data.hwave), WAVE_MAPPER, &wf, (DWORD_PTR) win32_audio_out_callback,
755
 
                                                        (DWORD_PTR) &audio_data, CALLBACK_FUNCTION) ;
756
 
                if (error)
757
 
                {       puts ("waveOutOpen failed.") ;
758
 
                        audio_data.hwave = 0 ;
759
 
                        continue ;
760
 
                        } ;
761
 
 
762
 
                audio_data.whdr [0].lpData = (char*) audio_data.buffer ;
763
 
                audio_data.whdr [1].lpData = ((char*) audio_data.buffer) + sizeof (audio_data.buffer) / 2 ;
764
 
 
765
 
                audio_data.whdr [0].dwBufferLength = sizeof (audio_data.buffer) / 2 ;
766
 
                audio_data.whdr [1].dwBufferLength = sizeof (audio_data.buffer) / 2 ;
767
 
 
768
 
                audio_data.whdr [0].dwFlags = 0 ;
769
 
                audio_data.whdr [1].dwFlags = 0 ;
770
 
 
771
 
                /* length of each audio buffer in samples */
772
 
                audio_data.bufferlen = sizeof (audio_data.buffer) / 2 / sizeof (short) ;
773
 
 
774
 
                /* Prepare the WAVEHDRs */
775
 
                if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR))))
776
 
                {       printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ;
777
 
                        waveOutClose (audio_data.hwave) ;
778
 
                        continue ;
779
 
                        } ;
780
 
 
781
 
                if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR))))
782
 
                {       printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ;
783
 
                        waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ;
784
 
                        waveOutClose (audio_data.hwave) ;
785
 
                        continue ;
786
 
                        } ;
787
 
 
788
 
                /* Fill up both buffers with audio data */
789
 
                audio_data.BuffersInUse = 0 ;
790
 
                win32_play_data (&audio_data) ;
791
 
                win32_play_data (&audio_data) ;
792
 
 
793
 
                /* loop until both buffers are released */
794
 
                while (audio_data.BuffersInUse > 0)
795
 
                {
796
 
                        /* wait for buffer to be released */
797
 
                        WaitForSingleObject (audio_data.Event, INFINITE) ;
798
 
 
799
 
                        /* refill the buffer if there is more data to play */
800
 
                        win32_play_data (&audio_data) ;
801
 
                        } ;
802
 
 
803
 
                waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ;
804
 
                waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)) ;
805
 
 
806
 
                waveOutClose (audio_data.hwave) ;
807
 
                audio_data.hwave = 0 ;
808
 
 
809
 
                DeleteCriticalSection (&audio_data.mutex) ;
810
 
 
811
 
                sf_close (audio_data.sndfile) ;
812
 
                } ;
813
 
 
814
 
} /* win32_play */
815
 
 
816
 
#endif /* Win32 */
817
 
 
818
 
/*------------------------------------------------------------------------------
819
 
**      Solaris.
820
 
*/
821
 
 
822
 
#if (defined (sun) && defined (unix)) /* ie Solaris */
823
 
 
824
 
static void
825
 
solaris_play (int argc, char *argv [])
826
 
{       static short    buffer [BUFFER_LEN] ;
827
 
        audio_info_t    audio_info ;
828
 
        SNDFILE                 *sndfile ;
829
 
        SF_INFO                 sfinfo ;
830
 
        unsigned long   delay_time ;
831
 
        long                    k, start_count, output_count, write_count, read_count ;
832
 
        int                             audio_fd, error, done ;
833
 
 
834
 
        for (k = 1 ; k < argc ; k++)
835
 
        {       printf ("Playing %s\n", argv [k]) ;
836
 
                if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
837
 
                {       puts (sf_strerror (NULL)) ;
838
 
                        continue ;
839
 
                        } ;
840
 
 
841
 
                if (sfinfo.channels < 1 || sfinfo.channels > 2)
842
 
                {       printf ("Error : channels = %d.\n", sfinfo.channels) ;
843
 
                        continue ;
844
 
                        } ;
845
 
 
846
 
                /* open the audio device - write only, non-blocking */
847
 
                if ((audio_fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0)
848
 
                {       perror ("open (/dev/audio) failed") ;
849
 
                        return ;
850
 
                        } ;
851
 
 
852
 
                /*      Retrive standard values. */
853
 
                AUDIO_INITINFO (&audio_info) ;
854
 
 
855
 
                audio_info.play.sample_rate = sfinfo.samplerate ;
856
 
                audio_info.play.channels = sfinfo.channels ;
857
 
                audio_info.play.precision = 16 ;
858
 
                audio_info.play.encoding = AUDIO_ENCODING_LINEAR ;
859
 
                audio_info.play.gain = AUDIO_MAX_GAIN ;
860
 
                audio_info.play.balance = AUDIO_MID_BALANCE ;
861
 
 
862
 
                if ((error = ioctl (audio_fd, AUDIO_SETINFO, &audio_info)))
863
 
                {       perror ("ioctl (AUDIO_SETINFO) failed") ;
864
 
                        return ;
865
 
                        } ;
866
 
 
867
 
                /* Delay time equal to 1/4 of a buffer in microseconds. */
868
 
                delay_time = (BUFFER_LEN * 1000000) / (audio_info.play.sample_rate * 4) ;
869
 
 
870
 
                done = 0 ;
871
 
                while (! done)
872
 
                {       read_count = sf_read_short (sndfile, buffer, BUFFER_LEN) ;
873
 
                        if (read_count < BUFFER_LEN)
874
 
                        {       memset (&(buffer [read_count]), 0, (BUFFER_LEN - read_count) * sizeof (short)) ;
875
 
                                /* Tell the main application to terminate. */
876
 
                                done = SF_TRUE ;
877
 
                                } ;
878
 
 
879
 
                        start_count = 0 ;
880
 
                        output_count = BUFFER_LEN * sizeof (short) ;
881
 
 
882
 
                        while (output_count > 0)
883
 
                        {       /* write as much data as possible */
884
 
                                write_count = write (audio_fd, &(buffer [start_count]), output_count) ;
885
 
                                if (write_count > 0)
886
 
                                {       output_count -= write_count ;
887
 
                                        start_count += write_count ;
888
 
                                        }
889
 
                                else
890
 
                                {       /*      Give the audio output time to catch up. */
891
 
                                        usleep (delay_time) ;
892
 
                                        } ;
893
 
                                } ; /* while (outpur_count > 0) */
894
 
                        } ; /* while (! done) */
895
 
 
896
 
                close (audio_fd) ;
897
 
                } ;
898
 
 
899
 
        return ;
900
 
} /* solaris_play */
901
 
 
902
 
#endif /* Solaris */
903
 
 
904
 
/*==============================================================================
905
 
**      Main function.
906
 
*/
907
 
 
908
 
int
909
 
main (int argc, char *argv [])
910
 
{
911
 
        if (argc < 2)
912
 
        {
913
 
                printf ("\nUsage : %s <input sound file>\n\n", argv [0]) ;
914
 
#if (OS_IS_WIN32 == 1)
915
 
                printf ("This is a Unix style command line application which\n"
916
 
                                "should be run in a MSDOS box or Command Shell window.\n\n") ;
917
 
                printf ("Sleeping for 5 seconds before exiting.\n\n") ;
918
 
 
919
 
                /* This is the officially blessed by microsoft way but I can't get
920
 
                ** it to link.
921
 
                **     Sleep (15) ;
922
 
                ** Instead, use this:
923
 
                */
924
 
                _sleep (5 * 1000) ;
925
 
#endif
926
 
                return 1 ;
927
 
                } ;
928
 
 
929
 
#if defined (__linux__)
930
 
        #if HAVE_ALSA_ASOUNDLIB_H
931
 
                if (access ("/proc/asound/cards", R_OK) == 0)
932
 
                        alsa_play (argc, argv) ;
933
 
                else
934
 
        #endif
935
 
                linux_play (argc, argv) ;
936
 
#elif (defined (__MACH__) && defined (__APPLE__))
937
 
        macosx_play (argc, argv) ;
938
 
#elif (defined (sun) && defined (unix))
939
 
        solaris_play (argc, argv) ;
940
 
#elif (OS_IS_WIN32 == 1)
941
 
        win32_play (argc, argv) ;
942
 
#elif defined (__BEOS__)
943
 
        printf ("This program cannot be compiled on BeOS.\n") ;
944
 
        printf ("Instead, compile the file sfplay_beos.cpp.\n") ;
945
 
        return 1 ;
946
 
#else
947
 
        puts ("*** Playing sound not yet supported on this platform.") ;
948
 
        puts ("*** Please feel free to submit a patch.") ;
949
 
        return 1 ;
950
 
#endif
951
 
 
952
 
        return 0 ;
953
 
} /* main */
954
 
/*
955
 
** Do not edit or modify anything in this comment block.
956
 
** The arch-tag line is a file identity tag for the GNU Arch
957
 
** revision control system.
958
 
**
959
 
** arch-tag: 8fc4110d-6cec-4e03-91df-0f384cabedac
960
 
*/