annotate src/libsndfile-1.0.25/programs/sndfile-play.c @ 83:ae30d91d2ffe

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