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