2 ** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
4 ** All rights reserved.
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions are
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
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.
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.
48 #if HAVE_ALSA_ASOUNDLIB_H
49 #define ALSA_PCM_NEW_HW_PARAMS_API
50 #define ALSA_PCM_NEW_SW_PARAMS_API
51 #include <alsa/asoundlib.h>
55 #if defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__)
57 #include <sys/ioctl.h>
58 #include <sys/soundcard.h>
60 #elif (defined (__MACH__) && defined (__APPLE__))
62 #include <CoreAudio/AudioHardware.h>
64 #elif defined (HAVE_SNDIO_H)
67 #elif (defined (sun) && defined (unix))
69 #include <sys/ioctl.h>
70 #include <sys/audioio.h>
72 #elif (OS_IS_WIN32 == 1)
78 #define SIGNED_SIZEOF(x) ((int) sizeof (x))
79 #define BUFFER_LEN (2048)
81 /*------------------------------------------------------------------------------
82 ** Linux/OSS functions for playing a sound.
85 #if HAVE_ALSA_ASOUNDLIB_H
87 static snd_pcm_t
* alsa_open (int channels
, unsigned srate
, int realtime
) ;
88 static int alsa_write_float (snd_pcm_t
*alsa_dev
, float *data
, int frames
, int channels
) ;
91 alsa_play (int argc
, char *argv
[])
92 { static float buffer
[BUFFER_LEN
] ;
95 snd_pcm_t
* alsa_dev
;
96 int k
, readcount
, subformat
;
98 for (k
= 1 ; k
< argc
; k
++)
99 { memset (&sfinfo
, 0, sizeof (sfinfo
)) ;
101 printf ("Playing %s\n", argv
[k
]) ;
102 if (! (sndfile
= sf_open (argv
[k
], SFM_READ
, &sfinfo
)))
103 { puts (sf_strerror (NULL
)) ;
107 if (sfinfo
.channels
< 1 || sfinfo
.channels
> 2)
108 { printf ("Error : channels = %d.\n", sfinfo
.channels
) ;
112 if ((alsa_dev
= alsa_open (sfinfo
.channels
, (unsigned) sfinfo
.samplerate
, SF_FALSE
)) == NULL
)
115 subformat
= sfinfo
.format
& SF_FORMAT_SUBMASK
;
117 if (subformat
== SF_FORMAT_FLOAT
|| subformat
== SF_FORMAT_DOUBLE
)
121 sf_command (sndfile
, SFC_CALC_SIGNAL_MAX
, &scale
, sizeof (scale
)) ;
125 scale
= 32700.0 / scale
;
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
) ;
134 { while ((readcount
= sf_read_float (sndfile
, buffer
, BUFFER_LEN
)))
135 alsa_write_float (alsa_dev
, buffer
, BUFFER_LEN
/ sfinfo
.channels
, sfinfo
.channels
) ;
138 snd_pcm_drain (alsa_dev
) ;
139 snd_pcm_close (alsa_dev
) ;
148 alsa_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
;
159 { alsa_period_size
= 256 ;
160 alsa_buffer_frames
= 3 * alsa_period_size
;
163 { alsa_period_size
= 1024 ;
164 alsa_buffer_frames
= 4 * alsa_period_size
;
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
)) ;
172 snd_pcm_nonblock (alsa_dev
, 0) ;
174 if ((err
= snd_pcm_hw_params_malloc (&hw_params
)) < 0)
175 { fprintf (stderr
, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err
)) ;
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
)) ;
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
)) ;
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
)) ;
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
)) ;
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
)) ;
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
)) ;
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
)) ;
214 if ((err
= snd_pcm_hw_params (alsa_dev
, hw_params
)) < 0)
215 { fprintf (stderr
, "cannot set parameters (%s)\n", snd_strerror (err
)) ;
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
) ;
227 snd_pcm_hw_params_free (hw_params
) ;
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
)) ;
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
)) ;
239 /* note: set start threshold to delay start until the ring buffer is full */
240 snd_pcm_sw_params_current (alsa_dev
, sw_params
) ;
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
)) ;
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
)) ;
252 snd_pcm_sw_params_free (sw_params
) ;
254 snd_pcm_reset (alsa_dev
) ;
258 if (err
< 0 && alsa_dev
!= NULL
)
259 { snd_pcm_close (alsa_dev
) ;
267 alsa_write_float (snd_pcm_t
*alsa_dev
, float *data
, int frames
, int channels
)
268 { static int epipe_count
= 0 ;
276 while (total
< frames
)
277 { retval
= snd_pcm_writei (alsa_dev
, data
+ total
* channels
, frames
- total
) ;
289 puts ("alsa_write_float: EAGAIN") ;
295 { printf ("alsa_write_float: EPIPE %d\n", epipe_count
) ;
296 if (epipe_count
> 140)
303 { snd_pcm_status_t
*status
;
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
;
311 gettimeofday (&now
, 0) ;
312 snd_pcm_status_get_trigger_tstamp (status
, &tstamp
) ;
313 timersub (&now
, &tstamp
, &diff
) ;
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) ;
319 fprintf (stderr
, "alsa_write_float: xrun. can't determine length\n") ;
323 snd_pcm_prepare (alsa_dev
) ;
327 fprintf (stderr
, "alsa_write_float: Bad PCM state.n") ;
332 fprintf (stderr
, "alsa_write_float: Suspend event.n") ;
337 puts ("alsa_write_float: EIO") ;
341 fprintf (stderr
, "alsa_write_float: retval = %d\n", retval
) ;
348 } /* alsa_write_float */
350 #endif /* HAVE_ALSA_ASOUNDLIB_H */
352 /*------------------------------------------------------------------------------
353 ** Linux/OSS functions for playing a sound.
356 #if defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__)
358 static int opensoundsys_open_device (int channels
, int srate
) ;
361 opensoundsys_play (int argc
, char *argv
[])
362 { static short buffer
[BUFFER_LEN
] ;
365 int k
, audio_device
, readcount
, writecount
, subformat
;
367 for (k
= 1 ; k
< argc
; k
++)
368 { memset (&sfinfo
, 0, sizeof (sfinfo
)) ;
370 printf ("Playing %s\n", argv
[k
]) ;
371 if (! (sndfile
= sf_open (argv
[k
], SFM_READ
, &sfinfo
)))
372 { puts (sf_strerror (NULL
)) ;
376 if (sfinfo
.channels
< 1 || sfinfo
.channels
> 2)
377 { printf ("Error : channels = %d.\n", sfinfo
.channels
) ;
381 audio_device
= opensoundsys_open_device (sfinfo
.channels
, sfinfo
.samplerate
) ;
383 subformat
= sfinfo
.format
& SF_FORMAT_SUBMASK
;
385 if (subformat
== SF_FORMAT_FLOAT
|| subformat
== SF_FORMAT_DOUBLE
)
386 { static float float_buffer
[BUFFER_LEN
] ;
390 sf_command (sndfile
, SFC_CALC_SIGNAL_MAX
, &scale
, sizeof (scale
)) ;
394 scale
= 32700.0 / scale
;
396 while ((readcount
= sf_read_float (sndfile
, float_buffer
, BUFFER_LEN
)))
397 { for (m
= 0 ; m
< readcount
; m
++)
398 buffer
[m
] = scale
* float_buffer
[m
] ;
399 writecount
= write (audio_device
, buffer
, readcount
* sizeof (short)) ;
403 { while ((readcount
= sf_read_short (sndfile
, buffer
, BUFFER_LEN
)))
404 writecount
= write (audio_device
, buffer
, readcount
* sizeof (short)) ;
407 if (ioctl (audio_device
, SNDCTL_DSP_POST
, 0) == -1)
408 perror ("ioctl (SNDCTL_DSP_POST) ") ;
410 if (ioctl (audio_device
, SNDCTL_DSP_SYNC
, 0) == -1)
411 perror ("ioctl (SNDCTL_DSP_SYNC) ") ;
413 close (audio_device
) ;
419 } /* opensoundsys_play */
422 opensoundsys_open_device (int channels
, int srate
)
423 { int fd
, stereo
, fmt
;
425 if ((fd
= open ("/dev/dsp", O_WRONLY
, 0)) == -1 &&
426 (fd
= open ("/dev/sound/dsp", O_WRONLY
, 0)) == -1)
427 { perror ("opensoundsys_open_device : open ") ;
432 if (ioctl (fd
, SNDCTL_DSP_STEREO
, &stereo
) == -1)
434 perror ("opensoundsys_open_device : stereo ") ;
438 if (ioctl (fd
, SNDCTL_DSP_RESET
, 0))
439 { perror ("opensoundsys_open_device : reset ") ;
443 fmt
= CPU_IS_BIG_ENDIAN
? AFMT_S16_BE
: AFMT_S16_LE
;
444 if (ioctl (fd
, SNDCTL_DSP_SETFMT
, &fmt
) != 0)
445 { perror ("opensoundsys_open_device : set format ") ;
449 if (ioctl (fd
, SNDCTL_DSP_CHANNELS
, &channels
) != 0)
450 { perror ("opensoundsys_open_device : channels ") ;
454 if (ioctl (fd
, SNDCTL_DSP_SPEED
, &srate
) != 0)
455 { perror ("opensoundsys_open_device : sample rate ") ;
459 if (ioctl (fd
, SNDCTL_DSP_SYNC
, 0) != 0)
460 { perror ("opensoundsys_open_device : sync ") ;
465 } /* opensoundsys_open_device */
467 #endif /* __linux__ */
469 /*------------------------------------------------------------------------------
470 ** Mac OS X functions for playing a sound.
473 #if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
476 { AudioStreamBasicDescription format
;
479 AudioDeviceID device
;
491 macosx_audio_out_callback (AudioDeviceID device
, const AudioTimeStamp
* current_time
,
492 const AudioBufferList
* data_in
, const AudioTimeStamp
* time_in
,
493 AudioBufferList
* data_out
, const AudioTimeStamp
* time_out
,
495 { MacOSXAudioData
*audio_data
;
496 int size
, sample_count
, read_count
, k
;
499 /* Prevent compiler warnings. */
501 current_time
= current_time
;
504 time_out
= time_out
;
506 audio_data
= (MacOSXAudioData
*) client_data
;
508 size
= data_out
->mBuffers
[0].mDataByteSize
;
509 sample_count
= size
/ sizeof (float) ;
511 buffer
= (float*) data_out
->mBuffers
[0].mData
;
513 if (audio_data
->fake_stereo
!= 0)
514 { read_count
= sf_read_float (audio_data
->sndfile
, buffer
, sample_count
/ 2) ;
516 for (k
= read_count
- 1 ; k
>= 0 ; k
--)
517 { buffer
[2 * k
] = buffer
[k
] ;
518 buffer
[2 * k
+ 1] = buffer
[k
] ;
523 read_count
= sf_read_float (audio_data
->sndfile
, buffer
, sample_count
) ;
525 /* Fill the remainder with zeroes. */
526 if (read_count
< sample_count
)
527 { if (audio_data
->fake_stereo
== 0)
528 memset (&(buffer
[read_count
]), 0, (sample_count
- read_count
) * sizeof (float)) ;
529 /* Tell the main application to terminate. */
530 audio_data
->done_playing
= SF_TRUE
;
534 } /* macosx_audio_out_callback */
537 macosx_play (int argc
, char *argv
[])
538 { MacOSXAudioData audio_data
;
540 UInt32 count
, buffer_size
;
543 audio_data
.fake_stereo
= 0 ;
544 audio_data
.device
= kAudioDeviceUnknown
;
546 /* get the default output device for the HAL */
547 count
= sizeof (AudioDeviceID
) ;
548 if ((err
= AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice
,
549 &count
, (void *) &(audio_data
.device
))) != noErr
)
550 { printf ("AudioHardwareGetProperty (kAudioDevicePropertyDefaultOutputDevice) failed.\n") ;
554 /* get the buffersize that the default device uses for IO */
555 count
= sizeof (UInt32
) ;
556 if ((err
= AudioDeviceGetProperty (audio_data
.device
, 0, false, kAudioDevicePropertyBufferSize
,
557 &count
, &buffer_size
)) != noErr
)
558 { printf ("AudioDeviceGetProperty (kAudioDevicePropertyBufferSize) failed.\n") ;
562 /* get a description of the data format used by the default device */
563 count
= sizeof (AudioStreamBasicDescription
) ;
564 if ((err
= AudioDeviceGetProperty (audio_data
.device
, 0, false, kAudioDevicePropertyStreamFormat
,
565 &count
, &(audio_data
.format
))) != noErr
)
566 { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
570 /* Base setup completed. Now play files. */
571 for (k
= 1 ; k
< argc
; k
++)
572 { printf ("Playing %s\n", argv
[k
]) ;
573 if (! (audio_data
.sndfile
= sf_open (argv
[k
], SFM_READ
, &(audio_data
.sfinfo
))))
574 { puts (sf_strerror (NULL
)) ;
578 if (audio_data
.sfinfo
.channels
< 1 || audio_data
.sfinfo
.channels
> 2)
579 { printf ("Error : channels = %d.\n", audio_data
.sfinfo
.channels
) ;
583 audio_data
.format
.mSampleRate
= audio_data
.sfinfo
.samplerate
;
585 if (audio_data
.sfinfo
.channels
== 1)
586 { audio_data
.format
.mChannelsPerFrame
= 2 ;
587 audio_data
.fake_stereo
= 1 ;
590 audio_data
.format
.mChannelsPerFrame
= audio_data
.sfinfo
.channels
;
592 if ((err
= AudioDeviceSetProperty (audio_data
.device
, NULL
, 0, false, kAudioDevicePropertyStreamFormat
,
593 sizeof (AudioStreamBasicDescription
), &(audio_data
.format
))) != noErr
)
594 { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
598 /* we want linear pcm */
599 if (audio_data
.format
.mFormatID
!= kAudioFormatLinearPCM
)
602 /* Fire off the device. */
603 if ((err
= AudioDeviceAddIOProc (audio_data
.device
, macosx_audio_out_callback
,
604 (void *) &audio_data
)) != noErr
)
605 { printf ("AudioDeviceAddIOProc failed.\n") ;
609 err
= AudioDeviceStart (audio_data
.device
, macosx_audio_out_callback
) ;
613 audio_data
.done_playing
= SF_FALSE
;
615 while (audio_data
.done_playing
== SF_FALSE
)
616 usleep (10 * 1000) ; /* 10 000 milliseconds. */
618 if ((err
= AudioDeviceStop (audio_data
.device
, macosx_audio_out_callback
)) != noErr
)
619 { printf ("AudioDeviceStop failed.\n") ;
623 err
= AudioDeviceRemoveIOProc (audio_data
.device
, macosx_audio_out_callback
) ;
625 { printf ("AudioDeviceRemoveIOProc failed.\n") ;
629 sf_close (audio_data
.sndfile
) ;
638 /*------------------------------------------------------------------------------
639 ** Win32 functions for playing a sound.
641 ** This API sucks. Its needlessly complicated and is *WAY* too loose with
642 ** passing pointers arounf in integers and and using char* pointers to
643 ** point to data instead of short*. It plain sucks!
646 #if (OS_IS_WIN32 == 1)
648 #define WIN32_BUFFER_LEN (1<<15)
654 CRITICAL_SECTION mutex
; /* to control access to BuffersInUSe */
655 HANDLE Event
; /* signal that a buffer is free */
657 short buffer
[WIN32_BUFFER_LEN
/ sizeof (short)] ;
658 int current
, bufferlen
;
664 sf_count_t remaining
;
669 win32_play_data (Win32_Audio_Data
*audio_data
)
670 { int thisread
, readcount
;
672 /* fill a buffer if there is more data and we can read it sucessfully */
673 readcount
= (audio_data
->remaining
> audio_data
->bufferlen
) ? audio_data
->bufferlen
: (int) audio_data
->remaining
;
675 thisread
= (int) sf_read_short (audio_data
->sndfile
, (short *) (audio_data
->whdr
[audio_data
->current
].lpData
), readcount
) ;
677 audio_data
->remaining
-= thisread
;
680 { /* Fix buffer length if this is only a partial block. */
681 if (thisread
< audio_data
->bufferlen
)
682 audio_data
->whdr
[audio_data
->current
].dwBufferLength
= thisread
* sizeof (short) ;
684 /* Queue the WAVEHDR */
685 waveOutWrite (audio_data
->hwave
, (LPWAVEHDR
) &(audio_data
->whdr
[audio_data
->current
]), sizeof (WAVEHDR
)) ;
687 /* count another buffer in use */
688 EnterCriticalSection (&audio_data
->mutex
) ;
689 audio_data
->BuffersInUse
++ ;
690 LeaveCriticalSection (&audio_data
->mutex
) ;
692 /* use the other buffer next time */
693 audio_data
->current
= (audio_data
->current
+ 1) % 2 ;
697 } /* win32_play_data */
700 win32_audio_out_callback (HWAVEOUT hwave
, UINT msg
, DWORD_PTR data
, DWORD param1
, DWORD param2
)
701 { Win32_Audio_Data
*audio_data
;
703 /* Prevent compiler warnings. */
711 ** I consider this technique of passing a pointer via an integer as
712 ** fundamentally broken but thats the way microsoft has defined the
715 audio_data
= (Win32_Audio_Data
*) data
;
717 /* let main loop know a buffer is free */
718 if (msg
== MM_WOM_DONE
)
719 { EnterCriticalSection (&audio_data
->mutex
) ;
720 audio_data
->BuffersInUse
-- ;
721 LeaveCriticalSection (&audio_data
->mutex
) ;
722 SetEvent (audio_data
->Event
) ;
726 } /* win32_audio_out_callback */
729 win32_play (int argc
, char *argv
[])
730 { Win32_Audio_Data audio_data
;
735 audio_data
.sndfile
= NULL
;
736 audio_data
.hwave
= 0 ;
738 for (k
= 1 ; k
< argc
; k
++)
739 { printf ("Playing %s\n", argv
[k
]) ;
741 if (! (audio_data
.sndfile
= sf_open (argv
[k
], SFM_READ
, &(audio_data
.sfinfo
))))
742 { puts (sf_strerror (NULL
)) ;
746 audio_data
.remaining
= audio_data
.sfinfo
.frames
* audio_data
.sfinfo
.channels
;
747 audio_data
.current
= 0 ;
749 InitializeCriticalSection (&audio_data
.mutex
) ;
750 audio_data
.Event
= CreateEvent (0, FALSE
, FALSE
, 0) ;
752 wf
.nChannels
= audio_data
.sfinfo
.channels
;
753 wf
.wFormatTag
= WAVE_FORMAT_PCM
;
755 wf
.wBitsPerSample
= 16 ;
757 wf
.nSamplesPerSec
= audio_data
.sfinfo
.samplerate
;
759 wf
.nBlockAlign
= audio_data
.sfinfo
.channels
* sizeof (short) ;
761 wf
.nAvgBytesPerSec
= wf
.nBlockAlign
* wf
.nSamplesPerSec
;
763 error
= waveOutOpen (&(audio_data
.hwave
), WAVE_MAPPER
, &wf
, (DWORD_PTR
) win32_audio_out_callback
,
764 (DWORD_PTR
) &audio_data
, CALLBACK_FUNCTION
) ;
766 { puts ("waveOutOpen failed.") ;
767 audio_data
.hwave
= 0 ;
771 audio_data
.whdr
[0].lpData
= (char*) audio_data
.buffer
;
772 audio_data
.whdr
[1].lpData
= ((char*) audio_data
.buffer
) + sizeof (audio_data
.buffer
) / 2 ;
774 audio_data
.whdr
[0].dwBufferLength
= sizeof (audio_data
.buffer
) / 2 ;
775 audio_data
.whdr
[1].dwBufferLength
= sizeof (audio_data
.buffer
) / 2 ;
777 audio_data
.whdr
[0].dwFlags
= 0 ;
778 audio_data
.whdr
[1].dwFlags
= 0 ;
780 /* length of each audio buffer in samples */
781 audio_data
.bufferlen
= sizeof (audio_data
.buffer
) / 2 / sizeof (short) ;
783 /* Prepare the WAVEHDRs */
784 if ((error
= waveOutPrepareHeader (audio_data
.hwave
, &(audio_data
.whdr
[0]), sizeof (WAVEHDR
))))
785 { printf ("waveOutPrepareHeader [0] failed : %08X\n", error
) ;
786 waveOutClose (audio_data
.hwave
) ;
790 if ((error
= waveOutPrepareHeader (audio_data
.hwave
, &(audio_data
.whdr
[1]), sizeof (WAVEHDR
))))
791 { printf ("waveOutPrepareHeader [1] failed : %08X\n", error
) ;
792 waveOutUnprepareHeader (audio_data
.hwave
, &(audio_data
.whdr
[0]), sizeof (WAVEHDR
)) ;
793 waveOutClose (audio_data
.hwave
) ;
797 /* Fill up both buffers with audio data */
798 audio_data
.BuffersInUse
= 0 ;
799 win32_play_data (&audio_data
) ;
800 win32_play_data (&audio_data
) ;
802 /* loop until both buffers are released */
803 while (audio_data
.BuffersInUse
> 0)
805 /* wait for buffer to be released */
806 WaitForSingleObject (audio_data
.Event
, INFINITE
) ;
808 /* refill the buffer if there is more data to play */
809 win32_play_data (&audio_data
) ;
812 waveOutUnprepareHeader (audio_data
.hwave
, &(audio_data
.whdr
[0]), sizeof (WAVEHDR
)) ;
813 waveOutUnprepareHeader (audio_data
.hwave
, &(audio_data
.whdr
[1]), sizeof (WAVEHDR
)) ;
815 waveOutClose (audio_data
.hwave
) ;
816 audio_data
.hwave
= 0 ;
818 DeleteCriticalSection (&audio_data
.mutex
) ;
820 sf_close (audio_data
.sndfile
) ;
827 /*------------------------------------------------------------------------------
831 #if defined (HAVE_SNDIO_H)
834 sndio_play (int argc
, char *argv
[])
835 { struct sio_hdl
*hdl
;
837 short buffer
[BUFFER_LEN
] ;
842 for (k
= 1 ; k
< argc
; k
++)
843 { printf ("Playing %s\n", argv
[k
]) ;
844 if (! (sndfile
= sf_open (argv
[k
], SFM_READ
, &sfinfo
)))
845 { puts (sf_strerror (NULL
)) ;
849 if (sfinfo
.channels
< 1 || sfinfo
.channels
> 2)
850 { printf ("Error : channels = %d.\n", sfinfo
.channels
) ;
854 if ((hdl
= sio_open (NULL
, SIO_PLAY
, 0)) == NULL
)
855 { fprintf (stderr
, "open sndio device failed") ;
860 par
.rate
= sfinfo
.samplerate
;
861 par
.pchan
= sfinfo
.channels
;
864 par
.le
= SIO_LE_NATIVE
;
866 if (! sio_setpar (hdl
, &par
) || ! sio_getpar (hdl
, &par
))
867 { fprintf (stderr
, "set sndio params failed") ;
871 if (! sio_start (hdl
))
872 { fprintf (stderr
, "sndio start failed") ;
876 while ((readcount
= sf_read_short (sndfile
, buffer
, BUFFER_LEN
)))
877 sio_write (hdl
, buffer
, readcount
* sizeof (short)) ;
887 /*------------------------------------------------------------------------------
891 #if (defined (sun) && defined (unix)) /* ie Solaris */
894 solaris_play (int argc
, char *argv
[])
895 { static short buffer
[BUFFER_LEN
] ;
896 audio_info_t audio_info
;
899 unsigned long delay_time
;
900 long k
, start_count
, output_count
, write_count
, read_count
;
901 int audio_fd
, error
, done
;
903 for (k
= 1 ; k
< argc
; k
++)
904 { printf ("Playing %s\n", argv
[k
]) ;
905 if (! (sndfile
= sf_open (argv
[k
], SFM_READ
, &sfinfo
)))
906 { puts (sf_strerror (NULL
)) ;
910 if (sfinfo
.channels
< 1 || sfinfo
.channels
> 2)
911 { printf ("Error : channels = %d.\n", sfinfo
.channels
) ;
915 /* open the audio device - write only, non-blocking */
916 if ((audio_fd
= open ("/dev/audio", O_WRONLY
| O_NONBLOCK
)) < 0)
917 { perror ("open (/dev/audio) failed") ;
921 /* Retrive standard values. */
922 AUDIO_INITINFO (&audio_info
) ;
924 audio_info
.play
.sample_rate
= sfinfo
.samplerate
;
925 audio_info
.play
.channels
= sfinfo
.channels
;
926 audio_info
.play
.precision
= 16 ;
927 audio_info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
928 audio_info
.play
.gain
= AUDIO_MAX_GAIN
;
929 audio_info
.play
.balance
= AUDIO_MID_BALANCE
;
931 if ((error
= ioctl (audio_fd
, AUDIO_SETINFO
, &audio_info
)))
932 { perror ("ioctl (AUDIO_SETINFO) failed") ;
936 /* Delay time equal to 1/4 of a buffer in microseconds. */
937 delay_time
= (BUFFER_LEN
* 1000000) / (audio_info
.play
.sample_rate
* 4) ;
941 { read_count
= sf_read_short (sndfile
, buffer
, BUFFER_LEN
) ;
942 if (read_count
< BUFFER_LEN
)
943 { memset (&(buffer
[read_count
]), 0, (BUFFER_LEN
- read_count
) * sizeof (short)) ;
944 /* Tell the main application to terminate. */
949 output_count
= BUFFER_LEN
* sizeof (short) ;
951 while (output_count
> 0)
952 { /* write as much data as possible */
953 write_count
= write (audio_fd
, &(buffer
[start_count
]), output_count
) ;
955 { output_count
-= write_count
;
956 start_count
+= write_count
;
959 { /* Give the audio output time to catch up. */
960 usleep (delay_time
) ;
962 } ; /* while (outpur_count > 0) */
963 } ; /* while (! done) */
973 /*==============================================================================
978 main (int argc
, char *argv
[])
982 printf ("\nUsage : %s <input sound file>\n\n", program_name (argv
[0])) ;
983 printf (" Using %s.\n\n", sf_version_string ()) ;
984 #if (OS_IS_WIN32 == 1)
985 printf ("This is a Unix style command line application which\n"
986 "should be run in a MSDOS box or Command Shell window.\n\n") ;
987 printf ("Sleeping for 5 seconds before exiting.\n\n") ;
994 #if defined (__linux__)
995 #if HAVE_ALSA_ASOUNDLIB_H
996 if (access ("/proc/asound/cards", R_OK
) == 0)
997 alsa_play (argc
, argv
) ;
1000 opensoundsys_play (argc
, argv
) ;
1001 #elif defined (__FreeBSD_kernel__) || defined (__FreeBSD__)
1002 opensoundsys_play (argc
, argv
) ;
1003 #elif (defined (__MACH__) && defined (__APPLE__))
1004 macosx_play (argc
, argv
) ;
1005 #elif defined HAVE_SNDIO_H
1006 sndio_play (argc
, argv
) ;
1007 #elif (defined (sun) && defined (unix))
1008 solaris_play (argc
, argv
) ;
1009 #elif (OS_IS_WIN32 == 1)
1010 win32_play (argc
, argv
) ;
1011 #elif defined (__BEOS__)
1012 printf ("This program cannot be compiled on BeOS.\n") ;
1013 printf ("Instead, compile the file sfplay_beos.cpp.\n") ;
1016 puts ("*** Playing sound not yet supported on this platform.") ;
1017 puts ("*** Please feel free to submit a patch.") ;