annotate src/libsamplerate-0.1.8/examples/audio_out.c @ 23:619f715526df sv_v2.1

Update Vamp plugin SDK to 2.5
author Chris Cannam
date Thu, 09 May 2013 10:52:46 +0100
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