From a6e6888a2d1b0ebda9e7cf18e2200757a868affc Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 8 Dec 2005 03:51:21 +0000 Subject: [PATCH] Add OSX audio support to Sudoku (THANK YOU IAN!) git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4690 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- configure.in | 4 ++ test/sudoku.cxx | 99 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index acdb5470d..acc77f6eb 100644 --- a/configure.in +++ b/configure.in @@ -396,6 +396,10 @@ AC_CHECK_HEADER(alsa/asoundlib.h, AC_DEFINE(HAVE_ALSA_ASOUNDLIB_H) AUDIOLIBS="-lasound") +if test x$uname = xDarwin; then + AUDIOLIBS="-framework CoreAudio" +fi + AC_SUBST(AUDIOLIBS) dnl Check for image libraries... diff --git a/test/sudoku.cxx b/test/sudoku.cxx index 840b49a46..26a68b866 100644 --- a/test/sudoku.cxx +++ b/test/sudoku.cxx @@ -48,12 +48,20 @@ # include "sudoku.xbm" #endif // WIN32 +// Audio headers... #include +#ifndef WIN32 +# include +#endif // !WIN32 + #ifdef HAVE_ALSA_ASOUNDLIB_H # define ALSA_PCM_NEW_HW_PARAMS_API # include #endif // HAVE_ALSA_ASOUNDLIB_H +#ifdef __APPLE__ +# include +#endif // __APPLE__ // @@ -81,9 +89,24 @@ // There are several good cross-platform audio libraries we could also // use, such as OpenAL, PortAudio, and SDL, however they were not chosen // for this application because of our limited use of sound. +// +// Many thanks to Ian MacArthur who provided sample code that led to +// the CoreAudio implementation you see here! class SudokuSound { // Private, OS-specific data... #ifdef __APPLE__ + AudioDeviceID device; + AudioStreamBasicDescription format; + short *data; + int remaining; + + static OSStatus audio_cb(AudioDeviceID device, + const AudioTimeStamp *current_time, + const AudioBufferList *data_in, + const AudioTimeStamp *time_in, + AudioBufferList *data_out, + const AudioTimeStamp *time_out, + void *client_data); #elif defined(WIN32) #else # ifdef HAVE_ALSA_ASOUNDLIB_H @@ -125,6 +148,36 @@ SudokuSound::SudokuSound() { sample_size = 0; #ifdef __APPLE__ + remaining = 0; + + UInt32 size = sizeof(device); + + if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + &size, (void *)&device) != noErr) return; + + size = sizeof(format); + if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat, + &size, &format) != noErr) return; + + // Set up a format we like... + format.mSampleRate = 44100.0; // 44.1kHz + format.mChannelsPerFrame = 2; // stereo + + if (AudioDeviceSetProperty(device, NULL, 0, false, + kAudioDevicePropertyStreamFormat, + sizeof(format), &format) != noErr) return; + + // Check we got linear pcm - what to do if we did not ??? + if (format.mFormatID != kAudioFormatLinearPCM) return; + + // Attach the callback + if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return; + + // Start the device... + AudioDeviceStart(device, audio_cb); + + sample_size = (int)format.mSampleRate / 20; + #elif defined(WIN32) #else # ifdef HAVE_ALSA_ASOUNDLIB_H @@ -137,7 +190,7 @@ SudokuSound::SudokuSound() { snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); + snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_channels(handle, params, 2); unsigned rate = 44100; int dir; @@ -187,6 +240,9 @@ SudokuSound::SudokuSound() { // Cleanup the SudokuSound class SudokuSound::~SudokuSound() { #ifdef __APPLE__ + AudioDeviceStop(device, audio_cb); + AudioDeviceRemoveIOProc(device, audio_cb); + #elif defined(WIN32) #else # ifdef HAVE_ALSA_ASOUNDLIB_H @@ -205,12 +261,51 @@ SudokuSound::~SudokuSound() { } +#ifdef __APPLE__ +// Callback function for writing audio data... +OSStatus +SudokuSound::audio_cb(AudioDeviceID device, + const AudioTimeStamp *current_time, + const AudioBufferList *data_in, + const AudioTimeStamp *time_in, + AudioBufferList *data_out, + const AudioTimeStamp *time_out, + void *client_data) { + SudokuSound *ss = (SudokuSound *)client_data; + int count; + float *buffer; + + if (!ss->remaining) return noErr; + + for (count = data_out->mBuffers[0].mDataByteSize / sizeof(float), + buffer = (float*) data_out->mBuffers[0].mData; + ss->remaining > 0 && count > 0; + count --, ss->data ++, ss->remaining --) { + *buffer++ = *(ss->data) / 32767.0; + } + + while (count > 0) { + *buffer++ = 0.0; + count --; + } + + return noErr; +} +#endif // __APPLE__ + + // Play a note for 250ms... void SudokuSound::play(char note) { Fl::check(); #ifdef __APPLE__ - // TODO + // Point to the next note... + data = sample_data[note - 'A']; + remaining = sample_size * 2; + + // Wait for the sound to complete... + usleep(50000); + #elif defined(WIN32) Beep(frequencies[note - 'A'], 50); #else