annotate src/libsamplerate-0.1.9/examples/audio_out.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 481f5f8c5634
children
rev   line source
Chris@41 1 /*
Chris@41 2 ** Copyright (c) 1999-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
Chris@41 3 ** All rights reserved.
Chris@41 4 **
Chris@41 5 ** This code is released under 2-clause BSD license. Please see the
Chris@41 6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
Chris@41 7 */
Chris@41 8
Chris@41 9 #include <stdio.h>
Chris@41 10 #include <stdlib.h>
Chris@41 11 #include <string.h>
Chris@41 12 #include <unistd.h>
Chris@41 13
Chris@41 14 #include <config.h>
Chris@41 15
Chris@41 16 #include "audio_out.h"
Chris@41 17
Chris@41 18 #if HAVE_ALSA_ASOUNDLIB_H
Chris@41 19 #define ALSA_PCM_NEW_HW_PARAMS_API
Chris@41 20 #define ALSA_PCM_NEW_SW_PARAMS_API
Chris@41 21 #include <alsa/asoundlib.h>
Chris@41 22 #include <sys/time.h>
Chris@41 23 #endif
Chris@41 24
Chris@41 25 #if (HAVE_SNDFILE)
Chris@41 26
Chris@41 27 #include <float_cast.h>
Chris@41 28
Chris@41 29 #include <sndfile.h>
Chris@41 30
Chris@41 31 #define BUFFER_LEN (2048)
Chris@41 32
Chris@41 33 #define MAKE_MAGIC(a,b,c,d,e,f,g,h) \
Chris@41 34 ((a) + ((b) << 1) + ((c) << 2) + ((d) << 3) + ((e) << 4) + ((f) << 5) + ((g) << 6) + ((h) << 7))
Chris@41 35
Chris@41 36 typedef struct AUDIO_OUT_s
Chris@41 37 { int magic ;
Chris@41 38 } AUDIO_OUT ;
Chris@41 39
Chris@41 40
Chris@41 41 /*------------------------------------------------------------------------------
Chris@41 42 ** Linux (ALSA and OSS) functions for playing a sound.
Chris@41 43 */
Chris@41 44
Chris@41 45 #if defined (__linux__)
Chris@41 46
Chris@41 47 #if HAVE_ALSA_ASOUNDLIB_H
Chris@41 48
Chris@41 49 #define ALSA_MAGIC MAKE_MAGIC ('L', 'n', 'x', '-', 'A', 'L', 'S', 'A')
Chris@41 50
Chris@41 51 typedef struct
Chris@41 52 { int magic ;
Chris@41 53 snd_pcm_t * dev ;
Chris@41 54 int channels ;
Chris@41 55 } ALSA_AUDIO_OUT ;
Chris@41 56
Chris@41 57 static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ;
Chris@41 58
Chris@41 59 static AUDIO_OUT *
Chris@41 60 alsa_open (int channels, unsigned samplerate)
Chris@41 61 { ALSA_AUDIO_OUT *alsa_out ;
Chris@41 62 const char * device = "default" ;
Chris@41 63 snd_pcm_hw_params_t *hw_params ;
Chris@41 64 snd_pcm_uframes_t buffer_size ;
Chris@41 65 snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
Chris@41 66 snd_pcm_sw_params_t *sw_params ;
Chris@41 67
Chris@41 68 int err ;
Chris@41 69
Chris@41 70 alsa_period_size = 1024 ;
Chris@41 71 alsa_buffer_frames = 4 * alsa_period_size ;
Chris@41 72
Chris@41 73 if ((alsa_out = calloc (1, sizeof (ALSA_AUDIO_OUT))) == NULL)
Chris@41 74 { perror ("alsa_open : malloc ") ;
Chris@41 75 exit (1) ;
Chris@41 76 } ;
Chris@41 77
Chris@41 78 alsa_out->magic = ALSA_MAGIC ;
Chris@41 79 alsa_out->channels = channels ;
Chris@41 80
Chris@41 81 if ((err = snd_pcm_open (&alsa_out->dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
Chris@41 82 { fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
Chris@41 83 goto catch_error ;
Chris@41 84 } ;
Chris@41 85
Chris@41 86 snd_pcm_nonblock (alsa_out->dev, 0) ;
Chris@41 87
Chris@41 88 if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
Chris@41 89 { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
Chris@41 90 goto catch_error ;
Chris@41 91 } ;
Chris@41 92
Chris@41 93 if ((err = snd_pcm_hw_params_any (alsa_out->dev, hw_params)) < 0)
Chris@41 94 { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
Chris@41 95 goto catch_error ;
Chris@41 96 } ;
Chris@41 97
Chris@41 98 if ((err = snd_pcm_hw_params_set_access (alsa_out->dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
Chris@41 99 { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
Chris@41 100 goto catch_error ;
Chris@41 101 } ;
Chris@41 102
Chris@41 103 if ((err = snd_pcm_hw_params_set_format (alsa_out->dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
Chris@41 104 { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
Chris@41 105 goto catch_error ;
Chris@41 106 } ;
Chris@41 107
Chris@41 108 if ((err = snd_pcm_hw_params_set_rate_near (alsa_out->dev, hw_params, &samplerate, 0)) < 0)
Chris@41 109 { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
Chris@41 110 goto catch_error ;
Chris@41 111 } ;
Chris@41 112
Chris@41 113 if ((err = snd_pcm_hw_params_set_channels (alsa_out->dev, hw_params, channels)) < 0)
Chris@41 114 { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
Chris@41 115 goto catch_error ;
Chris@41 116 } ;
Chris@41 117
Chris@41 118 if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_out->dev, hw_params, &alsa_buffer_frames)) < 0)
Chris@41 119 { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
Chris@41 120 goto catch_error ;
Chris@41 121 } ;
Chris@41 122
Chris@41 123 if ((err = snd_pcm_hw_params_set_period_size_near (alsa_out->dev, hw_params, &alsa_period_size, 0)) < 0)
Chris@41 124 { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
Chris@41 125 goto catch_error ;
Chris@41 126 } ;
Chris@41 127
Chris@41 128 if ((err = snd_pcm_hw_params (alsa_out->dev, hw_params)) < 0)
Chris@41 129 { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
Chris@41 130 goto catch_error ;
Chris@41 131 } ;
Chris@41 132
Chris@41 133 /* extra check: if we have only one period, this code won't work */
Chris@41 134 snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
Chris@41 135 snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
Chris@41 136 if (alsa_period_size == buffer_size)
Chris@41 137 { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
Chris@41 138 goto catch_error ;
Chris@41 139 } ;
Chris@41 140
Chris@41 141 snd_pcm_hw_params_free (hw_params) ;
Chris@41 142
Chris@41 143 if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
Chris@41 144 { fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
Chris@41 145 goto catch_error ;
Chris@41 146 } ;
Chris@41 147
Chris@41 148 if ((err = snd_pcm_sw_params_current (alsa_out->dev, sw_params)) != 0)
Chris@41 149 { fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
Chris@41 150 goto catch_error ;
Chris@41 151 } ;
Chris@41 152
Chris@41 153 /* note: set start threshold to delay start until the ring buffer is full */
Chris@41 154 snd_pcm_sw_params_current (alsa_out->dev, sw_params) ;
Chris@41 155
Chris@41 156 if ((err = snd_pcm_sw_params_set_start_threshold (alsa_out->dev, sw_params, buffer_size)) < 0)
Chris@41 157 { fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
Chris@41 158 goto catch_error ;
Chris@41 159 } ;
Chris@41 160
Chris@41 161 if ((err = snd_pcm_sw_params (alsa_out->dev, sw_params)) != 0)
Chris@41 162 { fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
Chris@41 163 goto catch_error ;
Chris@41 164 } ;
Chris@41 165
Chris@41 166 snd_pcm_sw_params_free (sw_params) ;
Chris@41 167
Chris@41 168 snd_pcm_reset (alsa_out->dev) ;
Chris@41 169
Chris@41 170 catch_error :
Chris@41 171
Chris@41 172 if (err < 0 && alsa_out->dev != NULL)
Chris@41 173 { snd_pcm_close (alsa_out->dev) ;
Chris@41 174 return NULL ;
Chris@41 175 } ;
Chris@41 176
Chris@41 177 return (AUDIO_OUT *) alsa_out ;
Chris@41 178 } /* alsa_open */
Chris@41 179
Chris@41 180 static void
Chris@41 181 alsa_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 182 { static float buffer [BUFFER_LEN] ;
Chris@41 183 ALSA_AUDIO_OUT *alsa_out ;
Chris@41 184 int read_frames ;
Chris@41 185
Chris@41 186 if ((alsa_out = (ALSA_AUDIO_OUT*) audio_out) == NULL)
Chris@41 187 { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
Chris@41 188 return ;
Chris@41 189 } ;
Chris@41 190
Chris@41 191 if (alsa_out->magic != ALSA_MAGIC)
Chris@41 192 { printf ("alsa_close : Bad magic number.\n") ;
Chris@41 193 return ;
Chris@41 194 } ;
Chris@41 195
Chris@41 196 while ((read_frames = callback (callback_data, buffer, BUFFER_LEN / alsa_out->channels)))
Chris@41 197 alsa_write_float (alsa_out->dev, buffer, read_frames, alsa_out->channels) ;
Chris@41 198
Chris@41 199 return ;
Chris@41 200 } /* alsa_play */
Chris@41 201
Chris@41 202 static int
Chris@41 203 alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels)
Chris@41 204 { static int epipe_count = 0 ;
Chris@41 205
Chris@41 206 int total = 0 ;
Chris@41 207 int retval ;
Chris@41 208
Chris@41 209 if (epipe_count > 0)
Chris@41 210 epipe_count -- ;
Chris@41 211
Chris@41 212 while (total < frames)
Chris@41 213 { retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ;
Chris@41 214
Chris@41 215 if (retval >= 0)
Chris@41 216 { total += retval ;
Chris@41 217 if (total == frames)
Chris@41 218 return total ;
Chris@41 219
Chris@41 220 continue ;
Chris@41 221 } ;
Chris@41 222
Chris@41 223 switch (retval)
Chris@41 224 { case -EAGAIN :
Chris@41 225 puts ("alsa_write_float: EAGAIN") ;
Chris@41 226 continue ;
Chris@41 227 break ;
Chris@41 228
Chris@41 229 case -EPIPE :
Chris@41 230 if (epipe_count > 0)
Chris@41 231 { printf ("alsa_write_float: EPIPE %d\n", epipe_count) ;
Chris@41 232 if (epipe_count > 140)
Chris@41 233 return retval ;
Chris@41 234 } ;
Chris@41 235 epipe_count += 100 ;
Chris@41 236
Chris@41 237 #if 0
Chris@41 238 if (0)
Chris@41 239 { snd_pcm_status_t *status ;
Chris@41 240
Chris@41 241 snd_pcm_status_alloca (&status) ;
Chris@41 242 if ((retval = snd_pcm_status (alsa_dev, status)) < 0)
Chris@41 243 fprintf (stderr, "alsa_out: xrun. can't determine length\n") ;
Chris@41 244 else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN)
Chris@41 245 { struct timeval now, diff, tstamp ;
Chris@41 246
Chris@41 247 gettimeofday (&now, 0) ;
Chris@41 248 snd_pcm_status_get_trigger_tstamp (status, &tstamp) ;
Chris@41 249 timersub (&now, &tstamp, &diff) ;
Chris@41 250
Chris@41 251 fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",
Chris@41 252 diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ;
Chris@41 253 }
Chris@41 254 else
Chris@41 255 fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ;
Chris@41 256 } ;
Chris@41 257 #endif
Chris@41 258
Chris@41 259 snd_pcm_prepare (alsa_dev) ;
Chris@41 260 break ;
Chris@41 261
Chris@41 262 case -EBADFD :
Chris@41 263 fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;
Chris@41 264 return 0 ;
Chris@41 265 break ;
Chris@41 266
Chris@41 267 case -ESTRPIPE :
Chris@41 268 fprintf (stderr, "alsa_write_float: Suspend event.n") ;
Chris@41 269 return 0 ;
Chris@41 270 break ;
Chris@41 271
Chris@41 272 case -EIO :
Chris@41 273 puts ("alsa_write_float: EIO") ;
Chris@41 274 return 0 ;
Chris@41 275
Chris@41 276 default :
Chris@41 277 fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ;
Chris@41 278 return 0 ;
Chris@41 279 break ;
Chris@41 280 } ; /* switch */
Chris@41 281 } ; /* while */
Chris@41 282
Chris@41 283 return total ;
Chris@41 284 } /* alsa_write_float */
Chris@41 285
Chris@41 286 static void
Chris@41 287 alsa_close (AUDIO_OUT *audio_out)
Chris@41 288 { ALSA_AUDIO_OUT *alsa_out ;
Chris@41 289
Chris@41 290 if ((alsa_out = (ALSA_AUDIO_OUT*) audio_out) == NULL)
Chris@41 291 { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
Chris@41 292 return ;
Chris@41 293 } ;
Chris@41 294
Chris@41 295 if (alsa_out->magic != ALSA_MAGIC)
Chris@41 296 { printf ("alsa_close : Bad magic number.\n") ;
Chris@41 297 return ;
Chris@41 298 } ;
Chris@41 299
Chris@41 300 memset (alsa_out, 0, sizeof (ALSA_AUDIO_OUT)) ;
Chris@41 301
Chris@41 302 free (alsa_out) ;
Chris@41 303
Chris@41 304 return ;
Chris@41 305 } /* alsa_close */
Chris@41 306
Chris@41 307 #endif /* HAVE_ALSA_ASOUNDLIB_H */
Chris@41 308
Chris@41 309 #include <fcntl.h>
Chris@41 310 #include <sys/ioctl.h>
Chris@41 311 #include <sys/soundcard.h>
Chris@41 312
Chris@41 313 #define OSS_MAGIC MAKE_MAGIC ('L', 'i', 'n', 'u', 'x', 'O', 'S', 'S')
Chris@41 314
Chris@41 315 typedef struct
Chris@41 316 { int magic ;
Chris@41 317 int fd ;
Chris@41 318 int channels ;
Chris@41 319 } OSS_AUDIO_OUT ;
Chris@41 320
Chris@41 321 static AUDIO_OUT *opensoundsys_open (int channels, int samplerate) ;
Chris@41 322 static void opensoundsys_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
Chris@41 323 static void opensoundsys_close (AUDIO_OUT *audio_out) ;
Chris@41 324
Chris@41 325
Chris@41 326 static AUDIO_OUT *
Chris@41 327 opensoundsys_open (int channels, int samplerate)
Chris@41 328 { OSS_AUDIO_OUT *opensoundsys_out ;
Chris@41 329 int stereo, fmt, error ;
Chris@41 330
Chris@41 331 if ((opensoundsys_out = calloc (1, sizeof (OSS_AUDIO_OUT))) == NULL)
Chris@41 332 { perror ("opensoundsys_open : malloc ") ;
Chris@41 333 exit (1) ;
Chris@41 334 } ;
Chris@41 335
Chris@41 336 opensoundsys_out->magic = OSS_MAGIC ;
Chris@41 337 opensoundsys_out->channels = channels ;
Chris@41 338
Chris@41 339 if ((opensoundsys_out->fd = open ("/dev/dsp", O_WRONLY, 0)) == -1)
Chris@41 340 { perror ("opensoundsys_open : open ") ;
Chris@41 341 exit (1) ;
Chris@41 342 } ;
Chris@41 343
Chris@41 344 stereo = 0 ;
Chris@41 345 if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_STEREO, &stereo) == -1)
Chris@41 346 { /* Fatal error */
Chris@41 347 perror ("opensoundsys_open : stereo ") ;
Chris@41 348 exit (1) ;
Chris@41 349 } ;
Chris@41 350
Chris@41 351 if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_RESET, 0))
Chris@41 352 { perror ("opensoundsys_open : reset ") ;
Chris@41 353 exit (1) ;
Chris@41 354 } ;
Chris@41 355
Chris@41 356 fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
Chris@41 357 if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_SETFMT, &fmt) != 0)
Chris@41 358 { perror ("opensoundsys_open_dsp_device : set format ") ;
Chris@41 359 exit (1) ;
Chris@41 360 } ;
Chris@41 361
Chris@41 362 if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_CHANNELS, &channels)) != 0)
Chris@41 363 { perror ("opensoundsys_open : channels ") ;
Chris@41 364 exit (1) ;
Chris@41 365 } ;
Chris@41 366
Chris@41 367 if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_SPEED, &samplerate)) != 0)
Chris@41 368 { perror ("opensoundsys_open : sample rate ") ;
Chris@41 369 exit (1) ;
Chris@41 370 } ;
Chris@41 371
Chris@41 372 if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_SYNC, 0)) != 0)
Chris@41 373 { perror ("opensoundsys_open : sync ") ;
Chris@41 374 exit (1) ;
Chris@41 375 } ;
Chris@41 376
Chris@41 377 return (AUDIO_OUT*) opensoundsys_out ;
Chris@41 378 } /* opensoundsys_open */
Chris@41 379
Chris@41 380 static void
Chris@41 381 opensoundsys_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 382 { OSS_AUDIO_OUT *opensoundsys_out ;
Chris@41 383 static float float_buffer [BUFFER_LEN] ;
Chris@41 384 static short buffer [BUFFER_LEN] ;
Chris@41 385 int k, read_frames ;
Chris@41 386
Chris@41 387 if ((opensoundsys_out = (OSS_AUDIO_OUT*) audio_out) == NULL)
Chris@41 388 { printf ("opensoundsys_play : AUDIO_OUT is NULL.\n") ;
Chris@41 389 return ;
Chris@41 390 } ;
Chris@41 391
Chris@41 392 if (opensoundsys_out->magic != OSS_MAGIC)
Chris@41 393 { printf ("opensoundsys_play : Bad magic number.\n") ;
Chris@41 394 return ;
Chris@41 395 } ;
Chris@41 396
Chris@41 397 while ((read_frames = callback (callback_data, float_buffer, BUFFER_LEN / opensoundsys_out->channels)))
Chris@41 398 { for (k = 0 ; k < read_frames * opensoundsys_out->channels ; k++)
Chris@41 399 buffer [k] = lrint (32767.0 * float_buffer [k]) ;
Chris@41 400 (void) write (opensoundsys_out->fd, buffer, read_frames * opensoundsys_out->channels * sizeof (short)) ;
Chris@41 401 } ;
Chris@41 402
Chris@41 403 return ;
Chris@41 404 } /* opensoundsys_play */
Chris@41 405
Chris@41 406 static void
Chris@41 407 opensoundsys_close (AUDIO_OUT *audio_out)
Chris@41 408 { OSS_AUDIO_OUT *opensoundsys_out ;
Chris@41 409
Chris@41 410 if ((opensoundsys_out = (OSS_AUDIO_OUT*) audio_out) == NULL)
Chris@41 411 { printf ("opensoundsys_close : AUDIO_OUT is NULL.\n") ;
Chris@41 412 return ;
Chris@41 413 } ;
Chris@41 414
Chris@41 415 if (opensoundsys_out->magic != OSS_MAGIC)
Chris@41 416 { printf ("opensoundsys_close : Bad magic number.\n") ;
Chris@41 417 return ;
Chris@41 418 } ;
Chris@41 419
Chris@41 420 memset (opensoundsys_out, 0, sizeof (OSS_AUDIO_OUT)) ;
Chris@41 421
Chris@41 422 free (opensoundsys_out) ;
Chris@41 423
Chris@41 424 return ;
Chris@41 425 } /* opensoundsys_close */
Chris@41 426
Chris@41 427 #endif /* __linux__ */
Chris@41 428
Chris@41 429 /*------------------------------------------------------------------------------
Chris@41 430 ** Mac OS X functions for playing a sound.
Chris@41 431 */
Chris@41 432
Chris@41 433 #if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
Chris@41 434
Chris@41 435 #include <Carbon.h>
Chris@41 436 #include <CoreAudio/AudioHardware.h>
Chris@41 437
Chris@41 438 #define MACOSX_MAGIC MAKE_MAGIC ('M', 'a', 'c', ' ', 'O', 'S', ' ', 'X')
Chris@41 439
Chris@41 440 typedef struct
Chris@41 441 { int magic ;
Chris@41 442 AudioStreamBasicDescription format ;
Chris@41 443
Chris@41 444 UInt32 buf_size ;
Chris@41 445 AudioDeviceID device ;
Chris@41 446
Chris@41 447 int channels ;
Chris@41 448 int samplerate ;
Chris@41 449 int buffer_size ;
Chris@41 450 int done_playing ;
Chris@41 451
Chris@41 452 get_audio_callback_t callback ;
Chris@41 453
Chris@41 454 void *callback_data ;
Chris@41 455 } MACOSX_AUDIO_OUT ;
Chris@41 456
Chris@41 457 static AUDIO_OUT *macosx_open (int channels, int samplerate) ;
Chris@41 458 static void macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
Chris@41 459 static void macosx_close (AUDIO_OUT *audio_out) ;
Chris@41 460
Chris@41 461 static OSStatus
Chris@41 462 macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
Chris@41 463 const AudioBufferList* data_in, const AudioTimeStamp* time_in,
Chris@41 464 AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data) ;
Chris@41 465
Chris@41 466
Chris@41 467 static AUDIO_OUT *
Chris@41 468 macosx_open (int channels, int samplerate)
Chris@41 469 { MACOSX_AUDIO_OUT *macosx_out ;
Chris@41 470 OSStatus err ;
Chris@41 471 size_t count ;
Chris@41 472
Chris@41 473 if ((macosx_out = calloc (1, sizeof (MACOSX_AUDIO_OUT))) == NULL)
Chris@41 474 { perror ("macosx_open : malloc ") ;
Chris@41 475 exit (1) ;
Chris@41 476 } ;
Chris@41 477
Chris@41 478 macosx_out->magic = MACOSX_MAGIC ;
Chris@41 479 macosx_out->channels = channels ;
Chris@41 480 macosx_out->samplerate = samplerate ;
Chris@41 481
Chris@41 482 macosx_out->device = kAudioDeviceUnknown ;
Chris@41 483
Chris@41 484 /* get the default output device for the HAL */
Chris@41 485 count = sizeof (AudioDeviceID) ;
Chris@41 486 if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
Chris@41 487 &count, (void *) &(macosx_out->device))) != noErr)
Chris@41 488 { printf ("AudioHardwareGetProperty failed.\n") ;
Chris@41 489 free (macosx_out) ;
Chris@41 490 return NULL ;
Chris@41 491 } ;
Chris@41 492
Chris@41 493 /* get the buffersize that the default device uses for IO */
Chris@41 494 count = sizeof (UInt32) ;
Chris@41 495 if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyBufferSize,
Chris@41 496 &count, &(macosx_out->buffer_size))) != noErr)
Chris@41 497 { printf ("AudioDeviceGetProperty (AudioDeviceGetProperty) failed.\n") ;
Chris@41 498 free (macosx_out) ;
Chris@41 499 return NULL ;
Chris@41 500 } ;
Chris@41 501
Chris@41 502 /* get a description of the data format used by the default device */
Chris@41 503 count = sizeof (AudioStreamBasicDescription) ;
Chris@41 504 if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyStreamFormat,
Chris@41 505 &count, &(macosx_out->format))) != noErr)
Chris@41 506 { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
Chris@41 507 free (macosx_out) ;
Chris@41 508 return NULL ;
Chris@41 509 } ;
Chris@41 510
Chris@41 511 macosx_out->format.mSampleRate = samplerate ;
Chris@41 512 macosx_out->format.mChannelsPerFrame = channels ;
Chris@41 513
Chris@41 514 if ((err = AudioDeviceSetProperty (macosx_out->device, NULL, 0, false, kAudioDevicePropertyStreamFormat,
Chris@41 515 sizeof (AudioStreamBasicDescription), &(macosx_out->format))) != noErr)
Chris@41 516 { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
Chris@41 517 free (macosx_out) ;
Chris@41 518 return NULL ;
Chris@41 519 } ;
Chris@41 520
Chris@41 521 /* we want linear pcm */
Chris@41 522 if (macosx_out->format.mFormatID != kAudioFormatLinearPCM)
Chris@41 523 { free (macosx_out) ;
Chris@41 524 return NULL ;
Chris@41 525 } ;
Chris@41 526
Chris@41 527 macosx_out->done_playing = 0 ;
Chris@41 528
Chris@41 529 /* Fire off the device. */
Chris@41 530 if ((err = AudioDeviceAddIOProc (macosx_out->device, macosx_audio_out_callback,
Chris@41 531 (void *) macosx_out)) != noErr)
Chris@41 532 { printf ("AudioDeviceAddIOProc failed.\n") ;
Chris@41 533 free (macosx_out) ;
Chris@41 534 return NULL ;
Chris@41 535 } ;
Chris@41 536
Chris@41 537 return (MACOSX_AUDIO_OUT *) macosx_out ;
Chris@41 538 } /* macosx_open */
Chris@41 539
Chris@41 540 static void
Chris@41 541 macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 542 { MACOSX_AUDIO_OUT *macosx_out ;
Chris@41 543 OSStatus err ;
Chris@41 544
Chris@41 545 if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
Chris@41 546 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
Chris@41 547 return ;
Chris@41 548 } ;
Chris@41 549
Chris@41 550 if (macosx_out->magic != MACOSX_MAGIC)
Chris@41 551 { printf ("macosx_play : Bad magic number.\n") ;
Chris@41 552 return ;
Chris@41 553 } ;
Chris@41 554
Chris@41 555 /* Set the callback function and callback data. */
Chris@41 556 macosx_out->callback = callback ;
Chris@41 557 macosx_out->callback_data = callback_data ;
Chris@41 558
Chris@41 559 err = AudioDeviceStart (macosx_out->device, macosx_audio_out_callback) ;
Chris@41 560 if (err != noErr)
Chris@41 561 printf ("AudioDeviceStart failed.\n") ;
Chris@41 562
Chris@41 563 while (macosx_out->done_playing == SF_FALSE)
Chris@41 564 usleep (10 * 1000) ; /* 10 000 milliseconds. */
Chris@41 565
Chris@41 566 return ;
Chris@41 567 } /* macosx_play */
Chris@41 568
Chris@41 569 static void
Chris@41 570 macosx_close (AUDIO_OUT *audio_out)
Chris@41 571 { MACOSX_AUDIO_OUT *macosx_out ;
Chris@41 572 OSStatus err ;
Chris@41 573
Chris@41 574 if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
Chris@41 575 { printf ("macosx_close : AUDIO_OUT is NULL.\n") ;
Chris@41 576 return ;
Chris@41 577 } ;
Chris@41 578
Chris@41 579 if (macosx_out->magic != MACOSX_MAGIC)
Chris@41 580 { printf ("macosx_close : Bad magic number.\n") ;
Chris@41 581 return ;
Chris@41 582 } ;
Chris@41 583
Chris@41 584
Chris@41 585 if ((err = AudioDeviceStop (macosx_out->device, macosx_audio_out_callback)) != noErr)
Chris@41 586 { printf ("AudioDeviceStop failed.\n") ;
Chris@41 587 return ;
Chris@41 588 } ;
Chris@41 589
Chris@41 590 err = AudioDeviceRemoveIOProc (macosx_out->device, macosx_audio_out_callback) ;
Chris@41 591 if (err != noErr)
Chris@41 592 { printf ("AudioDeviceRemoveIOProc failed.\n") ;
Chris@41 593 return ;
Chris@41 594 } ;
Chris@41 595
Chris@41 596 } /* macosx_close */
Chris@41 597
Chris@41 598 static OSStatus
Chris@41 599 macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
Chris@41 600 const AudioBufferList* data_in, const AudioTimeStamp* time_in,
Chris@41 601 AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data)
Chris@41 602 { MACOSX_AUDIO_OUT *macosx_out ;
Chris@41 603 int k, size, frame_count, read_count ;
Chris@41 604 float *buffer ;
Chris@41 605
Chris@41 606 if ((macosx_out = (MACOSX_AUDIO_OUT*) client_data) == NULL)
Chris@41 607 { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
Chris@41 608 return 42 ;
Chris@41 609 } ;
Chris@41 610
Chris@41 611 if (macosx_out->magic != MACOSX_MAGIC)
Chris@41 612 { printf ("macosx_play : Bad magic number.\n") ;
Chris@41 613 return 42 ;
Chris@41 614 } ;
Chris@41 615
Chris@41 616 size = data_out->mBuffers [0].mDataByteSize ;
Chris@41 617 frame_count = size / sizeof (float) / macosx_out->channels ;
Chris@41 618
Chris@41 619 buffer = (float*) data_out->mBuffers [0].mData ;
Chris@41 620
Chris@41 621 read_count = macosx_out->callback (macosx_out->callback_data, buffer, frame_count) ;
Chris@41 622
Chris@41 623 if (read_count < frame_count)
Chris@41 624 { memset (&(buffer [read_count]), 0, (frame_count - read_count) * sizeof (float)) ;
Chris@41 625 macosx_out->done_playing = 1 ;
Chris@41 626 } ;
Chris@41 627
Chris@41 628 return noErr ;
Chris@41 629 } /* macosx_audio_out_callback */
Chris@41 630
Chris@41 631 #endif /* MacOSX */
Chris@41 632
Chris@41 633
Chris@41 634 /*------------------------------------------------------------------------------
Chris@41 635 ** Win32 functions for playing a sound.
Chris@41 636 **
Chris@41 637 ** This API sucks. Its needlessly complicated and is *WAY* too loose with
Chris@41 638 ** passing pointers arounf in integers and and using char* pointers to
Chris@41 639 ** point to data instead of short*. It plain sucks!
Chris@41 640 */
Chris@41 641
Chris@41 642 #if (defined (_WIN32) || defined (WIN32))
Chris@41 643
Chris@41 644 #include <windows.h>
Chris@41 645 #include <mmsystem.h>
Chris@41 646
Chris@41 647 #define WIN32_BUFFER_LEN (1<<15)
Chris@41 648 #define WIN32_MAGIC MAKE_MAGIC ('W', 'i', 'n', '3', '2', 's', 'u', 'x')
Chris@41 649
Chris@41 650 typedef struct
Chris@41 651 { int magic ;
Chris@41 652
Chris@41 653 HWAVEOUT hwave ;
Chris@41 654 WAVEHDR whdr [2] ;
Chris@41 655
Chris@41 656 HANDLE Event ;
Chris@41 657
Chris@41 658 short short_buffer [WIN32_BUFFER_LEN / sizeof (short)] ;
Chris@41 659 float float_buffer [WIN32_BUFFER_LEN / sizeof (short) / 2] ;
Chris@41 660
Chris@41 661 int bufferlen, current ;
Chris@41 662
Chris@41 663 int channels ;
Chris@41 664
Chris@41 665 get_audio_callback_t callback ;
Chris@41 666
Chris@41 667 void *callback_data ;
Chris@41 668 } WIN32_AUDIO_OUT ;
Chris@41 669
Chris@41 670 static AUDIO_OUT *win32_open (int channels, int samplerate) ;
Chris@41 671 static void win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
Chris@41 672 static void win32_close (AUDIO_OUT *audio_out) ;
Chris@41 673
Chris@41 674 static DWORD CALLBACK
Chris@41 675 win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2) ;
Chris@41 676
Chris@41 677 static AUDIO_OUT*
Chris@41 678 win32_open (int channels, int samplerate)
Chris@41 679 { WIN32_AUDIO_OUT *win32_out ;
Chris@41 680
Chris@41 681 WAVEFORMATEX wf ;
Chris@41 682 int error ;
Chris@41 683
Chris@41 684 if ((win32_out = calloc (1, sizeof (WIN32_AUDIO_OUT))) == NULL)
Chris@41 685 { perror ("win32_open : malloc ") ;
Chris@41 686 exit (1) ;
Chris@41 687 } ;
Chris@41 688
Chris@41 689 win32_out->magic = WIN32_MAGIC ;
Chris@41 690 win32_out->channels = channels ;
Chris@41 691
Chris@41 692 win32_out->current = 0 ;
Chris@41 693
Chris@41 694 win32_out->Event = CreateEvent (0, FALSE, FALSE, 0) ;
Chris@41 695
Chris@41 696 wf.nChannels = channels ;
Chris@41 697 wf.nSamplesPerSec = samplerate ;
Chris@41 698 wf.nBlockAlign = channels * sizeof (short) ;
Chris@41 699
Chris@41 700 wf.wFormatTag = WAVE_FORMAT_PCM ;
Chris@41 701 wf.cbSize = 0 ;
Chris@41 702 wf.wBitsPerSample = 16 ;
Chris@41 703 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ;
Chris@41 704
Chris@41 705 error = waveOutOpen (&(win32_out->hwave), WAVE_MAPPER, &wf, (DWORD) win32_audio_out_callback,
Chris@41 706 (DWORD) win32_out, CALLBACK_FUNCTION) ;
Chris@41 707 if (error)
Chris@41 708 { puts ("waveOutOpen failed.") ;
Chris@41 709 free (win32_out) ;
Chris@41 710 return NULL ;
Chris@41 711 } ;
Chris@41 712
Chris@41 713 waveOutPause (win32_out->hwave) ;
Chris@41 714
Chris@41 715 return (WIN32_AUDIO_OUT *) win32_out ;
Chris@41 716 } /* win32_open */
Chris@41 717
Chris@41 718 static void
Chris@41 719 win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 720 { WIN32_AUDIO_OUT *win32_out ;
Chris@41 721 int error ;
Chris@41 722
Chris@41 723 if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
Chris@41 724 { printf ("win32_play : AUDIO_OUT is NULL.\n") ;
Chris@41 725 return ;
Chris@41 726 } ;
Chris@41 727
Chris@41 728 if (win32_out->magic != WIN32_MAGIC)
Chris@41 729 { printf ("win32_play : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
Chris@41 730 return ;
Chris@41 731 } ;
Chris@41 732
Chris@41 733 /* Set the callback function and callback data. */
Chris@41 734 win32_out->callback = callback ;
Chris@41 735 win32_out->callback_data = callback_data ;
Chris@41 736
Chris@41 737 win32_out->whdr [0].lpData = (char*) win32_out->short_buffer ;
Chris@41 738 win32_out->whdr [1].lpData = ((char*) win32_out->short_buffer) + sizeof (win32_out->short_buffer) / 2 ;
Chris@41 739
Chris@41 740 win32_out->whdr [0].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
Chris@41 741 win32_out->whdr [1].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
Chris@41 742
Chris@41 743 win32_out->bufferlen = sizeof (win32_out->short_buffer) / 2 / sizeof (short) ;
Chris@41 744
Chris@41 745 /* Prepare the WAVEHDRs */
Chris@41 746 if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR))))
Chris@41 747 { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ;
Chris@41 748 waveOutClose (win32_out->hwave) ;
Chris@41 749 return ;
Chris@41 750 } ;
Chris@41 751
Chris@41 752 if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR))))
Chris@41 753 { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ;
Chris@41 754 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
Chris@41 755 waveOutClose (win32_out->hwave) ;
Chris@41 756 return ;
Chris@41 757 } ;
Chris@41 758
Chris@41 759 waveOutRestart (win32_out->hwave) ;
Chris@41 760
Chris@41 761 /* Fake 2 calls to the callback function to queue up enough audio. */
Chris@41 762 win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
Chris@41 763 win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
Chris@41 764
Chris@41 765 /* Wait for playback to finish. The callback notifies us when all
Chris@41 766 ** wave data has been played.
Chris@41 767 */
Chris@41 768 WaitForSingleObject (win32_out->Event, INFINITE) ;
Chris@41 769
Chris@41 770 waveOutPause (win32_out->hwave) ;
Chris@41 771 waveOutReset (win32_out->hwave) ;
Chris@41 772
Chris@41 773 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
Chris@41 774 waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR)) ;
Chris@41 775
Chris@41 776 waveOutClose (win32_out->hwave) ;
Chris@41 777 win32_out->hwave = 0 ;
Chris@41 778
Chris@41 779 return ;
Chris@41 780 } /* win32_play */
Chris@41 781
Chris@41 782 static void
Chris@41 783 win32_close (AUDIO_OUT *audio_out)
Chris@41 784 { WIN32_AUDIO_OUT *win32_out ;
Chris@41 785
Chris@41 786 if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
Chris@41 787 { printf ("win32_close : AUDIO_OUT is NULL.\n") ;
Chris@41 788 return ;
Chris@41 789 } ;
Chris@41 790
Chris@41 791 if (win32_out->magic != WIN32_MAGIC)
Chris@41 792 { printf ("win32_close : Bad magic number.\n") ;
Chris@41 793 return ;
Chris@41 794 } ;
Chris@41 795
Chris@41 796 memset (win32_out, 0, sizeof (WIN32_AUDIO_OUT)) ;
Chris@41 797
Chris@41 798 free (win32_out) ;
Chris@41 799 } /* win32_close */
Chris@41 800
Chris@41 801 static DWORD CALLBACK
Chris@41 802 win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2)
Chris@41 803 { WIN32_AUDIO_OUT *win32_out ;
Chris@41 804 int read_count, frame_count, k ;
Chris@41 805 short *sptr ;
Chris@41 806
Chris@41 807 /*
Chris@41 808 ** I consider this technique of passing a pointer via an integer as
Chris@41 809 ** fundamentally broken but thats the way microsoft has defined the
Chris@41 810 ** interface.
Chris@41 811 */
Chris@41 812 if ((win32_out = (WIN32_AUDIO_OUT*) data) == NULL)
Chris@41 813 { printf ("win32_audio_out_callback : AUDIO_OUT is NULL.\n") ;
Chris@41 814 return 1 ;
Chris@41 815 } ;
Chris@41 816
Chris@41 817 if (win32_out->magic != WIN32_MAGIC)
Chris@41 818 { printf ("win32_audio_out_callback : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
Chris@41 819 return 1 ;
Chris@41 820 } ;
Chris@41 821
Chris@41 822 if (msg != MM_WOM_DONE)
Chris@41 823 return 0 ;
Chris@41 824
Chris@41 825 /* Do the actual audio. */
Chris@41 826 sample_count = win32_out->bufferlen ;
Chris@41 827 frame_count = sample_count / win32_out->channels ;
Chris@41 828
Chris@41 829 read_count = win32_out->callback (win32_out->callback_data, win32_out->float_buffer, frame_count) ;
Chris@41 830
Chris@41 831 sptr = (short*) win32_out->whdr [win32_out->current].lpData ;
Chris@41 832
Chris@41 833 for (k = 0 ; k < read_count ; k++)
Chris@41 834 sptr [k] = lrint (32767.0 * win32_out->float_buffer [k]) ;
Chris@41 835
Chris@41 836 if (read_count > 0)
Chris@41 837 { /* Fix buffer length is only a partial block. */
Chris@41 838 if (read_count * sizeof (short) < win32_out->bufferlen)
Chris@41 839 win32_out->whdr [win32_out->current].dwBufferLength = read_count * sizeof (short) ;
Chris@41 840
Chris@41 841 /* Queue the WAVEHDR */
Chris@41 842 waveOutWrite (win32_out->hwave, (LPWAVEHDR) &(win32_out->whdr [win32_out->current]), sizeof (WAVEHDR)) ;
Chris@41 843 }
Chris@41 844 else
Chris@41 845 { /* Stop playback */
Chris@41 846 waveOutPause (win32_out->hwave) ;
Chris@41 847
Chris@41 848 SetEvent (win32_out->Event) ;
Chris@41 849 } ;
Chris@41 850
Chris@41 851 win32_out->current = (win32_out->current + 1) % 2 ;
Chris@41 852
Chris@41 853 return 0 ;
Chris@41 854 } /* win32_audio_out_callback */
Chris@41 855
Chris@41 856 #endif /* Win32 */
Chris@41 857
Chris@41 858 /*------------------------------------------------------------------------------
Chris@41 859 ** Solaris.
Chris@41 860 */
Chris@41 861
Chris@41 862 #if (defined (sun) && defined (unix)) /* ie Solaris */
Chris@41 863
Chris@41 864 #include <fcntl.h>
Chris@41 865 #include <sys/ioctl.h>
Chris@41 866 #include <sys/audioio.h>
Chris@41 867
Chris@41 868 #define SOLARIS_MAGIC MAKE_MAGIC ('S', 'o', 'l', 'a', 'r', 'i', 's', ' ')
Chris@41 869
Chris@41 870 typedef struct
Chris@41 871 { int magic ;
Chris@41 872 int fd ;
Chris@41 873 int channels ;
Chris@41 874 int samplerate ;
Chris@41 875 } SOLARIS_AUDIO_OUT ;
Chris@41 876
Chris@41 877 static AUDIO_OUT *solaris_open (int channels, int samplerate) ;
Chris@41 878 static void solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
Chris@41 879 static void solaris_close (AUDIO_OUT *audio_out) ;
Chris@41 880
Chris@41 881 static AUDIO_OUT *
Chris@41 882 solaris_open (int channels, int samplerate)
Chris@41 883 { SOLARIS_AUDIO_OUT *solaris_out ;
Chris@41 884 audio_info_t audio_info ;
Chris@41 885 int error ;
Chris@41 886
Chris@41 887 if ((solaris_out = calloc (1, sizeof (SOLARIS_AUDIO_OUT))) == NULL)
Chris@41 888 { perror ("solaris_open : malloc ") ;
Chris@41 889 exit (1) ;
Chris@41 890 } ;
Chris@41 891
Chris@41 892 solaris_out->magic = SOLARIS_MAGIC ;
Chris@41 893 solaris_out->channels = channels ;
Chris@41 894 solaris_out->samplerate = channels ;
Chris@41 895
Chris@41 896 /* open the audio device - write only, non-blocking */
Chris@41 897 if ((solaris_out->fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0)
Chris@41 898 { perror ("open (/dev/audio) failed") ;
Chris@41 899 exit (1) ;
Chris@41 900 } ;
Chris@41 901
Chris@41 902 /* Retrive standard values. */
Chris@41 903 AUDIO_INITINFO (&audio_info) ;
Chris@41 904
Chris@41 905 audio_info.play.sample_rate = samplerate ;
Chris@41 906 audio_info.play.channels = channels ;
Chris@41 907 audio_info.play.precision = 16 ;
Chris@41 908 audio_info.play.encoding = AUDIO_ENCODING_LINEAR ;
Chris@41 909 audio_info.play.gain = AUDIO_MAX_GAIN ;
Chris@41 910 audio_info.play.balance = AUDIO_MID_BALANCE ;
Chris@41 911
Chris@41 912 if ((error = ioctl (solaris_out->fd, AUDIO_SETINFO, &audio_info)))
Chris@41 913 { perror ("ioctl (AUDIO_SETINFO) failed") ;
Chris@41 914 exit (1) ;
Chris@41 915 } ;
Chris@41 916
Chris@41 917 return (AUDIO_OUT*) solaris_out ;
Chris@41 918 } /* solaris_open */
Chris@41 919
Chris@41 920 static void
Chris@41 921 solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 922 { SOLARIS_AUDIO_OUT *solaris_out ;
Chris@41 923 static float float_buffer [BUFFER_LEN] ;
Chris@41 924 static short buffer [BUFFER_LEN] ;
Chris@41 925 int k, read_frames ;
Chris@41 926
Chris@41 927 if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
Chris@41 928 { printf ("solaris_play : AUDIO_OUT is NULL.\n") ;
Chris@41 929 return ;
Chris@41 930 } ;
Chris@41 931
Chris@41 932 if (solaris_out->magic != SOLARIS_MAGIC)
Chris@41 933 { printf ("solaris_play : Bad magic number.\n") ;
Chris@41 934 return ;
Chris@41 935 } ;
Chris@41 936
Chris@41 937 while ((read_frames = callback (callback_data, float_buffer, BUFFER_LEN / solaris_out->channels)))
Chris@41 938 { for (k = 0 ; k < read_frames * solaris_out->channels ; k++)
Chris@41 939 buffer [k] = lrint (32767.0 * float_buffer [k]) ;
Chris@41 940 write (solaris_out->fd, buffer, read_frames * solaris_out->channels * sizeof (short)) ;
Chris@41 941 } ;
Chris@41 942
Chris@41 943 return ;
Chris@41 944 } /* solaris_play */
Chris@41 945
Chris@41 946 static void
Chris@41 947 solaris_close (AUDIO_OUT *audio_out)
Chris@41 948 { SOLARIS_AUDIO_OUT *solaris_out ;
Chris@41 949
Chris@41 950 if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
Chris@41 951 { printf ("solaris_close : AUDIO_OUT is NULL.\n") ;
Chris@41 952 return ;
Chris@41 953 } ;
Chris@41 954
Chris@41 955 if (solaris_out->magic != SOLARIS_MAGIC)
Chris@41 956 { printf ("solaris_close : Bad magic number.\n") ;
Chris@41 957 return ;
Chris@41 958 } ;
Chris@41 959
Chris@41 960 memset (solaris_out, 0, sizeof (SOLARIS_AUDIO_OUT)) ;
Chris@41 961
Chris@41 962 free (solaris_out) ;
Chris@41 963
Chris@41 964 return ;
Chris@41 965 } /* solaris_close */
Chris@41 966
Chris@41 967 #endif /* Solaris */
Chris@41 968
Chris@41 969 /*==============================================================================
Chris@41 970 ** Main function.
Chris@41 971 */
Chris@41 972
Chris@41 973 AUDIO_OUT *
Chris@41 974 audio_open (int channels, int samplerate)
Chris@41 975 {
Chris@41 976 #if defined (__linux__)
Chris@41 977 #if HAVE_ALSA_ASOUNDLIB_H
Chris@41 978 if (access ("/proc/asound/cards", R_OK) == 0)
Chris@41 979 return alsa_open (channels, samplerate) ;
Chris@41 980 #endif
Chris@41 981 return opensoundsys_open (channels, samplerate) ;
Chris@41 982 #elif (defined (__MACH__) && defined (__APPLE__))
Chris@41 983 return macosx_open (channels, samplerate) ;
Chris@41 984 #elif (defined (sun) && defined (unix))
Chris@41 985 return solaris_open (channels, samplerate) ;
Chris@41 986 #elif (defined (_WIN32) || defined (WIN32))
Chris@41 987 return win32_open (channels, samplerate) ;
Chris@41 988 #else
Chris@41 989 #warning "*** Playing sound not yet supported on this platform."
Chris@41 990 #warning "*** Please feel free to submit a patch."
Chris@41 991 printf ("Error : Playing sound not yet supported on this platform.\n") ;
Chris@41 992 return NULL ;
Chris@41 993 #endif
Chris@41 994
Chris@41 995
Chris@41 996 return NULL ;
Chris@41 997 } /* audio_open */
Chris@41 998
Chris@41 999 void
Chris@41 1000 audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 1001 {
Chris@41 1002
Chris@41 1003 if (callback == NULL)
Chris@41 1004 { printf ("Error : bad callback pointer.\n") ;
Chris@41 1005 return ;
Chris@41 1006 } ;
Chris@41 1007
Chris@41 1008 if (audio_out == NULL)
Chris@41 1009 { printf ("Error : bad audio_out pointer.\n") ;
Chris@41 1010 return ;
Chris@41 1011 } ;
Chris@41 1012
Chris@41 1013 if (callback_data == NULL)
Chris@41 1014 { printf ("Error : bad callback_data pointer.\n") ;
Chris@41 1015 return ;
Chris@41 1016 } ;
Chris@41 1017
Chris@41 1018 #if defined (__linux__)
Chris@41 1019 #if HAVE_ALSA_ASOUNDLIB_H
Chris@41 1020 if (audio_out->magic == ALSA_MAGIC)
Chris@41 1021 alsa_play (callback, audio_out, callback_data) ;
Chris@41 1022 #endif
Chris@41 1023 opensoundsys_play (callback, audio_out, callback_data) ;
Chris@41 1024 #elif (defined (__MACH__) && defined (__APPLE__))
Chris@41 1025 macosx_play (callback, audio_out, callback_data) ;
Chris@41 1026 #elif (defined (sun) && defined (unix))
Chris@41 1027 solaris_play (callback, audio_out, callback_data) ;
Chris@41 1028 #elif (defined (_WIN32) || defined (WIN32))
Chris@41 1029 win32_play (callback, audio_out, callback_data) ;
Chris@41 1030 #else
Chris@41 1031 #warning "*** Playing sound not yet supported on this platform."
Chris@41 1032 #warning "*** Please feel free to submit a patch."
Chris@41 1033 printf ("Error : Playing sound not yet supported on this platform.\n") ;
Chris@41 1034 return ;
Chris@41 1035 #endif
Chris@41 1036
Chris@41 1037 return ;
Chris@41 1038 } /* audio_play */
Chris@41 1039
Chris@41 1040 void
Chris@41 1041 audio_close (AUDIO_OUT *audio_out)
Chris@41 1042 {
Chris@41 1043 #if defined (__linux__)
Chris@41 1044 #if HAVE_ALSA_ASOUNDLIB_H
Chris@41 1045 if (audio_out->magic == ALSA_MAGIC)
Chris@41 1046 alsa_close (audio_out) ;
Chris@41 1047 #endif
Chris@41 1048 opensoundsys_close (audio_out) ;
Chris@41 1049 #elif (defined (__MACH__) && defined (__APPLE__))
Chris@41 1050 macosx_close (audio_out) ;
Chris@41 1051 #elif (defined (sun) && defined (unix))
Chris@41 1052 solaris_close (audio_out) ;
Chris@41 1053 #elif (defined (_WIN32) || defined (WIN32))
Chris@41 1054 win32_close (audio_out) ;
Chris@41 1055 #else
Chris@41 1056 #warning "*** Playing sound not yet supported on this platform."
Chris@41 1057 #warning "*** Please feel free to submit a patch."
Chris@41 1058 printf ("Error : Playing sound not yet supported on this platform.\n") ;
Chris@41 1059 return ;
Chris@41 1060 #endif
Chris@41 1061
Chris@41 1062 return ;
Chris@41 1063 } /* audio_close */
Chris@41 1064
Chris@41 1065 #else /* (HAVE_SNDFILE == 0) */
Chris@41 1066
Chris@41 1067 /* Do not have libsndfile installed so just return. */
Chris@41 1068
Chris@41 1069 AUDIO_OUT *
Chris@41 1070 audio_open (int channels, int samplerate)
Chris@41 1071 {
Chris@41 1072 (void) channels ;
Chris@41 1073 (void) samplerate ;
Chris@41 1074
Chris@41 1075 return NULL ;
Chris@41 1076 } /* audio_open */
Chris@41 1077
Chris@41 1078 void
Chris@41 1079 audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
Chris@41 1080 {
Chris@41 1081 (void) callback ;
Chris@41 1082 (void) audio_out ;
Chris@41 1083 (void) callback_data ;
Chris@41 1084
Chris@41 1085 return ;
Chris@41 1086 } /* audio_play */
Chris@41 1087
Chris@41 1088 void
Chris@41 1089 audio_close (AUDIO_OUT *audio_out)
Chris@41 1090 {
Chris@41 1091 audio_out = audio_out ;
Chris@41 1092
Chris@41 1093 return ;
Chris@41 1094 } /* audio_close */
Chris@41 1095
Chris@41 1096 #endif /* HAVE_SNDFILE */
Chris@41 1097