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