2 ** Copyright (c) 1999-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** All rights reserved.
5 ** This code is released under 2-clause BSD license. Please see the
6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
16 #include "audio_out.h"
18 #if HAVE_ALSA_ASOUNDLIB_H
19 #define ALSA_PCM_NEW_HW_PARAMS_API
20 #define ALSA_PCM_NEW_SW_PARAMS_API
21 #include <alsa/asoundlib.h>
27 #include <float_cast.h>
31 #define BUFFER_LEN (2048)
33 #define MAKE_MAGIC(a,b,c,d,e,f,g,h) \
34 ((a) + ((b) << 1) + ((c) << 2) + ((d) << 3) + ((e) << 4) + ((f) << 5) + ((g) << 6) + ((h) << 7))
36 typedef struct AUDIO_OUT_s
41 /*------------------------------------------------------------------------------
42 ** Linux (ALSA and OSS) functions for playing a sound.
45 #if defined (__linux__)
47 #if HAVE_ALSA_ASOUNDLIB_H
49 #define ALSA_MAGIC MAKE_MAGIC ('L', 'n', 'x', '-', 'A', 'L', 'S', 'A')
57 static int alsa_write_float (snd_pcm_t
*alsa_dev
, float *data
, int frames
, int channels
) ;
60 alsa_open (int channels
, unsigned samplerate
)
61 { ALSA_AUDIO_OUT
*alsa_out
;
62 const char * device
= "default" ;
63 snd_pcm_hw_params_t
*hw_params
;
64 snd_pcm_uframes_t buffer_size
;
65 snd_pcm_uframes_t alsa_period_size
, alsa_buffer_frames
;
66 snd_pcm_sw_params_t
*sw_params
;
70 alsa_period_size
= 1024 ;
71 alsa_buffer_frames
= 4 * alsa_period_size
;
73 if ((alsa_out
= calloc (1, sizeof (ALSA_AUDIO_OUT
))) == NULL
)
74 { perror ("alsa_open : malloc ") ;
78 alsa_out
->magic
= ALSA_MAGIC
;
79 alsa_out
->channels
= channels
;
81 if ((err
= snd_pcm_open (&alsa_out
->dev
, device
, SND_PCM_STREAM_PLAYBACK
, 0)) < 0)
82 { fprintf (stderr
, "cannot open audio device \"%s\" (%s)\n", device
, snd_strerror (err
)) ;
86 snd_pcm_nonblock (alsa_out
->dev
, 0) ;
88 if ((err
= snd_pcm_hw_params_malloc (&hw_params
)) < 0)
89 { fprintf (stderr
, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err
)) ;
93 if ((err
= snd_pcm_hw_params_any (alsa_out
->dev
, hw_params
)) < 0)
94 { fprintf (stderr
, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err
)) ;
98 if ((err
= snd_pcm_hw_params_set_access (alsa_out
->dev
, hw_params
, SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
99 { fprintf (stderr
, "cannot set access type (%s)\n", snd_strerror (err
)) ;
103 if ((err
= snd_pcm_hw_params_set_format (alsa_out
->dev
, hw_params
, SND_PCM_FORMAT_FLOAT
)) < 0)
104 { fprintf (stderr
, "cannot set sample format (%s)\n", snd_strerror (err
)) ;
108 if ((err
= snd_pcm_hw_params_set_rate_near (alsa_out
->dev
, hw_params
, &samplerate
, 0)) < 0)
109 { fprintf (stderr
, "cannot set sample rate (%s)\n", snd_strerror (err
)) ;
113 if ((err
= snd_pcm_hw_params_set_channels (alsa_out
->dev
, hw_params
, channels
)) < 0)
114 { fprintf (stderr
, "cannot set channel count (%s)\n", snd_strerror (err
)) ;
118 if ((err
= snd_pcm_hw_params_set_buffer_size_near (alsa_out
->dev
, hw_params
, &alsa_buffer_frames
)) < 0)
119 { fprintf (stderr
, "cannot set buffer size (%s)\n", snd_strerror (err
)) ;
123 if ((err
= snd_pcm_hw_params_set_period_size_near (alsa_out
->dev
, hw_params
, &alsa_period_size
, 0)) < 0)
124 { fprintf (stderr
, "cannot set period size (%s)\n", snd_strerror (err
)) ;
128 if ((err
= snd_pcm_hw_params (alsa_out
->dev
, hw_params
)) < 0)
129 { fprintf (stderr
, "cannot set parameters (%s)\n", snd_strerror (err
)) ;
133 /* extra check: if we have only one period, this code won't work */
134 snd_pcm_hw_params_get_period_size (hw_params
, &alsa_period_size
, 0) ;
135 snd_pcm_hw_params_get_buffer_size (hw_params
, &buffer_size
) ;
136 if (alsa_period_size
== buffer_size
)
137 { fprintf (stderr
, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size
, buffer_size
) ;
141 snd_pcm_hw_params_free (hw_params
) ;
143 if ((err
= snd_pcm_sw_params_malloc (&sw_params
)) != 0)
144 { fprintf (stderr
, "%s: snd_pcm_sw_params_malloc: %s", __func__
, snd_strerror (err
)) ;
148 if ((err
= snd_pcm_sw_params_current (alsa_out
->dev
, sw_params
)) != 0)
149 { fprintf (stderr
, "%s: snd_pcm_sw_params_current: %s", __func__
, snd_strerror (err
)) ;
153 /* note: set start threshold to delay start until the ring buffer is full */
154 snd_pcm_sw_params_current (alsa_out
->dev
, sw_params
) ;
156 if ((err
= snd_pcm_sw_params_set_start_threshold (alsa_out
->dev
, sw_params
, buffer_size
)) < 0)
157 { fprintf (stderr
, "cannot set start threshold (%s)\n", snd_strerror (err
)) ;
161 if ((err
= snd_pcm_sw_params (alsa_out
->dev
, sw_params
)) != 0)
162 { fprintf (stderr
, "%s: snd_pcm_sw_params: %s", __func__
, snd_strerror (err
)) ;
166 snd_pcm_sw_params_free (sw_params
) ;
168 snd_pcm_reset (alsa_out
->dev
) ;
172 if (err
< 0 && alsa_out
->dev
!= NULL
)
173 { snd_pcm_close (alsa_out
->dev
) ;
177 return (AUDIO_OUT
*) alsa_out
;
181 alsa_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
182 { static float buffer
[BUFFER_LEN
] ;
183 ALSA_AUDIO_OUT
*alsa_out
;
186 if ((alsa_out
= (ALSA_AUDIO_OUT
*) audio_out
) == NULL
)
187 { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
191 if (alsa_out
->magic
!= ALSA_MAGIC
)
192 { printf ("alsa_close : Bad magic number.\n") ;
196 while ((read_frames
= callback (callback_data
, buffer
, BUFFER_LEN
/ alsa_out
->channels
)))
197 alsa_write_float (alsa_out
->dev
, buffer
, read_frames
, alsa_out
->channels
) ;
203 alsa_write_float (snd_pcm_t
*alsa_dev
, float *data
, int frames
, int channels
)
204 { static int epipe_count
= 0 ;
212 while (total
< frames
)
213 { retval
= snd_pcm_writei (alsa_dev
, data
+ total
* channels
, frames
- total
) ;
225 puts ("alsa_write_float: EAGAIN") ;
231 { printf ("alsa_write_float: EPIPE %d\n", epipe_count
) ;
232 if (epipe_count
> 140)
239 { snd_pcm_status_t
*status
;
241 snd_pcm_status_alloca (&status
) ;
242 if ((retval
= snd_pcm_status (alsa_dev
, status
)) < 0)
243 fprintf (stderr
, "alsa_out: xrun. can't determine length\n") ;
244 else if (snd_pcm_status_get_state (status
) == SND_PCM_STATE_XRUN
)
245 { struct timeval now
, diff
, tstamp
;
247 gettimeofday (&now
, 0) ;
248 snd_pcm_status_get_trigger_tstamp (status
, &tstamp
) ;
249 timersub (&now
, &tstamp
, &diff
) ;
251 fprintf (stderr
, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",
252 diff
.tv_sec
* 1000 + diff
.tv_usec
/ 1000.0) ;
255 fprintf (stderr
, "alsa_write_float: xrun. can't determine length\n") ;
259 snd_pcm_prepare (alsa_dev
) ;
263 fprintf (stderr
, "alsa_write_float: Bad PCM state.n") ;
268 fprintf (stderr
, "alsa_write_float: Suspend event.n") ;
273 puts ("alsa_write_float: EIO") ;
277 fprintf (stderr
, "alsa_write_float: retval = %d\n", retval
) ;
284 } /* alsa_write_float */
287 alsa_close (AUDIO_OUT
*audio_out
)
288 { ALSA_AUDIO_OUT
*alsa_out
;
290 if ((alsa_out
= (ALSA_AUDIO_OUT
*) audio_out
) == NULL
)
291 { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
295 if (alsa_out
->magic
!= ALSA_MAGIC
)
296 { printf ("alsa_close : Bad magic number.\n") ;
300 memset (alsa_out
, 0, sizeof (ALSA_AUDIO_OUT
)) ;
307 #endif /* HAVE_ALSA_ASOUNDLIB_H */
310 #include <sys/ioctl.h>
311 #include <sys/soundcard.h>
313 #define OSS_MAGIC MAKE_MAGIC ('L', 'i', 'n', 'u', 'x', 'O', 'S', 'S')
321 static AUDIO_OUT
*opensoundsys_open (int channels
, int samplerate
) ;
322 static void opensoundsys_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
) ;
323 static void opensoundsys_close (AUDIO_OUT
*audio_out
) ;
327 opensoundsys_open (int channels
, int samplerate
)
328 { OSS_AUDIO_OUT
*opensoundsys_out
;
329 int stereo
, fmt
, error
;
331 if ((opensoundsys_out
= calloc (1, sizeof (OSS_AUDIO_OUT
))) == NULL
)
332 { perror ("opensoundsys_open : malloc ") ;
336 opensoundsys_out
->magic
= OSS_MAGIC
;
337 opensoundsys_out
->channels
= channels
;
339 if ((opensoundsys_out
->fd
= open ("/dev/dsp", O_WRONLY
, 0)) == -1)
340 { perror ("opensoundsys_open : open ") ;
345 if (ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_STEREO
, &stereo
) == -1)
347 perror ("opensoundsys_open : stereo ") ;
351 if (ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_RESET
, 0))
352 { perror ("opensoundsys_open : reset ") ;
356 fmt
= CPU_IS_BIG_ENDIAN
? AFMT_S16_BE
: AFMT_S16_LE
;
357 if (ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_SETFMT
, &fmt
) != 0)
358 { perror ("opensoundsys_open_dsp_device : set format ") ;
362 if ((error
= ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_CHANNELS
, &channels
)) != 0)
363 { perror ("opensoundsys_open : channels ") ;
367 if ((error
= ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_SPEED
, &samplerate
)) != 0)
368 { perror ("opensoundsys_open : sample rate ") ;
372 if ((error
= ioctl (opensoundsys_out
->fd
, SNDCTL_DSP_SYNC
, 0)) != 0)
373 { perror ("opensoundsys_open : sync ") ;
377 return (AUDIO_OUT
*) opensoundsys_out
;
378 } /* opensoundsys_open */
381 opensoundsys_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
382 { OSS_AUDIO_OUT
*opensoundsys_out
;
383 static float float_buffer
[BUFFER_LEN
] ;
384 static short buffer
[BUFFER_LEN
] ;
387 if ((opensoundsys_out
= (OSS_AUDIO_OUT
*) audio_out
) == NULL
)
388 { printf ("opensoundsys_play : AUDIO_OUT is NULL.\n") ;
392 if (opensoundsys_out
->magic
!= OSS_MAGIC
)
393 { printf ("opensoundsys_play : Bad magic number.\n") ;
397 while ((read_frames
= callback (callback_data
, float_buffer
, BUFFER_LEN
/ opensoundsys_out
->channels
)))
398 { for (k
= 0 ; k
< read_frames
* opensoundsys_out
->channels
; k
++)
399 buffer
[k
] = lrint (32767.0 * float_buffer
[k
]) ;
400 (void) write (opensoundsys_out
->fd
, buffer
, read_frames
* opensoundsys_out
->channels
* sizeof (short)) ;
404 } /* opensoundsys_play */
407 opensoundsys_close (AUDIO_OUT
*audio_out
)
408 { OSS_AUDIO_OUT
*opensoundsys_out
;
410 if ((opensoundsys_out
= (OSS_AUDIO_OUT
*) audio_out
) == NULL
)
411 { printf ("opensoundsys_close : AUDIO_OUT is NULL.\n") ;
415 if (opensoundsys_out
->magic
!= OSS_MAGIC
)
416 { printf ("opensoundsys_close : Bad magic number.\n") ;
420 memset (opensoundsys_out
, 0, sizeof (OSS_AUDIO_OUT
)) ;
422 free (opensoundsys_out
) ;
425 } /* opensoundsys_close */
427 #endif /* __linux__ */
429 /*------------------------------------------------------------------------------
430 ** Mac OS X functions for playing a sound.
433 #if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
436 #include <CoreAudio/AudioHardware.h>
438 #define MACOSX_MAGIC MAKE_MAGIC ('M', 'a', 'c', ' ', 'O', 'S', ' ', 'X')
442 AudioStreamBasicDescription format
;
445 AudioDeviceID device
;
452 get_audio_callback_t callback
;
454 void *callback_data
;
457 static AUDIO_OUT
*macosx_open (int channels
, int samplerate
) ;
458 static void macosx_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
) ;
459 static void macosx_close (AUDIO_OUT
*audio_out
) ;
462 macosx_audio_out_callback (AudioDeviceID device
, const AudioTimeStamp
* current_time
,
463 const AudioBufferList
* data_in
, const AudioTimeStamp
* time_in
,
464 AudioBufferList
* data_out
, const AudioTimeStamp
* time_out
, void* client_data
) ;
468 macosx_open (int channels
, int samplerate
)
469 { MACOSX_AUDIO_OUT
*macosx_out
;
473 if ((macosx_out
= calloc (1, sizeof (MACOSX_AUDIO_OUT
))) == NULL
)
474 { perror ("macosx_open : malloc ") ;
478 macosx_out
->magic
= MACOSX_MAGIC
;
479 macosx_out
->channels
= channels
;
480 macosx_out
->samplerate
= samplerate
;
482 macosx_out
->device
= kAudioDeviceUnknown
;
484 /* get the default output device for the HAL */
485 count
= sizeof (AudioDeviceID
) ;
486 if ((err
= AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice
,
487 &count
, (void *) &(macosx_out
->device
))) != noErr
)
488 { printf ("AudioHardwareGetProperty failed.\n") ;
493 /* get the buffersize that the default device uses for IO */
494 count
= sizeof (UInt32
) ;
495 if ((err
= AudioDeviceGetProperty (macosx_out
->device
, 0, false, kAudioDevicePropertyBufferSize
,
496 &count
, &(macosx_out
->buffer_size
))) != noErr
)
497 { printf ("AudioDeviceGetProperty (AudioDeviceGetProperty) failed.\n") ;
502 /* get a description of the data format used by the default device */
503 count
= sizeof (AudioStreamBasicDescription
) ;
504 if ((err
= AudioDeviceGetProperty (macosx_out
->device
, 0, false, kAudioDevicePropertyStreamFormat
,
505 &count
, &(macosx_out
->format
))) != noErr
)
506 { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
511 macosx_out
->format
.mSampleRate
= samplerate
;
512 macosx_out
->format
.mChannelsPerFrame
= channels
;
514 if ((err
= AudioDeviceSetProperty (macosx_out
->device
, NULL
, 0, false, kAudioDevicePropertyStreamFormat
,
515 sizeof (AudioStreamBasicDescription
), &(macosx_out
->format
))) != noErr
)
516 { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
521 /* we want linear pcm */
522 if (macosx_out
->format
.mFormatID
!= kAudioFormatLinearPCM
)
523 { free (macosx_out
) ;
527 macosx_out
->done_playing
= 0 ;
529 /* Fire off the device. */
530 if ((err
= AudioDeviceAddIOProc (macosx_out
->device
, macosx_audio_out_callback
,
531 (void *) macosx_out
)) != noErr
)
532 { printf ("AudioDeviceAddIOProc failed.\n") ;
537 return (MACOSX_AUDIO_OUT
*) macosx_out
;
541 macosx_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
542 { MACOSX_AUDIO_OUT
*macosx_out
;
545 if ((macosx_out
= (MACOSX_AUDIO_OUT
*) audio_out
) == NULL
)
546 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
550 if (macosx_out
->magic
!= MACOSX_MAGIC
)
551 { printf ("macosx_play : Bad magic number.\n") ;
555 /* Set the callback function and callback data. */
556 macosx_out
->callback
= callback
;
557 macosx_out
->callback_data
= callback_data
;
559 err
= AudioDeviceStart (macosx_out
->device
, macosx_audio_out_callback
) ;
561 printf ("AudioDeviceStart failed.\n") ;
563 while (macosx_out
->done_playing
== SF_FALSE
)
564 usleep (10 * 1000) ; /* 10 000 milliseconds. */
570 macosx_close (AUDIO_OUT
*audio_out
)
571 { MACOSX_AUDIO_OUT
*macosx_out
;
574 if ((macosx_out
= (MACOSX_AUDIO_OUT
*) audio_out
) == NULL
)
575 { printf ("macosx_close : AUDIO_OUT is NULL.\n") ;
579 if (macosx_out
->magic
!= MACOSX_MAGIC
)
580 { printf ("macosx_close : Bad magic number.\n") ;
585 if ((err
= AudioDeviceStop (macosx_out
->device
, macosx_audio_out_callback
)) != noErr
)
586 { printf ("AudioDeviceStop failed.\n") ;
590 err
= AudioDeviceRemoveIOProc (macosx_out
->device
, macosx_audio_out_callback
) ;
592 { printf ("AudioDeviceRemoveIOProc failed.\n") ;
599 macosx_audio_out_callback (AudioDeviceID device
, const AudioTimeStamp
* current_time
,
600 const AudioBufferList
* data_in
, const AudioTimeStamp
* time_in
,
601 AudioBufferList
* data_out
, const AudioTimeStamp
* time_out
, void* client_data
)
602 { MACOSX_AUDIO_OUT
*macosx_out
;
603 int k
, size
, frame_count
, read_count
;
606 if ((macosx_out
= (MACOSX_AUDIO_OUT
*) client_data
) == NULL
)
607 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
611 if (macosx_out
->magic
!= MACOSX_MAGIC
)
612 { printf ("macosx_play : Bad magic number.\n") ;
616 size
= data_out
->mBuffers
[0].mDataByteSize
;
617 frame_count
= size
/ sizeof (float) / macosx_out
->channels
;
619 buffer
= (float*) data_out
->mBuffers
[0].mData
;
621 read_count
= macosx_out
->callback (macosx_out
->callback_data
, buffer
, frame_count
) ;
623 if (read_count
< frame_count
)
624 { memset (&(buffer
[read_count
]), 0, (frame_count
- read_count
) * sizeof (float)) ;
625 macosx_out
->done_playing
= 1 ;
629 } /* macosx_audio_out_callback */
634 /*------------------------------------------------------------------------------
635 ** Win32 functions for playing a sound.
637 ** This API sucks. Its needlessly complicated and is *WAY* too loose with
638 ** passing pointers arounf in integers and and using char* pointers to
639 ** point to data instead of short*. It plain sucks!
642 #if (defined (_WIN32) || defined (WIN32))
645 #include <mmsystem.h>
647 #define WIN32_BUFFER_LEN (1<<15)
648 #define WIN32_MAGIC MAKE_MAGIC ('W', 'i', 'n', '3', '2', 's', 'u', 'x')
658 short short_buffer
[WIN32_BUFFER_LEN
/ sizeof (short)] ;
659 float float_buffer
[WIN32_BUFFER_LEN
/ sizeof (short) / 2] ;
661 int bufferlen
, current
;
665 get_audio_callback_t callback
;
667 void *callback_data
;
670 static AUDIO_OUT
*win32_open (int channels
, int samplerate
) ;
671 static void win32_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
) ;
672 static void win32_close (AUDIO_OUT
*audio_out
) ;
674 static DWORD CALLBACK
675 win32_audio_out_callback (HWAVEOUT hwave
, UINT msg
, DWORD data
, DWORD param1
, DWORD param2
) ;
678 win32_open (int channels
, int samplerate
)
679 { WIN32_AUDIO_OUT
*win32_out
;
684 if ((win32_out
= calloc (1, sizeof (WIN32_AUDIO_OUT
))) == NULL
)
685 { perror ("win32_open : malloc ") ;
689 win32_out
->magic
= WIN32_MAGIC
;
690 win32_out
->channels
= channels
;
692 win32_out
->current
= 0 ;
694 win32_out
->Event
= CreateEvent (0, FALSE
, FALSE
, 0) ;
696 wf
.nChannels
= channels
;
697 wf
.nSamplesPerSec
= samplerate
;
698 wf
.nBlockAlign
= channels
* sizeof (short) ;
700 wf
.wFormatTag
= WAVE_FORMAT_PCM
;
702 wf
.wBitsPerSample
= 16 ;
703 wf
.nAvgBytesPerSec
= wf
.nBlockAlign
* wf
.nSamplesPerSec
;
705 error
= waveOutOpen (&(win32_out
->hwave
), WAVE_MAPPER
, &wf
, (DWORD
) win32_audio_out_callback
,
706 (DWORD
) win32_out
, CALLBACK_FUNCTION
) ;
708 { puts ("waveOutOpen failed.") ;
713 waveOutPause (win32_out
->hwave
) ;
715 return (WIN32_AUDIO_OUT
*) win32_out
;
719 win32_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
720 { WIN32_AUDIO_OUT
*win32_out
;
723 if ((win32_out
= (WIN32_AUDIO_OUT
*) audio_out
) == NULL
)
724 { printf ("win32_play : AUDIO_OUT is NULL.\n") ;
728 if (win32_out
->magic
!= WIN32_MAGIC
)
729 { printf ("win32_play : Bad magic number (%d %d).\n", win32_out
->magic
, WIN32_MAGIC
) ;
733 /* Set the callback function and callback data. */
734 win32_out
->callback
= callback
;
735 win32_out
->callback_data
= callback_data
;
737 win32_out
->whdr
[0].lpData
= (char*) win32_out
->short_buffer
;
738 win32_out
->whdr
[1].lpData
= ((char*) win32_out
->short_buffer
) + sizeof (win32_out
->short_buffer
) / 2 ;
740 win32_out
->whdr
[0].dwBufferLength
= sizeof (win32_out
->short_buffer
) / 2 ;
741 win32_out
->whdr
[1].dwBufferLength
= sizeof (win32_out
->short_buffer
) / 2 ;
743 win32_out
->bufferlen
= sizeof (win32_out
->short_buffer
) / 2 / sizeof (short) ;
745 /* Prepare the WAVEHDRs */
746 if ((error
= waveOutPrepareHeader (win32_out
->hwave
, &(win32_out
->whdr
[0]), sizeof (WAVEHDR
))))
747 { printf ("waveOutPrepareHeader [0] failed : %08X\n", error
) ;
748 waveOutClose (win32_out
->hwave
) ;
752 if ((error
= waveOutPrepareHeader (win32_out
->hwave
, &(win32_out
->whdr
[1]), sizeof (WAVEHDR
))))
753 { printf ("waveOutPrepareHeader [1] failed : %08X\n", error
) ;
754 waveOutUnprepareHeader (win32_out
->hwave
, &(win32_out
->whdr
[0]), sizeof (WAVEHDR
)) ;
755 waveOutClose (win32_out
->hwave
) ;
759 waveOutRestart (win32_out
->hwave
) ;
761 /* Fake 2 calls to the callback function to queue up enough audio. */
762 win32_audio_out_callback (0, MM_WOM_DONE
, (DWORD
) win32_out
, 0, 0) ;
763 win32_audio_out_callback (0, MM_WOM_DONE
, (DWORD
) win32_out
, 0, 0) ;
765 /* Wait for playback to finish. The callback notifies us when all
766 ** wave data has been played.
768 WaitForSingleObject (win32_out
->Event
, INFINITE
) ;
770 waveOutPause (win32_out
->hwave
) ;
771 waveOutReset (win32_out
->hwave
) ;
773 waveOutUnprepareHeader (win32_out
->hwave
, &(win32_out
->whdr
[0]), sizeof (WAVEHDR
)) ;
774 waveOutUnprepareHeader (win32_out
->hwave
, &(win32_out
->whdr
[1]), sizeof (WAVEHDR
)) ;
776 waveOutClose (win32_out
->hwave
) ;
777 win32_out
->hwave
= 0 ;
783 win32_close (AUDIO_OUT
*audio_out
)
784 { WIN32_AUDIO_OUT
*win32_out
;
786 if ((win32_out
= (WIN32_AUDIO_OUT
*) audio_out
) == NULL
)
787 { printf ("win32_close : AUDIO_OUT is NULL.\n") ;
791 if (win32_out
->magic
!= WIN32_MAGIC
)
792 { printf ("win32_close : Bad magic number.\n") ;
796 memset (win32_out
, 0, sizeof (WIN32_AUDIO_OUT
)) ;
801 static DWORD CALLBACK
802 win32_audio_out_callback (HWAVEOUT hwave
, UINT msg
, DWORD data
, DWORD param1
, DWORD param2
)
803 { WIN32_AUDIO_OUT
*win32_out
;
804 int read_count
, frame_count
, k
;
808 ** I consider this technique of passing a pointer via an integer as
809 ** fundamentally broken but thats the way microsoft has defined the
812 if ((win32_out
= (WIN32_AUDIO_OUT
*) data
) == NULL
)
813 { printf ("win32_audio_out_callback : AUDIO_OUT is NULL.\n") ;
817 if (win32_out
->magic
!= WIN32_MAGIC
)
818 { printf ("win32_audio_out_callback : Bad magic number (%d %d).\n", win32_out
->magic
, WIN32_MAGIC
) ;
822 if (msg
!= MM_WOM_DONE
)
825 /* Do the actual audio. */
826 sample_count
= win32_out
->bufferlen
;
827 frame_count
= sample_count
/ win32_out
->channels
;
829 read_count
= win32_out
->callback (win32_out
->callback_data
, win32_out
->float_buffer
, frame_count
) ;
831 sptr
= (short*) win32_out
->whdr
[win32_out
->current
].lpData
;
833 for (k
= 0 ; k
< read_count
; k
++)
834 sptr
[k
] = lrint (32767.0 * win32_out
->float_buffer
[k
]) ;
837 { /* Fix buffer length is only a partial block. */
838 if (read_count
* sizeof (short) < win32_out
->bufferlen
)
839 win32_out
->whdr
[win32_out
->current
].dwBufferLength
= read_count
* sizeof (short) ;
841 /* Queue the WAVEHDR */
842 waveOutWrite (win32_out
->hwave
, (LPWAVEHDR
) &(win32_out
->whdr
[win32_out
->current
]), sizeof (WAVEHDR
)) ;
845 { /* Stop playback */
846 waveOutPause (win32_out
->hwave
) ;
848 SetEvent (win32_out
->Event
) ;
851 win32_out
->current
= (win32_out
->current
+ 1) % 2 ;
854 } /* win32_audio_out_callback */
858 /*------------------------------------------------------------------------------
862 #if (defined (sun) && defined (unix)) /* ie Solaris */
865 #include <sys/ioctl.h>
866 #include <sys/audioio.h>
868 #define SOLARIS_MAGIC MAKE_MAGIC ('S', 'o', 'l', 'a', 'r', 'i', 's', ' ')
875 } SOLARIS_AUDIO_OUT
;
877 static AUDIO_OUT
*solaris_open (int channels
, int samplerate
) ;
878 static void solaris_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
) ;
879 static void solaris_close (AUDIO_OUT
*audio_out
) ;
882 solaris_open (int channels
, int samplerate
)
883 { SOLARIS_AUDIO_OUT
*solaris_out
;
884 audio_info_t audio_info
;
887 if ((solaris_out
= calloc (1, sizeof (SOLARIS_AUDIO_OUT
))) == NULL
)
888 { perror ("solaris_open : malloc ") ;
892 solaris_out
->magic
= SOLARIS_MAGIC
;
893 solaris_out
->channels
= channels
;
894 solaris_out
->samplerate
= channels
;
896 /* open the audio device - write only, non-blocking */
897 if ((solaris_out
->fd
= open ("/dev/audio", O_WRONLY
| O_NONBLOCK
)) < 0)
898 { perror ("open (/dev/audio) failed") ;
902 /* Retrive standard values. */
903 AUDIO_INITINFO (&audio_info
) ;
905 audio_info
.play
.sample_rate
= samplerate
;
906 audio_info
.play
.channels
= channels
;
907 audio_info
.play
.precision
= 16 ;
908 audio_info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
909 audio_info
.play
.gain
= AUDIO_MAX_GAIN
;
910 audio_info
.play
.balance
= AUDIO_MID_BALANCE
;
912 if ((error
= ioctl (solaris_out
->fd
, AUDIO_SETINFO
, &audio_info
)))
913 { perror ("ioctl (AUDIO_SETINFO) failed") ;
917 return (AUDIO_OUT
*) solaris_out
;
921 solaris_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
922 { SOLARIS_AUDIO_OUT
*solaris_out
;
923 static float float_buffer
[BUFFER_LEN
] ;
924 static short buffer
[BUFFER_LEN
] ;
927 if ((solaris_out
= (SOLARIS_AUDIO_OUT
*) audio_out
) == NULL
)
928 { printf ("solaris_play : AUDIO_OUT is NULL.\n") ;
932 if (solaris_out
->magic
!= SOLARIS_MAGIC
)
933 { printf ("solaris_play : Bad magic number.\n") ;
937 while ((read_frames
= callback (callback_data
, float_buffer
, BUFFER_LEN
/ solaris_out
->channels
)))
938 { for (k
= 0 ; k
< read_frames
* solaris_out
->channels
; k
++)
939 buffer
[k
] = lrint (32767.0 * float_buffer
[k
]) ;
940 write (solaris_out
->fd
, buffer
, read_frames
* solaris_out
->channels
* sizeof (short)) ;
947 solaris_close (AUDIO_OUT
*audio_out
)
948 { SOLARIS_AUDIO_OUT
*solaris_out
;
950 if ((solaris_out
= (SOLARIS_AUDIO_OUT
*) audio_out
) == NULL
)
951 { printf ("solaris_close : AUDIO_OUT is NULL.\n") ;
955 if (solaris_out
->magic
!= SOLARIS_MAGIC
)
956 { printf ("solaris_close : Bad magic number.\n") ;
960 memset (solaris_out
, 0, sizeof (SOLARIS_AUDIO_OUT
)) ;
965 } /* solaris_close */
969 /*==============================================================================
974 audio_open (int channels
, int samplerate
)
976 #if defined (__linux__)
977 #if HAVE_ALSA_ASOUNDLIB_H
978 if (access ("/proc/asound/cards", R_OK
) == 0)
979 return alsa_open (channels
, samplerate
) ;
981 return opensoundsys_open (channels
, samplerate
) ;
982 #elif (defined (__MACH__) && defined (__APPLE__))
983 return macosx_open (channels
, samplerate
) ;
984 #elif (defined (sun) && defined (unix))
985 return solaris_open (channels
, samplerate
) ;
986 #elif (defined (_WIN32) || defined (WIN32))
987 return win32_open (channels
, samplerate
) ;
989 #warning "*** Playing sound not yet supported on this platform."
990 #warning "*** Please feel free to submit a patch."
991 printf ("Error : Playing sound not yet supported on this platform.\n") ;
1000 audio_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
1003 if (callback
== NULL
)
1004 { printf ("Error : bad callback pointer.\n") ;
1008 if (audio_out
== NULL
)
1009 { printf ("Error : bad audio_out pointer.\n") ;
1013 if (callback_data
== NULL
)
1014 { printf ("Error : bad callback_data pointer.\n") ;
1018 #if defined (__linux__)
1019 #if HAVE_ALSA_ASOUNDLIB_H
1020 if (audio_out
->magic
== ALSA_MAGIC
)
1021 alsa_play (callback
, audio_out
, callback_data
) ;
1023 opensoundsys_play (callback
, audio_out
, callback_data
) ;
1024 #elif (defined (__MACH__) && defined (__APPLE__))
1025 macosx_play (callback
, audio_out
, callback_data
) ;
1026 #elif (defined (sun) && defined (unix))
1027 solaris_play (callback
, audio_out
, callback_data
) ;
1028 #elif (defined (_WIN32) || defined (WIN32))
1029 win32_play (callback
, audio_out
, callback_data
) ;
1031 #warning "*** Playing sound not yet supported on this platform."
1032 #warning "*** Please feel free to submit a patch."
1033 printf ("Error : Playing sound not yet supported on this platform.\n") ;
1041 audio_close (AUDIO_OUT
*audio_out
)
1043 #if defined (__linux__)
1044 #if HAVE_ALSA_ASOUNDLIB_H
1045 if (audio_out
->magic
== ALSA_MAGIC
)
1046 alsa_close (audio_out
) ;
1048 opensoundsys_close (audio_out
) ;
1049 #elif (defined (__MACH__) && defined (__APPLE__))
1050 macosx_close (audio_out
) ;
1051 #elif (defined (sun) && defined (unix))
1052 solaris_close (audio_out
) ;
1053 #elif (defined (_WIN32) || defined (WIN32))
1054 win32_close (audio_out
) ;
1056 #warning "*** Playing sound not yet supported on this platform."
1057 #warning "*** Please feel free to submit a patch."
1058 printf ("Error : Playing sound not yet supported on this platform.\n") ;
1065 #else /* (HAVE_SNDFILE == 0) */
1067 /* Do not have libsndfile installed so just return. */
1070 audio_open (int channels
, int samplerate
)
1079 audio_play (get_audio_callback_t callback
, AUDIO_OUT
*audio_out
, void *callback_data
)
1083 (void) callback_data
;
1089 audio_close (AUDIO_OUT
*audio_out
)
1091 audio_out
= audio_out
;
1096 #endif /* HAVE_SNDFILE */