blob: 1055555c26368b096ea62c00eaf7ad3b52d094d3 [file] [log] [blame]
Emeric Vigiereebea672012-08-06 17:36:30 -04001/*
2** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
3**
4** This program is free software; you can redistribute it and/or modify
5** it under the terms of the GNU General Public License as published by
6** the Free Software Foundation; either version 2 of the License, or
7** (at your option) any later version.
8**
9** This program is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12** GNU General Public License for more details.
13**
14** You should have received a copy of the GNU General Public License
15** along with this program; if not, write to the Free Software
16** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <config.h>
25
26#include "audio_out.h"
27
28#if (HAVE_SNDFILE)
29
30#include <float_cast.h>
31
32#include <sndfile.h>
33
34#define BUFFER_LEN (2048)
35
36#define MAKE_MAGIC(a,b,c,d,e,f,g,h) \
37 ((a) + ((b) << 1) + ((c) << 2) + ((d) << 3) + ((e) << 4) + ((f) << 5) + ((g) << 6) + ((h) << 7))
38
39/*------------------------------------------------------------------------------
40** Linux/OSS functions for playing a sound.
41*/
42
43#if defined (__linux__)
44
45#include <fcntl.h>
46#include <sys/ioctl.h>
47#include <sys/soundcard.h>
48
49#define LINUX_MAGIC MAKE_MAGIC ('L', 'i', 'n', 'u', 'x', 'O', 'S', 'S')
50
51typedef struct
52{ int magic ;
53 int fd ;
54 int channels ;
55} LINUX_AUDIO_OUT ;
56
57static AUDIO_OUT *linux_open (int channels, int samplerate) ;
58static void linux_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
59static void linux_close (AUDIO_OUT *audio_out) ;
60
61
62static AUDIO_OUT *
63linux_open (int channels, int samplerate)
64{ LINUX_AUDIO_OUT *linux_out ;
65 int stereo, fmt, error ;
66
67 if ((linux_out = malloc (sizeof (LINUX_AUDIO_OUT))) == NULL)
68 { perror ("linux_open : malloc ") ;
69 exit (1) ;
70 } ;
71
72 linux_out->magic = LINUX_MAGIC ;
73 linux_out->channels = channels ;
74
75 if ((linux_out->fd = open ("/dev/dsp", O_WRONLY, 0)) == -1)
76 { perror ("linux_open : open ") ;
77 exit (1) ;
78 } ;
79
80 stereo = 0 ;
81 if (ioctl (linux_out->fd, SNDCTL_DSP_STEREO, &stereo) == -1)
82 { /* Fatal error */
83 perror ("linux_open : stereo ") ;
84 exit (1) ;
85 } ;
86
87 if (ioctl (linux_out->fd, SNDCTL_DSP_RESET, 0))
88 { perror ("linux_open : reset ") ;
89 exit (1) ;
90 } ;
91
92 fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
93 if (ioctl (linux_out->fd, SNDCTL_DSP_SETFMT, &fmt) != 0)
94 { perror ("linux_open_dsp_device : set format ") ;
95 exit (1) ;
96 } ;
97
98 if ((error = ioctl (linux_out->fd, SNDCTL_DSP_CHANNELS, &channels)) != 0)
99 { perror ("linux_open : channels ") ;
100 exit (1) ;
101 } ;
102
103 if ((error = ioctl (linux_out->fd, SNDCTL_DSP_SPEED, &samplerate)) != 0)
104 { perror ("linux_open : sample rate ") ;
105 exit (1) ;
106 } ;
107
108 if ((error = ioctl (linux_out->fd, SNDCTL_DSP_SYNC, 0)) != 0)
109 { perror ("linux_open : sync ") ;
110 exit (1) ;
111 } ;
112
113 return (AUDIO_OUT*) linux_out ;
114} /* linux_open */
115
116static void
117linux_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
118{ LINUX_AUDIO_OUT *linux_out ;
119 static float float_buffer [BUFFER_LEN] ;
120 static short buffer [BUFFER_LEN] ;
121 int k, readcount ;
122
123 if ((linux_out = (LINUX_AUDIO_OUT*) audio_out) == NULL)
124 { printf ("linux_play : AUDIO_OUT is NULL.\n") ;
125 return ;
126 } ;
127
128 if (linux_out->magic != LINUX_MAGIC)
129 { printf ("linux_play : Bad magic number.\n") ;
130 return ;
131 } ;
132
133 while ((readcount = callback (callback_data, float_buffer, BUFFER_LEN / linux_out->channels)))
134 { for (k = 0 ; k < readcount * linux_out->channels ; k++)
135 buffer [k] = lrint (32767.0 * float_buffer [k]) ;
136 (void) write (linux_out->fd, buffer, readcount * linux_out->channels * sizeof (short)) ;
137 } ;
138
139 return ;
140} /* linux_play */
141
142static void
143linux_close (AUDIO_OUT *audio_out)
144{ LINUX_AUDIO_OUT *linux_out ;
145
146 if ((linux_out = (LINUX_AUDIO_OUT*) audio_out) == NULL)
147 { printf ("linux_close : AUDIO_OUT is NULL.\n") ;
148 return ;
149 } ;
150
151 if (linux_out->magic != LINUX_MAGIC)
152 { printf ("linux_close : Bad magic number.\n") ;
153 return ;
154 } ;
155
156 memset (linux_out, 0, sizeof (LINUX_AUDIO_OUT)) ;
157
158 free (linux_out) ;
159
160 return ;
161} /* linux_close */
162
163#endif /* __linux__ */
164
165/*------------------------------------------------------------------------------
166** Mac OS X functions for playing a sound.
167*/
168
169#if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
170
171#include <Carbon.h>
172#include <CoreAudio/AudioHardware.h>
173
174#define MACOSX_MAGIC MAKE_MAGIC ('M', 'a', 'c', ' ', 'O', 'S', ' ', 'X')
175
176typedef struct
177{ int magic ;
178 AudioStreamBasicDescription format ;
179
180 UInt32 buf_size ;
181 AudioDeviceID device ;
182
183 int channels ;
184 int samplerate ;
185 int buffer_size ;
186 int done_playing ;
187
188 get_audio_callback_t callback ;
189
190 void *callback_data ;
191} MACOSX_AUDIO_OUT ;
192
193static AUDIO_OUT *macosx_open (int channels, int samplerate) ;
194static void macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
195static void macosx_close (AUDIO_OUT *audio_out) ;
196
197static OSStatus
198macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
199 const AudioBufferList* data_in, const AudioTimeStamp* time_in,
200 AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data) ;
201
202
203static AUDIO_OUT *
204macosx_open (int channels, int samplerate)
205{ MACOSX_AUDIO_OUT *macosx_out ;
206 OSStatus err ;
207 size_t count ;
208
209 if ((macosx_out = malloc (sizeof (MACOSX_AUDIO_OUT))) == NULL)
210 { perror ("macosx_open : malloc ") ;
211 exit (1) ;
212 } ;
213
214 macosx_out->magic = MACOSX_MAGIC ;
215 macosx_out->channels = channels ;
216 macosx_out->samplerate = samplerate ;
217
218 macosx_out->device = kAudioDeviceUnknown ;
219
220 /* get the default output device for the HAL */
221 count = sizeof (AudioDeviceID) ;
222 if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
223 &count, (void *) &(macosx_out->device))) != noErr)
224 { printf ("AudioHardwareGetProperty failed.\n") ;
225 free (macosx_out) ;
226 return NULL ;
227 } ;
228
229 /* get the buffersize that the default device uses for IO */
230 count = sizeof (UInt32) ;
231 if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyBufferSize,
232 &count, &(macosx_out->buffer_size))) != noErr)
233 { printf ("AudioDeviceGetProperty (AudioDeviceGetProperty) failed.\n") ;
234 free (macosx_out) ;
235 return NULL ;
236 } ;
237
238 /* get a description of the data format used by the default device */
239 count = sizeof (AudioStreamBasicDescription) ;
240 if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyStreamFormat,
241 &count, &(macosx_out->format))) != noErr)
242 { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
243 free (macosx_out) ;
244 return NULL ;
245 } ;
246
247 macosx_out->format.mSampleRate = samplerate ;
248 macosx_out->format.mChannelsPerFrame = channels ;
249
250 if ((err = AudioDeviceSetProperty (macosx_out->device, NULL, 0, false, kAudioDevicePropertyStreamFormat,
251 sizeof (AudioStreamBasicDescription), &(macosx_out->format))) != noErr)
252 { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
253 free (macosx_out) ;
254 return NULL ;
255 } ;
256
257 /* we want linear pcm */
258 if (macosx_out->format.mFormatID != kAudioFormatLinearPCM)
259 { free (macosx_out) ;
260 return NULL ;
261 } ;
262
263 macosx_out->done_playing = 0 ;
264
265 /* Fire off the device. */
266 if ((err = AudioDeviceAddIOProc (macosx_out->device, macosx_audio_out_callback,
267 (void *) macosx_out)) != noErr)
268 { printf ("AudioDeviceAddIOProc failed.\n") ;
269 free (macosx_out) ;
270 return NULL ;
271 } ;
272
273 return (MACOSX_AUDIO_OUT *) macosx_out ;
274} /* macosx_open */
275
276static void
277macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
278{ MACOSX_AUDIO_OUT *macosx_out ;
279 OSStatus err ;
280
281 if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
282 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
283 return ;
284 } ;
285
286 if (macosx_out->magic != MACOSX_MAGIC)
287 { printf ("macosx_play : Bad magic number.\n") ;
288 return ;
289 } ;
290
291 /* Set the callback function and callback data. */
292 macosx_out->callback = callback ;
293 macosx_out->callback_data = callback_data ;
294
295 err = AudioDeviceStart (macosx_out->device, macosx_audio_out_callback) ;
296 if (err != noErr)
297 printf ("AudioDeviceStart failed.\n") ;
298
299 while (macosx_out->done_playing == SF_FALSE)
300 usleep (10 * 1000) ; /* 10 000 milliseconds. */
301
302 return ;
303} /* macosx_play */
304
305static void
306macosx_close (AUDIO_OUT *audio_out)
307{ MACOSX_AUDIO_OUT *macosx_out ;
308 OSStatus err ;
309
310 if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
311 { printf ("macosx_close : AUDIO_OUT is NULL.\n") ;
312 return ;
313 } ;
314
315 if (macosx_out->magic != MACOSX_MAGIC)
316 { printf ("macosx_close : Bad magic number.\n") ;
317 return ;
318 } ;
319
320
321 if ((err = AudioDeviceStop (macosx_out->device, macosx_audio_out_callback)) != noErr)
322 { printf ("AudioDeviceStop failed.\n") ;
323 return ;
324 } ;
325
326 err = AudioDeviceRemoveIOProc (macosx_out->device, macosx_audio_out_callback) ;
327 if (err != noErr)
328 { printf ("AudioDeviceRemoveIOProc failed.\n") ;
329 return ;
330 } ;
331
332} /* macosx_close */
333
334static OSStatus
335macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
336 const AudioBufferList* data_in, const AudioTimeStamp* time_in,
337 AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data)
338{ MACOSX_AUDIO_OUT *macosx_out ;
339 int k, size, sample_count, read_count ;
340 float *buffer ;
341
342 if ((macosx_out = (MACOSX_AUDIO_OUT*) client_data) == NULL)
343 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
344 return 42 ;
345 } ;
346
347 if (macosx_out->magic != MACOSX_MAGIC)
348 { printf ("macosx_play : Bad magic number.\n") ;
349 return 42 ;
350 } ;
351
352 size = data_out->mBuffers [0].mDataByteSize ;
353 sample_count = size / sizeof (float) / macosx_out->channels ;
354
355 buffer = (float*) data_out->mBuffers [0].mData ;
356
357 read_count = macosx_out->callback (macosx_out->callback_data, buffer, sample_count) ;
358
359 if (read_count < sample_count)
360 { memset (&(buffer [read_count]), 0, (sample_count - read_count) * sizeof (float)) ;
361 macosx_out->done_playing = 1 ;
362 } ;
363
364 return noErr ;
365} /* macosx_audio_out_callback */
366
367#endif /* MacOSX */
368
369
370/*------------------------------------------------------------------------------
371** Win32 functions for playing a sound.
372**
373** This API sucks. Its needlessly complicated and is *WAY* too loose with
374** passing pointers arounf in integers and and using char* pointers to
375** point to data instead of short*. It plain sucks!
376*/
377
378#if (defined (_WIN32) || defined (WIN32))
379
380#include <windows.h>
381#include <mmsystem.h>
382
383#define WIN32_BUFFER_LEN (1<<15)
384#define WIN32_MAGIC MAKE_MAGIC ('W', 'i', 'n', '3', '2', 's', 'u', 'x')
385
386typedef struct
387{ int magic ;
388
389 HWAVEOUT hwave ;
390 WAVEHDR whdr [2] ;
391
392 HANDLE Event ;
393
394 short short_buffer [WIN32_BUFFER_LEN / sizeof (short)] ;
395 float float_buffer [WIN32_BUFFER_LEN / sizeof (short) / 2] ;
396
397 int bufferlen, current ;
398
399 int channels ;
400
401 get_audio_callback_t callback ;
402
403 void *callback_data ;
404} WIN32_AUDIO_OUT ;
405
406static AUDIO_OUT *win32_open (int channels, int samplerate) ;
407static void win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
408static void win32_close (AUDIO_OUT *audio_out) ;
409
410static DWORD CALLBACK
411 win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2) ;
412
413static AUDIO_OUT*
414win32_open (int channels, int samplerate)
415{ WIN32_AUDIO_OUT *win32_out ;
416
417 WAVEFORMATEX wf ;
418 int error ;
419
420 if ((win32_out = malloc (sizeof (WIN32_AUDIO_OUT))) == NULL)
421 { perror ("win32_open : malloc ") ;
422 exit (1) ;
423 } ;
424
425 win32_out->magic = WIN32_MAGIC ;
426 win32_out->channels = channels ;
427
428 win32_out->current = 0 ;
429
430 win32_out->Event = CreateEvent (0, FALSE, FALSE, 0) ;
431
432 wf.nChannels = channels ;
433 wf.nSamplesPerSec = samplerate ;
434 wf.nBlockAlign = channels * sizeof (short) ;
435
436 wf.wFormatTag = WAVE_FORMAT_PCM ;
437 wf.cbSize = 0 ;
438 wf.wBitsPerSample = 16 ;
439 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ;
440
441 error = waveOutOpen (&(win32_out->hwave), WAVE_MAPPER, &wf, (DWORD) win32_audio_out_callback,
442 (DWORD) win32_out, CALLBACK_FUNCTION) ;
443 if (error)
444 { puts ("waveOutOpen failed.") ;
445 free (win32_out) ;
446 return NULL ;
447 } ;
448
449 waveOutPause (win32_out->hwave) ;
450
451 return (WIN32_AUDIO_OUT *) win32_out ;
452} /* win32_open */
453
454static void
455win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
456{ WIN32_AUDIO_OUT *win32_out ;
457 int error ;
458
459 if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
460 { printf ("win32_play : AUDIO_OUT is NULL.\n") ;
461 return ;
462 } ;
463
464 if (win32_out->magic != WIN32_MAGIC)
465 { printf ("win32_play : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
466 return ;
467 } ;
468
469 /* Set the callback function and callback data. */
470 win32_out->callback = callback ;
471 win32_out->callback_data = callback_data ;
472
473 win32_out->whdr [0].lpData = (char*) win32_out->short_buffer ;
474 win32_out->whdr [1].lpData = ((char*) win32_out->short_buffer) + sizeof (win32_out->short_buffer) / 2 ;
475
476 win32_out->whdr [0].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
477 win32_out->whdr [1].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
478
479 win32_out->bufferlen = sizeof (win32_out->short_buffer) / 2 / sizeof (short) ;
480
481 /* Prepare the WAVEHDRs */
482 if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR))))
483 { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ;
484 waveOutClose (win32_out->hwave) ;
485 return ;
486 } ;
487
488 if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR))))
489 { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ;
490 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
491 waveOutClose (win32_out->hwave) ;
492 return ;
493 } ;
494
495 waveOutRestart (win32_out->hwave) ;
496
497 /* Fake 2 calls to the callback function to queue up enough audio. */
498 win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
499 win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
500
501 /* Wait for playback to finish. The callback notifies us when all
502 ** wave data has been played.
503 */
504 WaitForSingleObject (win32_out->Event, INFINITE) ;
505
506 waveOutPause (win32_out->hwave) ;
507 waveOutReset (win32_out->hwave) ;
508
509 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
510 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR)) ;
511
512 waveOutClose (win32_out->hwave) ;
513 win32_out->hwave = 0 ;
514
515 return ;
516} /* win32_play */
517
518static void
519win32_close (AUDIO_OUT *audio_out)
520{ WIN32_AUDIO_OUT *win32_out ;
521
522 if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
523 { printf ("win32_close : AUDIO_OUT is NULL.\n") ;
524 return ;
525 } ;
526
527 if (win32_out->magic != WIN32_MAGIC)
528 { printf ("win32_close : Bad magic number.\n") ;
529 return ;
530 } ;
531
532 memset (win32_out, 0, sizeof (WIN32_AUDIO_OUT)) ;
533
534 free (win32_out) ;
535} /* win32_close */
536
537static DWORD CALLBACK
538win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2)
539{ WIN32_AUDIO_OUT *win32_out ;
540 int read_count, sample_count, k ;
541 short *sptr ;
542
543 /*
544 ** I consider this technique of passing a pointer via an integer as
545 ** fundamentally broken but thats the way microsoft has defined the
546 ** interface.
547 */
548 if ((win32_out = (WIN32_AUDIO_OUT*) data) == NULL)
549 { printf ("win32_audio_out_callback : AUDIO_OUT is NULL.\n") ;
550 return 1 ;
551 } ;
552
553 if (win32_out->magic != WIN32_MAGIC)
554 { printf ("win32_audio_out_callback : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
555 return 1 ;
556 } ;
557
558 if (msg != MM_WOM_DONE)
559 return 0 ;
560
561 /* Do the actual audio. */
562 sample_count = win32_out->bufferlen ;
563
564 read_count = win32_out->callback (win32_out->callback_data, win32_out->float_buffer, sample_count) ;
565
566 sptr = (short*) win32_out->whdr [win32_out->current].lpData ;
567
568 for (k = 0 ; k < read_count ; k++)
569 sptr [k] = lrint (32767.0 * win32_out->float_buffer [k]) ;
570
571 if (read_count > 0)
572 { /* Fix buffer length is only a partial block. */
573 if (read_count * sizeof (short) < win32_out->bufferlen)
574 win32_out->whdr [win32_out->current].dwBufferLength = read_count * sizeof (short) ;
575
576 /* Queue the WAVEHDR */
577 waveOutWrite (win32_out->hwave, (LPWAVEHDR) &(win32_out->whdr [win32_out->current]), sizeof (WAVEHDR)) ;
578 }
579 else
580 { /* Stop playback */
581 waveOutPause (win32_out->hwave) ;
582
583 SetEvent (win32_out->Event) ;
584 } ;
585
586 win32_out->current = (win32_out->current + 1) % 2 ;
587
588 return 0 ;
589} /* win32_audio_out_callback */
590
591#endif /* Win32 */
592
593/*------------------------------------------------------------------------------
594** Solaris.
595*/
596
597#if (defined (sun) && defined (unix)) /* ie Solaris */
598
599#include <fcntl.h>
600#include <sys/ioctl.h>
601#include <sys/audioio.h>
602
603#define SOLARIS_MAGIC MAKE_MAGIC ('S', 'o', 'l', 'a', 'r', 'i', 's', ' ')
604
605typedef struct
606{ int magic ;
607 int fd ;
608 int channels ;
609 int samplerate ;
610} SOLARIS_AUDIO_OUT ;
611
612static AUDIO_OUT *solaris_open (int channels, int samplerate) ;
613static void solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
614static void solaris_close (AUDIO_OUT *audio_out) ;
615
616static AUDIO_OUT *
617solaris_open (int channels, int samplerate)
618{ SOLARIS_AUDIO_OUT *solaris_out ;
619 audio_info_t audio_info ;
620 int error ;
621
622 if ((solaris_out = malloc (sizeof (SOLARIS_AUDIO_OUT))) == NULL)
623 { perror ("solaris_open : malloc ") ;
624 exit (1) ;
625 } ;
626
627 solaris_out->magic = SOLARIS_MAGIC ;
628 solaris_out->channels = channels ;
629 solaris_out->samplerate = channels ;
630
631 /* open the audio device - write only, non-blocking */
632 if ((solaris_out->fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0)
633 { perror ("open (/dev/audio) failed") ;
634 exit (1) ;
635 } ;
636
637 /* Retrive standard values. */
638 AUDIO_INITINFO (&audio_info) ;
639
640 audio_info.play.sample_rate = samplerate ;
641 audio_info.play.channels = channels ;
642 audio_info.play.precision = 16 ;
643 audio_info.play.encoding = AUDIO_ENCODING_LINEAR ;
644 audio_info.play.gain = AUDIO_MAX_GAIN ;
645 audio_info.play.balance = AUDIO_MID_BALANCE ;
646
647 if ((error = ioctl (solaris_out->fd, AUDIO_SETINFO, &audio_info)))
648 { perror ("ioctl (AUDIO_SETINFO) failed") ;
649 exit (1) ;
650 } ;
651
652 return (AUDIO_OUT*) solaris_out ;
653} /* solaris_open */
654
655static void
656solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
657{ SOLARIS_AUDIO_OUT *solaris_out ;
658 static float float_buffer [BUFFER_LEN] ;
659 static short buffer [BUFFER_LEN] ;
660 int k, readcount ;
661
662 if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
663 { printf ("solaris_play : AUDIO_OUT is NULL.\n") ;
664 return ;
665 } ;
666
667 if (solaris_out->magic != SOLARIS_MAGIC)
668 { printf ("solaris_play : Bad magic number.\n") ;
669 return ;
670 } ;
671
672 while ((readcount = callback (callback_data, float_buffer, BUFFER_LEN / solaris_out->channels)))
673 { for (k = 0 ; k < readcount * solaris_out->channels ; k++)
674 buffer [k] = lrint (32767.0 * float_buffer [k]) ;
675 write (solaris_out->fd, buffer, readcount * solaris_out->channels * sizeof (short)) ;
676 } ;
677
678 return ;
679} /* solaris_play */
680
681static void
682solaris_close (AUDIO_OUT *audio_out)
683{ SOLARIS_AUDIO_OUT *solaris_out ;
684
685 if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
686 { printf ("solaris_close : AUDIO_OUT is NULL.\n") ;
687 return ;
688 } ;
689
690 if (solaris_out->magic != SOLARIS_MAGIC)
691 { printf ("solaris_close : Bad magic number.\n") ;
692 return ;
693 } ;
694
695 memset (solaris_out, 0, sizeof (SOLARIS_AUDIO_OUT)) ;
696
697 free (solaris_out) ;
698
699 return ;
700} /* solaris_close */
701
702#endif /* Solaris */
703
704/*==============================================================================
705** Main function.
706*/
707
708AUDIO_OUT *
709audio_open (int channels, int samplerate)
710{
711#if defined (__linux__)
712 return linux_open (channels, samplerate) ;
713#elif (defined (__MACH__) && defined (__APPLE__))
714 return macosx_open (channels, samplerate) ;
715#elif (defined (sun) && defined (unix))
716 return solaris_open (channels, samplerate) ;
717#elif (defined (_WIN32) || defined (WIN32))
718 return win32_open (channels, samplerate) ;
719#else
720 #warning "*** Playing sound not yet supported on this platform."
721 #warning "*** Please feel free to submit a patch."
722 printf ("Error : Playing sound not yet supported on this platform.\n") ;
723 return NULL ;
724#endif
725
726
727 return NULL ;
728} /* audio_open */
729
730void
731audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
732{
733
734 if (callback == NULL)
735 { printf ("Error : bad callback pointer.\n") ;
736 return ;
737 } ;
738
739 if (audio_out == NULL)
740 { printf ("Error : bad audio_out pointer.\n") ;
741 return ;
742 } ;
743
744 if (callback_data == NULL)
745 { printf ("Error : bad callback_data pointer.\n") ;
746 return ;
747 } ;
748
749#if defined (__linux__)
750 linux_play (callback, audio_out, callback_data) ;
751#elif (defined (__MACH__) && defined (__APPLE__))
752 macosx_play (callback, audio_out, callback_data) ;
753#elif (defined (sun) && defined (unix))
754 solaris_play (callback, audio_out, callback_data) ;
755#elif (defined (_WIN32) || defined (WIN32))
756 win32_play (callback, audio_out, callback_data) ;
757#else
758 #warning "*** Playing sound not yet supported on this platform."
759 #warning "*** Please feel free to submit a patch."
760 printf ("Error : Playing sound not yet supported on this platform.\n") ;
761 return ;
762#endif
763
764 return ;
765} /* audio_play */
766
767void
768audio_close (AUDIO_OUT *audio_out)
769{
770#if defined (__linux__)
771 linux_close (audio_out) ;
772#elif (defined (__MACH__) && defined (__APPLE__))
773 macosx_close (audio_out) ;
774#elif (defined (sun) && defined (unix))
775 solaris_close (audio_out) ;
776#elif (defined (_WIN32) || defined (WIN32))
777 win32_close (audio_out) ;
778#else
779 #warning "*** Playing sound not yet supported on this platform."
780 #warning "*** Please feel free to submit a patch."
781 printf ("Error : Playing sound not yet supported on this platform.\n") ;
782 return ;
783#endif
784
785 return ;
786} /* audio_close */
787
788#else /* (HAVE_SNDFILE == 0) */
789
790/* Do not have libsndfile installed so just return. */
791
792AUDIO_OUT *
793audio_open (int channels, int samplerate)
794{
795 (void) channels ;
796 (void) samplerate ;
797
798 return NULL ;
799} /* audio_open */
800
801void
802audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
803{
804 (void) callback ;
805 (void) audio_out ;
806 (void) callback_data ;
807
808 return ;
809} /* audio_play */
810
811void
812audio_close (AUDIO_OUT *audio_out)
813{
814 audio_out = audio_out ;
815
816 return ;
817} /* audio_close */
818
819#endif /* HAVE_SNDFILE */
820