几种播放音频文件的方式(十四) —— OpenAL框架之简单示例一(三)

版本记录

版本号 时间
V1.0 2017.12.29

前言

ios系统中有很多方式可以播放音频文件,这里我们就详细的说明下播放音乐文件的原理和实例。感兴趣的可以看我写的上面几篇。
1. 几种播放音频文件的方式(一) —— 播放本地音乐
2. 几种播放音频文件的方式(二) —— 音效播放
3. 几种播放音频文件的方式(三) —— 网络音乐播放
4. 几种播放音频文件的方式(四) —— 音频队列服务(Audio Queue Services)(一)
5. 几种播放音频文件的方式(五) —— 音频队列服务(Audio Queue Services)简介(二)
6. 几种播放音频文件的方式(六) —— 音频队列服务(Audio Queue Services)之关于音频队列(三)
7. 几种播放音频文件的方式(七) —— 音频队列服务(Audio Queue Services)之录制音频(四)
8. 几种播放音频文件的方式(八) —— 音频队列服务(Audio Queue Services)之播放音频(五)
9. 几种播放音频文件的方式(九) —— Media Player框架之基本概览(一)
10. 几种播放音频文件的方式(十) —— Media Player框架之简单播放音频示例(二)
11. 几种播放音频文件的方式(十一) —— AudioUnit框架之基本概览(一)
12. 几种播放音频文件的方式(十二) —— OpenAL框架之基本概览(一)
13. 几种播放音频文件的方式(十三) —— OpenAL框架之分步解析(二)

简单示例

下面我们就看一下示例OpenALExampleOpenALExample项目使用OpenGLOpenAL创建一个基于Cocoa的应用程序,允许用户操纵空间中的对象,并听到他们的声音相应的效果。 它使用4个来源播放录制的数据,还有一个使用OpenAL捕获API播放捕获的音频。 该应用程序还显示如何使用Apple Spatial Audio扩展可用的oreverb,occlusion和obstruction效果。

下面我们就看一下代码。

1. main.m
/*
     File: main.m
 Abstract: main.m
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import <Cocoa/Cocoa.h>
 
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc,  (const char **) argv);
}
2. Controller.h
/*
     File: Controller.h
 Abstract: Controller.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import <Cocoa/Cocoa.h>
#import "MyOpenGLView.h"
 
enum    {
            kSourceOneIndex = 0,
            kSourceTwoIndex,
            kSourceThreeIndex,
            kSourceFourIndex,
            kCaptureSourceIndex,
            kListenerIndex
};
 
 
enum    {
            kListenerGainEditTextItem   = 1000,
            kDopplerFactorEditTextItem,
            kSpeedOfSoundEditTextItem,
            kVelocitySpeedEditTextItem,
            kReverbLevelEditTextItem,
            kReverbEQFrequencyEditTextItem,
            kReverbEQBandwidth,
            kReverbEQGain,
            kListenerElevation,         // ListenerPosY
            kListenerPosX               = 3000,
            kListenerPosZ               = 3002
};
 
 
@interface Controller : NSObject {
    IBOutlet NSWindow*              mainWindow;
    IBOutlet MyOpenGLView*          view;
 
    // Slider Outlets
 
    IBOutlet NSSlider*              mListenerGainSlider;
    IBOutlet NSSlider*              mDopplerFactorSlider;
    IBOutlet NSSlider*              mSpeedOfSoundSlider;
    IBOutlet NSSlider*              mListenerVelocityScalerSlider;
    IBOutlet NSSlider*              mListenerReverbLevelSlider;
    IBOutlet NSSlider*              mReverbEQFrequencySlider;
    IBOutlet NSSlider*              mReverbEQGainSlider;
    IBOutlet NSSlider*              mReverbEQBandwidthSlider;
    IBOutlet NSSlider*              mListenerElevationSlider;   // 1008
    IBOutlet NSButton*              mReverbOnCheckbox;
    IBOutlet NSPopUpButton*         mReverbQualityPU;
    IBOutlet NSPopUpButton*         mReverbRoomtypePU;
 
    IBOutlet NSSlider*              mCaptureSourceGainSlider;
    IBOutlet NSSlider*              mCaptureSourcePitchSlider;
    IBOutlet NSButton*              mCaptureSourceOnCheckbox;
    IBOutlet NSButton*              mCaptureSourceCaptureSamplesButton;
    
    IBOutlet NSSlider*              mCaptureSourceReverbSlider;
    IBOutlet NSSlider*              mCaptureSourceOcclusionSlider;
    IBOutlet NSSlider*              mCaptureSourceObstructionSlider;
    IBOutlet NSButton*              mCaptureSourceConesCheckbox;
    IBOutlet NSSlider*              mCaptureSourceAngleSlider;
    IBOutlet NSSlider*              mCaptureSourceVelocitySlider;
    IBOutlet NSSlider*              mCaptureSourceInnerConeAngleSlider;
    IBOutlet NSSlider*              mCaptureSourceOuterConeAngleSlider;
    IBOutlet NSSlider*              mCaptureSourceOuterConeGainSlider;
 
    // Text Field Outlets
    
    IBOutlet NSTextField*           mListenerGain;
    IBOutlet NSTextField*           mListenerElevation;
    IBOutlet NSTextField*           mDopplerFactor;
    IBOutlet NSTextField*           mSpeedOfSound;
    IBOutlet NSTextField*           mListenerVelocityScaler;
    IBOutlet NSTextField*           mListenerReverbLevel;
    IBOutlet NSTextField*           mReverbEQFrequency;
    IBOutlet NSTextField*           mReverbEQGain;
    IBOutlet NSTextField*           mReverbEQBandwidth;
 
    IBOutlet NSTextField*           mListenerXPos;
    IBOutlet NSTextField*           mListenerZPos;
    IBOutlet NSTextField*           mListenerXVelocity;
    IBOutlet NSTextField*           mListenerZVelocity;
    
    IBOutlet NSTextField*           mSourceOnePitch;
    IBOutlet NSTextField*           mSourceTwoPitch;
    IBOutlet NSTextField*           mSourceThreePitch;
    IBOutlet NSTextField*           mSourceFourPitch;
    IBOutlet NSTextField*           mCaptureSourcePitch;
    
    IBOutlet NSTextField*           mSourceOneGain;
    IBOutlet NSTextField*           mSourceTwoGain;
    IBOutlet NSTextField*           mSourceThreeGain;
    IBOutlet NSTextField*           mSourceFourGain;
    IBOutlet NSTextField*           mCaptureSourceGain;
 
    IBOutlet NSTextField*           mSourceOneReferenceDistance;
    IBOutlet NSTextField*           mSourceTwoReferenceDistance;
    IBOutlet NSTextField*           mSourceThreeReferenceDistance;
    IBOutlet NSTextField*           mSourceFourReferenceDistance;
    IBOutlet NSTextField*           mCaptureSourceReferenceDistance;
 
    IBOutlet NSTextField*           mSourceOneMaxDistance;
    IBOutlet NSTextField*           mSourceTwoMaxDistance;
    IBOutlet NSTextField*           mSourceThreeMaxDistance;
    IBOutlet NSTextField*           mSourceFourMaxDistance;
    IBOutlet NSTextField*           mCaptureSourceMaxDistance;
 
    IBOutlet NSTextField*           mSourceOneRolloffFactor;
    IBOutlet NSTextField*           mSourceTwoRolloffFactor;
    IBOutlet NSTextField*           mSourceThreeRolloffFactor;
    IBOutlet NSTextField*           mSourceFourRolloffFactor;
    IBOutlet NSTextField*           mCaptureSourceRolloffFactor;
    
    IBOutlet NSTextField*           mSourceOneInnerConeAngle;
    IBOutlet NSTextField*           mSourceTwoInnerConeAngle;
    IBOutlet NSTextField*           mSourceThreeInnerConeAngle;
    IBOutlet NSTextField*           mSourceFourInnerConeAngle;
    IBOutlet NSTextField*           mCaptureSourceInnerConeAngle;
 
    IBOutlet NSTextField*           mSourceOneOuterConeAngle;
    IBOutlet NSTextField*           mSourceTwoOuterConeAngle;
    IBOutlet NSTextField*           mSourceThreeOuterConeAngle;
    IBOutlet NSTextField*           mSourceFourOuterConeAngle;
    IBOutlet NSTextField*           mCaptureSourceOuterConeAngle;
 
    IBOutlet NSTextField*           mSourceOneOuterConeGain;
    IBOutlet NSTextField*           mSourceTwoOuterConeGain;
    IBOutlet NSTextField*           mSourceThreeOuterConeGain;
    IBOutlet NSTextField*           mSourceFourOuterConeGain;
    IBOutlet NSTextField*           mCaptureSourceOuterConeGain;
 
    IBOutlet NSTextField*           mSourceOneReverbLevel;
    IBOutlet NSTextField*           mSourceTwoReverbLevel;
    IBOutlet NSTextField*           mSourceThreeReverbLevel;
    IBOutlet NSTextField*           mSourceFourReverbLevel;
    IBOutlet NSTextField*           mCaptureSourceReverbLevel;
    
    IBOutlet NSTextField*           mSourceOneOcclusionLevel;
    IBOutlet NSTextField*           mSourceTwoOcclusionLevel;
    IBOutlet NSTextField*           mSourceThreeOcclusionLevel;
    IBOutlet NSTextField*           mSourceFourOcclusionLevel;
    IBOutlet NSTextField*           mCaptureSourceOcclusionLevel;
    
    IBOutlet NSTextField*           mSourceOneObstructionLevel;
    IBOutlet NSTextField*           mSourceTwoObstructionLevel;
    IBOutlet NSTextField*           mSourceThreeObstructionLevel;
    IBOutlet NSTextField*           mSourceFourObstructionLevel;
    IBOutlet NSTextField*           mCaptureSourceObstructionLevel;
 
    IBOutlet NSTextField*           mSourceOneVelocity;
    IBOutlet NSTextField*           mSourceTwoVelocity;
    IBOutlet NSTextField*           mSourceThreeVelocity;
    IBOutlet NSTextField*           mSourceFourVelocity;
    IBOutlet NSTextField*           mCaptureSourceVelocity;
 
    IBOutlet NSTextField*           mSourceOneXVelocity;
    IBOutlet NSTextField*           mSourceTwoXVelocity;
    IBOutlet NSTextField*           mSourceThreeXVelocity;
    IBOutlet NSTextField*           mSourceFourXVelocity;
    IBOutlet NSTextField*           mCaptureSourceXVelocity;
    
    IBOutlet NSTextField*           mSourceOneZVelocity;
    IBOutlet NSTextField*           mSourceTwoZVelocity;
    IBOutlet NSTextField*           mSourceThreeZVelocity;
    IBOutlet NSTextField*           mSourceFourZVelocity;
    IBOutlet NSTextField*           mCaptureSourceZVelocity;
 
    IBOutlet NSTextField*           mSourceOneXPosition;
    IBOutlet NSTextField*           mSourceTwoXPosition;
    IBOutlet NSTextField*           mSourceThreeXPosition;
    IBOutlet NSTextField*           mSourceFourXPosition;
    IBOutlet NSTextField*           mCaptureSourceXPosition;
    
    IBOutlet NSTextField*           mCaptureSourceYPosition;
 
    IBOutlet NSTextField*           mSourceOneZPosition;
    IBOutlet NSTextField*           mSourceTwoZPosition;
    IBOutlet NSTextField*           mSourceThreeZPosition;
    IBOutlet NSTextField*           mSourceFourZPosition;
    IBOutlet NSTextField*           mCaptureSourceZPosition;
    
    IBOutlet NSTextField*           mALExtensionList;
    IBOutlet NSTextField*           mALCExtensionList;
    IBOutlet NSTextField*           mALCDefaultDeviceName;
    IBOutlet NSTextField*           mALCCaptureDefaultDeviceName;
    IBOutlet NSTextField*           mALVersion;
    
    IBOutlet NSTextField*           mSamplesCaptured;
}
 
// Context/Listener
- (IBAction)    setListenerGainSlider:(id)inSender;
- (IBAction)    setListenerDirectionSlider:(id)inSender;
- (IBAction)    setListenerVelocitySlider:(id)inSender;
- (IBAction)    setListenerElevationSlider:(id)inSender;
- (IBAction)    setDopplerFactorSlider:(id)inSender;
- (IBAction)    setSpeedOfSoundSlider:(id)inSender;
 
- (IBAction)    setReverbLevelSlider:(id)inSender;
- (IBAction)    setReverbEQGainSlider:(id)inSender;
- (IBAction)    setReverbEQBandwidthSlider:(id)inSender;
- (IBAction)    setReverbEQFrequencySlider:(id)inSender;
 
- (IBAction)    setReverbQualityPU:(id)inSender;
- (IBAction)    setDistanceModelPU:(id)inSender;
- (IBAction)    setReverbRoomTypePU:(id)inSender;
 
- (IBAction)    setRenderChannelsCheckbox:(id)inSender;
- (IBAction)    setRenderQualityCheckbox:(id)inSender;
- (IBAction)    setReverbOnCheckbox:(id)inSender;
 
// Source
 
- (IBAction)    setSourcePitchSlider:(id)inSender;
- (IBAction)    setSourceGainSlider:(id)inSender;
- (IBAction)    setSourceAngleSlider:(id)inSender;
- (IBAction)    setSourceVelocitySlider:(id)inSender;
- (IBAction)    setSourceOuterConeGainSlider:(id)inSender;
- (IBAction)    setSourceOuterConeAngleSlider:(id)inSender;
- (IBAction)    setSourceInnerConeAngleSlider:(id)inSender;
 
- (IBAction)    setSourceReverbSlider:(id)inSender;
- (IBAction)    setSourceOcclusionSlider:(id)inSender;
- (IBAction)    setSourceObstructionSlider:(id)inSender;
 
- (IBAction)    setSourceUseConesCheckBox:(id)inSender;
- (IBAction)    setSourcePlayStatesCheckBox:(id)inSender;
 
- (IBAction)    captureSamplesButton:(id)inSender;
 
 
- (void) controlTextDidEndEditing:(NSNotification *) aNotification;
- (void) myObserver:(NSNotification *)inNotification;
- (void) awakeFromNib;
 
@end
3. Controller.m
/*
     File: Controller.m
 Abstract: Controller.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import "Controller.h"
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Extension API Procs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef OSStatus    (*alcASAGetListenerProcPtr) (const ALuint property, ALvoid *data, ALuint *dataSize);
OSStatus  alcASAGetListenerProc(const ALuint property, ALvoid *data, ALuint *dataSize)
{
    OSStatus    err = noErr;
    static  alcASAGetListenerProcPtr    proc = NULL;
    
    if (proc == NULL) {
        proc = (alcASAGetListenerProcPtr) alcGetProcAddress(NULL, "alcASAGetListener");
    }
    
    if (proc)
        err = proc(property, data, dataSize);
    return (err);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@implementation Controller
 
- (void)myObserver:(NSNotification *)inNotification
{
    float   x,z;
    int     objIndex;
    [[view scene]   getCurrentObjectPosition: &objIndex : &x : &z];
    
    switch(objIndex)
    {
        case kSourceOneIndex:
            [mSourceOneXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
            [mSourceOneZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            break;
 
        case kSourceTwoIndex:
            [mSourceTwoXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
            [mSourceTwoZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            break;
 
        case kSourceThreeIndex:
            [mSourceThreeXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
            [mSourceThreeZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            break;
 
        case kSourceFourIndex:
            [mSourceFourXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
            [mSourceFourZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            break;
 
        case kCaptureSourceIndex:
            if ([[view scene] hasInput])
            {
                [mCaptureSourceXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
                [mCaptureSourceZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            }
            break;
 
        case kListenerIndex:
            [mListenerXPos setStringValue: [NSString stringWithFormat: @"%.1f", x]];
            [mListenerZPos setStringValue: [NSString stringWithFormat: @"%.1f", z]];
            break;
    }
    
    
    //NSLog(@"Message recieved");
}
 
- (void) awakeFromNib
{
    float   x, z;
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(myObserver:) name: @"OALNotify" object: NULL];
 
    [mainWindow setDelegate:(id) self];
 
    // only enable the capture source if capture is available
    if ([[view scene] hasInput])
    {
        // enable the capture controls
        [mCaptureSourceGainSlider setEnabled: true];
        [mCaptureSourcePitchSlider setEnabled: true];
        [mCaptureSourceOnCheckbox setEnabled: true];
        [mCaptureSourceCaptureSamplesButton setEnabled: true];
 
        [mCaptureSourceConesCheckbox setEnabled: true];
        [mCaptureSourceAngleSlider setEnabled: true];
        [mCaptureSourceVelocitySlider setEnabled: true];
        [mCaptureSourceInnerConeAngleSlider setEnabled: true];
        [mCaptureSourceOuterConeAngleSlider setEnabled: true];
        [mCaptureSourceOuterConeGainSlider setEnabled: true];
 
        [mCaptureSourceXPosition setEnabled: true];
        [mCaptureSourceZPosition setEnabled: true];
        [mCaptureSourceYPosition setEnabled: true];
        [mCaptureSourceReferenceDistance setEnabled: true];
        [mCaptureSourceMaxDistance setEnabled: true];
        [mCaptureSourceRolloffFactor setEnabled: true];
 
        [[view scene]   getObjectPosition: kCaptureSourceIndex : &x : &z];
 
        [mCaptureSourceXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
        [mCaptureSourceYPosition setStringValue: [NSString stringWithFormat: @"%.1f", 0.0]];
        [mCaptureSourceZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
 
        [mCaptureSourceGain setStringValue: [NSString stringWithFormat: @"%.1f", 1.0]];
        [mCaptureSourcePitch setStringValue: [NSString stringWithFormat: @"%.1f", 1.0]];
 
        [mCaptureSourceXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", 0.0]];
        [mCaptureSourceZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", 0.0]];
        [mCaptureSourceVelocity setStringValue: [NSString stringWithFormat: @"%.1f", 0.0]];
 
        [mCaptureSourceInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", 90.0]];
        [mCaptureSourceOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", 180.0]];
        [mCaptureSourceOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", 0.0]];
 
        if ([[view scene] hasASAExtension])
        {
            [mCaptureSourceReverbSlider setEnabled: true];
            [mCaptureSourceOcclusionSlider setEnabled: true];
            [mCaptureSourceObstructionSlider setEnabled: true];
            [mCaptureSourceReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", 0.0]];
            [mCaptureSourceOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", 0.0]];
            [mCaptureSourceObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", 0.0]];
        }
    }
 
    // Enable ASA Features is extension is present
    if ([[view scene] hasASAExtension])
    {
        [mListenerReverbLevel setEnabled: true];
        [mListenerReverbLevelSlider setEnabled: true];
        [mReverbEQFrequency setEnabled: true];
        [mReverbEQFrequencySlider setEnabled: true];
        [mReverbEQBandwidth setEnabled: true];
        [mReverbEQBandwidthSlider setEnabled: true];
        [mReverbEQGain setEnabled: true];
        [mReverbEQGainSlider setEnabled: true];
 
        [mReverbOnCheckbox setEnabled: true];
        [mReverbQualityPU setEnabled: true];
        [mReverbRoomtypePU setEnabled: true];
        
        // populate the Reverb Room Preset PU (mReverbRoomtypePU) with any aupresets found in Contents/Resources/ReverbPresets of the app bundle
        NSArray*    pathsArray =[[NSBundle mainBundle] pathsForResourcesOfType:@"aupreset" inDirectory:@"ReverbPresets"];
        int pathCount = [pathsArray count];
        int i;
        NSString*   presetPath = NULL;
        for(i = 0; i < pathCount; i++)
        {
            presetPath = [pathsArray objectAtIndex:i];
            if (presetPath)
            {
                CFURLRef url = CFURLCreateWithString(NULL, (CFStringRef) presetPath, NULL);             
                if (url)
                {
                    CFURLRef nuURL = CFURLCreateCopyDeletingPathExtension(kCFAllocatorDefault, url);    // strip the .aupreset extension
                    if (nuURL)
                    {
                        CFStringRef lastPathComponent = CFURLCopyLastPathComponent (nuURL);             // get the preset name
                        if (lastPathComponent)
                        {
                            [mReverbRoomtypePU addItemWithTitle: (NSString*) lastPathComponent];
                            CFRelease(lastPathComponent);
                        }
                        CFRelease(nuURL);
                    }
                    CFRelease(url);
                }
            }
        }               
    }
 
    // position text
    [[view scene]   getObjectPosition: kSourceOneIndex : &x : &z];
    [mSourceOneXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
    [mSourceOneZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
 
    [[view scene]   getObjectPosition: kSourceTwoIndex : &x : &z];
    [mSourceTwoXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
    [mSourceTwoZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
 
    [[view scene]   getObjectPosition: kSourceThreeIndex : &x : &z];
    [mSourceThreeXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
    [mSourceThreeZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
 
    [[view scene]   getObjectPosition: kSourceFourIndex : &x : &z];
    [mSourceFourXPosition setStringValue: [NSString stringWithFormat: @"%.1f", x]];
    [mSourceFourZPosition setStringValue: [NSString stringWithFormat: @"%.1f", z]];
 
    // get current values of source attributes to diplay in UI at start up time
    [mSourceOneReferenceDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceReferenceDistance:0]]];
    [mSourceTwoReferenceDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceReferenceDistance:1]]];
    [mSourceThreeReferenceDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceReferenceDistance:2]]];
    [mSourceFourReferenceDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceReferenceDistance:3]]];
    [mCaptureSourceReferenceDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceReferenceDistance:4]]];
 
    [mSourceOneMaxDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceMaxDistance:0]]];
    [mSourceTwoMaxDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceMaxDistance:1]]];
    [mSourceThreeMaxDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceMaxDistance:2]]];
    [mSourceFourMaxDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceMaxDistance:3]]];
    [mCaptureSourceMaxDistance setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceMaxDistance:4]]];
    
    [mSourceOneRolloffFactor setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceRolloffFactor:0]]];
    [mSourceTwoRolloffFactor setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceRolloffFactor:1]]];
    [mSourceThreeRolloffFactor setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceRolloffFactor:2]]];
    [mSourceFourRolloffFactor setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceRolloffFactor:3]]];
    [mCaptureSourceRolloffFactor setStringValue: [NSString stringWithFormat: @"%.1f", [[view scene] getSourceRolloffFactor:4]]];
    
    // doppler factor
    float   setting = alGetFloat(AL_DOPPLER_FACTOR);
    [mDopplerFactor setStringValue: [NSString stringWithFormat: @"%.2f", setting]];
    [mDopplerFactorSlider setFloatValue: setting];          // move the corresponding slider
 
    // speed of sound
    setting = alGetFloat(AL_SPEED_OF_SOUND);
    [mSpeedOfSound setStringValue: [NSString stringWithFormat: @"%.2f", setting]];
    [mSpeedOfSoundSlider setFloatValue: setting];           // move the corresponding slider
 
    // display some info about the library
    
    // SEE IF STRING IS RETURNED FIRST SO THESE WON'T CRASH ON A NULL STRING
    if (alGetString(AL_EXTENSIONS))
        [mALExtensionList setStringValue: [NSString stringWithUTF8String: (const char *) alGetString(AL_EXTENSIONS)]];
    if ( alcGetString(alcGetContextsDevice(alcGetCurrentContext()), ALC_EXTENSIONS))
        [mALCExtensionList setStringValue: [NSString stringWithUTF8String: (const char *) alcGetString(alcGetContextsDevice(alcGetCurrentContext()), ALC_EXTENSIONS)]];
    if (alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER))
        [mALCDefaultDeviceName setStringValue: [NSString stringWithUTF8String: (const char *) alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER)]];
 
    if (alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER))
        [mALCCaptureDefaultDeviceName setStringValue: [NSString stringWithUTF8String: (const char *) alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)]];
    if (alGetString(AL_VERSION))
        [mALVersion setStringValue: [NSString stringWithUTF8String: (const char *) alGetString(AL_VERSION)]];   
}
 
 
#pragma mark ***** Listener Controls *****
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setListenerDirectionSlider:(id)inSender
{
    // orient the listener and get it x & z velocities
    float   xVelocity, zVelocity;
    [[view scene] setListenerOrientation:[inSender floatValue] : &xVelocity : &zVelocity];
 
    // update the x & z velocity text
    [mListenerXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", xVelocity]];
    [mListenerZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", zVelocity]];
 
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// this is a velocity scaler that is applied to the direction the listener is facing 
- (IBAction)setListenerVelocitySlider:(id)inSender
{
    float   velocity = [inSender floatValue];
    [mListenerVelocityScaler setStringValue: [NSString stringWithFormat: @"%.2f", velocity]];
        
    float   xVelocity, zVelocity;
    [[view scene] setListenerVelocity:velocity : &xVelocity : &zVelocity];
    
    // update the x & z velocity text
    [mListenerXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", xVelocity]];
    [mListenerZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", zVelocity]];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setListenerGainSlider:(id)inSender
{
    float   gain = [inSender floatValue];
    [mListenerGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
        
    [[view scene] setListenerGain:gain];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setListenerElevationSlider:(id)inSender
{
    float   elevation = [inSender floatValue];
    [mListenerElevation setStringValue: [NSString stringWithFormat: @"%.2f", elevation]];
        
    [[view scene] setListenerElevation:elevation];
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setDopplerFactorSlider:(id)inSender
{
    float   setting = [inSender floatValue];
    [mDopplerFactor setStringValue: [NSString stringWithFormat: @"%.2f", setting]];
        
    [[view scene] setDopplerFactor:setting];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSpeedOfSoundSlider:(id)inSender
{
    float   setting = [inSender floatValue];
    [mSpeedOfSound setStringValue: [NSString stringWithFormat: @"%.2f", setting]];
        
    [[view scene] setSpeedOfSound:setting];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setDistanceModelPU:(id)inSender
{
    int     tag = [[inSender selectedItem] tag];
        
    [[view scene] setDistanceModel:tag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setRenderChannelsCheckbox:(id)inSender
{
    int channels = [inSender intValue];
        
    [[view scene] setRenderChannels:channels];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setRenderQualityCheckbox:(id)inSender
{
    int quality = [inSender intValue];
        
    [[view scene] setRenderQuality:quality];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CONTEXT REVERB
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Listener Reverb *****
- (IBAction)    setReverbLevelSlider:(id)inSender
{
    float   level = [inSender floatValue];
    [mListenerReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
        
    [[view scene] setGlobalReverb:level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbEQGainSlider:(id)inSender
{
    float   level = [inSender floatValue];
    [mReverbEQGain setStringValue: [NSString stringWithFormat: @"%.2f", level]];
    [[view scene] setReverbEQGain:level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbEQBandwidthSlider:(id)inSender
{
    float   level = [inSender floatValue];
    [mReverbEQBandwidth setStringValue: [NSString stringWithFormat: @"%.2f", level]];
    [[view scene] setReverbEQBandwidth:level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbEQFrequencySlider:(id)inSender
{
    float   level = [inSender floatValue];
    [mReverbEQFrequency setStringValue: [NSString stringWithFormat: @"%.2f", level]];
    [[view scene] setReverbEQFrequency:level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbOnCheckbox:(id)inSender
{
    int state = [inSender intValue];
        
    [[view scene] setReverbOn:state];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbQualityPU:(id)inSender;
{
    int     tag = [[inSender selectedItem] tag];
        
    [[view scene] setReverbQuality:tag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setReverbRoomTypePU:(id)inSender
{
    int         index = [inSender indexOfSelectedItem];
    int         tag = [[inSender selectedItem] tag];
    NSString*   itemText = [inSender titleOfSelectedItem];
        
    [[view scene] setReverbRoomType:tag controlIndex:index title:itemText];
    
    // get the reverb freq, gain and badwidth and set the sliders and text now..........
    float   gain=0.0, bd=0.0, freq=0.0;
    ALuint  size;
    
    usleep(50000);
    
    // update EQ Bandwidth Controls
    size =  sizeof(bd);
    alcASAGetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_BANDWITH"), &bd, &size);
    [mReverbEQBandwidth setStringValue: [NSString stringWithFormat: @"%.2f", bd]];
    [mReverbEQBandwidthSlider setFloatValue: bd];   // move the corresponding slider
    
    // update EQ Frequency Controls
    size =  sizeof(freq);
    alcASAGetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_FREQ"), &freq, &size);
    [mReverbEQFrequency setStringValue: [NSString stringWithFormat: @"%.2f", freq]];
    [mReverbEQFrequencySlider setFloatValue: freq]; // move the corresponding slider
 
    // update EQ Gain Controls
    size =  sizeof(gain);
    alcASAGetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_GAIN"), &gain, &size);
    [mReverbEQGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
    [mReverbEQGainSlider setFloatValue: gain];      // move the corresponding slider
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SOURCE SETTINGS
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Source Controls *****
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setSourceGainSlider:(id)inSender
{
    float   gain = [inSender floatValue];
    int     tag = [inSender tag];
 
    // update the corresponding text field
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceFourIndex:
            [mSourceFourGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
    }
        
    [[view scene] setSourceGain:tag :gain];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setSourcePitchSlider:(id)inSender
{
    float   pitch = [inSender floatValue];
    int     tag = [inSender tag];
 
    // update the corresponding text field
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOnePitch setStringValue: [NSString stringWithFormat: @"%.2f", pitch]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoPitch setStringValue: [NSString stringWithFormat: @"%.2f", pitch]];
            break;
        case kSourceThreeIndex:
            [mSourceThreePitch setStringValue: [NSString stringWithFormat: @"%.2f", pitch]];
            break;
        case kSourceFourIndex:
            [mSourceFourPitch setStringValue: [NSString stringWithFormat: @"%.2f", pitch]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourcePitch setStringValue: [NSString stringWithFormat: @"%.2f", pitch]];
            break;
    }
        
    [[view scene] setSourcePitch:tag :pitch];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)setSourceAngleSlider:(id)inSender
{
    int     tag = [inSender tag];
    float   outX, outZ;
 
    [[view scene] setSourceAngle:tag :[inSender floatValue]];   
    [[view scene] getSourceVelocities:tag :&outX : &outZ];
 
    // update the corresponding text fields
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceOneZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceTwoZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceThreeZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceFourIndex:
            [mSourceFourXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceFourZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mCaptureSourceZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
    }
    
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceVelocitySlider:(id)inSender
{
    float   velocity = [inSender floatValue];
    int     tag = [inSender tag];
 
    float outX, outZ;
    [[view scene] setSourceVelocity:tag :velocity];
    [[view scene] getSourceVelocities:tag :&outX : &outZ];
 
    // update the corresponding text fields
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneVelocity setStringValue: [NSString stringWithFormat: @"%.1f", velocity]];
            [mSourceOneXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceOneZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoVelocity setStringValue: [NSString stringWithFormat: @"%.1f", velocity]];
            [mSourceTwoXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceTwoZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeVelocity setStringValue: [NSString stringWithFormat: @"%.1f", velocity]];
            [mSourceThreeXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceThreeZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kSourceFourIndex:
            [mSourceFourVelocity setStringValue: [NSString stringWithFormat: @"%.1f", velocity]];
            [mSourceFourXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mSourceFourZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceVelocity setStringValue: [NSString stringWithFormat: @"%.1f", velocity]];
            [mCaptureSourceXVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outX]];
            [mCaptureSourceZVelocity setStringValue: [NSString stringWithFormat: @"%.1f", outZ]];
            break;
    }
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceOuterConeGainSlider:(id)inSender
{
    float   gain = [inSender floatValue];
    int     tag = [inSender tag];
 
    [[view scene] setSourceOuterConeGain:tag :gain];
 
    // update the corresponding text fields
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kSourceFourIndex:
            [mSourceFourOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", gain]];
            break;
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceOuterConeAngleSlider:(id)inSender
{
    float   angle = [inSender floatValue];
    int     tag = [inSender tag];
 
    [[view scene] setSourceOuterConeAngle:tag :angle];
 
    // update the corresponding text fields
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceFourIndex:
            [mSourceFourOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
    }
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceInnerConeAngleSlider:(id)inSender
{
    float   angle = [inSender floatValue];
    int     tag = [inSender tag];
 
    [[view scene] setSourceInnerConeAngle:tag :angle];
 
    // update the corresponding text fields
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kSourceFourIndex:
            [mSourceFourInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", angle]];
            break;
    }
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceUseConesCheckBox:(id)inSender
{
    int     tag = [inSender tag];
    int state = [inSender intValue];
 
    [[view scene] setSourceDirectionOnOff:tag :state];
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourcePlayStatesCheckBox:(id)inSender
{
    int     tag = [inSender tag];
    int state = [inSender intValue];
 
    [[view scene] setSourcePlayState:tag :state];
    [view setNeedsDisplay:YES];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Source Effects *****
 
- (IBAction)    setSourceReverbSlider:(id)inSender
{
    float   level = [inSender floatValue];
    int     tag = [inSender tag];
 
    // update the corresponding text field
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceFourIndex:
            [mSourceFourReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceReverbLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
    }
        
    [[view scene] setSourceReverb:tag :level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceOcclusionSlider:(id)inSender
{
    float   level = [inSender floatValue];
    int     tag = [inSender tag];
 
    // update the corresponding text field
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceFourIndex:
            [mSourceFourOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceOcclusionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
    }
        
    [[view scene] setSourceOcclusion:tag :level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    setSourceObstructionSlider:(id)inSender
{
    float   level = [inSender floatValue];
    int     tag = [inSender tag];
 
    // update the corresponding text field
    switch (tag)
    {
        case kSourceOneIndex:
            [mSourceOneObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceTwoIndex:
            [mSourceTwoObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceThreeIndex:
            [mSourceThreeObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kSourceFourIndex:
            [mSourceFourObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
        case kCaptureSourceIndex:
            [mCaptureSourceObstructionLevel setStringValue: [NSString stringWithFormat: @"%.2f", level]];
            break;
    }
        
    [[view scene] setSourceObstruction:tag :level];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EDIT TEXT
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
#define kReferenceDistanceText  4200
#define kMaxDistanceText        4300
#define kRolloffFactorText      4400
#define kSourcePosXText         5000
#define kSourcePosYText         5100
#define kSourcePosZText         5200
#define kListenerPosXText       3000
#define kListenerPosZText       3002
 
- (void) controlTextDidEndEditing:(NSNotification *) aNotification {
    NSTextField * obj = [aNotification object];
 
    // which text field
    switch ([obj tag])
    {
        case kListenerElevation:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   elevation = [obj floatValue];
            [mListenerElevationSlider setFloatValue: elevation];            // move the corresponding slider
            [[view scene] setListenerElevation:elevation];                  // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
 
        case kListenerGainEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   gain = [obj floatValue];
            [mListenerGainSlider setFloatValue: gain];              // move the corresponding slider
            [[view scene] setListenerGain:gain];                    // Set OpenAL
        }
            break;
 
        case kDopplerFactorEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   doppler = [obj floatValue];
            [mDopplerFactorSlider setFloatValue: doppler];          // move the corresponding slider
            [[view scene] setDopplerFactor:doppler];                // Set OpenAL
        }
            break;
 
        case kSpeedOfSoundEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   sos = [obj floatValue];
            [mSpeedOfSoundSlider setFloatValue: sos];               // move the corresponding slider
            [[view scene] setSpeedOfSound:sos];                     // Set OpenAL
        }
            break;
 
        case kVelocitySpeedEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   velocity = [obj floatValue];
            [mListenerVelocityScalerSlider setFloatValue: velocity];        // move the corresponding slider
            [[view scene] setListenerVelocity:velocity : NULL : NULL];      // Set OpenAL
        }
            break;
 
        case kReverbLevelEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   level = [obj floatValue];
            [mListenerReverbLevelSlider setFloatValue: level];      // move the corresponding slider
            [[view scene] setGlobalReverb:level];                   // Set OpenAL
        }
            break;
 
        case kReverbEQFrequencyEditTextItem:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   frequency = [obj floatValue];
            [mReverbEQFrequencySlider setFloatValue: frequency];    // move the corresponding slider
            [[view scene] setReverbEQFrequency:frequency];          // Set OpenAL
        }
            break;
 
        case kReverbEQBandwidth:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   bandwidth = [obj floatValue];
            [mReverbEQBandwidthSlider setFloatValue: bandwidth];    // move the corresponding slider
            [[view scene] setReverbEQBandwidth:bandwidth];          // Set OpenAL
        }
            break;
 
        case kReverbEQGain:
        {   // get the numeric value of  the field string
            // set the slider to this value
            float   gain = [obj floatValue];
            [mReverbEQGainSlider setFloatValue: gain];              // move the corresponding slider
            [[view scene] setReverbEQGain:gain];                    // Set OpenAL
        }
            break;
 
        case kListenerPosXText:
        {
            float   pos = [obj floatValue];
            [[view scene] setListenerPositionX : pos];                  // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
 
        case kListenerPosZText:
        {
            float   pos = [obj floatValue];
            [[view scene] setListenerPositionZ : pos];                  // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
 
 
        case kSourcePosXText:
        case kSourcePosXText+1:
        case kSourcePosXText+2:
        case kSourcePosXText+3:
        case kSourcePosXText+4:
        {
            float   pos = [obj floatValue];
            [[view scene] setSourcePositionX:[obj tag] - kSourcePosXText : pos];                    // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
 
        case kSourcePosYText:
        case kSourcePosYText+1:
        case kSourcePosYText+2:
        case kSourcePosYText+3:
        case kSourcePosYText+4:
        {
            float   pos = [obj floatValue];
            [[view scene] setSourcePositionY:[obj tag] - kSourcePosYText : pos];                    // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
 
        case kSourcePosZText:
        case kSourcePosZText+1:
        case kSourcePosZText+2:
        case kSourcePosZText+3:
        case kSourcePosZText+4:
        {
            float   pos = [obj floatValue];
            [[view scene] setSourcePositionZ:[obj tag] - kSourcePosZText : pos];                    // Set OpenAL
            [view setNeedsDisplay:YES];
        }
            break;
            
        case kReferenceDistanceText:
        case kReferenceDistanceText+1:
        case kReferenceDistanceText+2:
        case kReferenceDistanceText+3:
        case kReferenceDistanceText+4:
        {
            float   ro = [obj floatValue];
            [[view scene] setSourceReferenceDistance:[obj tag] - kReferenceDistanceText : ro];                  // Set OpenAL
        }
            break;
 
        case kMaxDistanceText:
        case kMaxDistanceText+1:
        case kMaxDistanceText+2:
        case kMaxDistanceText+3:
        case kMaxDistanceText+4:
        {
            float   ro = [obj floatValue];
            [[view scene] setSourceMaxDistance:[obj tag] - kMaxDistanceText : ro];                  // Set OpenAL
        }
            break;
 
        case kRolloffFactorText:
        case kRolloffFactorText+1:
        case kRolloffFactorText+2:
        case kRolloffFactorText+3:
        case kRolloffFactorText+4:
        {
            float   ro = [obj floatValue];
            [[view scene] setSourceRolloffFactor:[obj tag] - kRolloffFactorText : ro];                  // Set OpenAL
        }
            break;
    }
}
 
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (IBAction)    captureSamplesButton:(id)inSender
{
    int     samplesCaptured = 0;
    [[view scene] captureSamples:&samplesCaptured];
    
 
    float       theValue = samplesCaptured;
    [mSamplesCaptured setStringValue: [NSString stringWithFormat: @"%.1f", theValue]];
}
 
- (void)windowWillClose:(NSNotification *)aNotification {
    [NSApp terminate:self];
}
 
@end
4.MyOpenALSupport.h
/*
     File: MyOpenALSupport.h
 Abstract: MyOpenALSupport.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#include <CoreFoundation/CoreFoundation.h>
#include <AudioToolbox/AudioToolbox.h>
#import <OpenAL/al.h>
#import <OpenAL/alc.h>
 
void* MyGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei*    outSampleRate);
5. MyOpenALSupport.c
/*
     File: MyOpenALSupport.c
 Abstract: MyOpenALSupport.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
 */
#include "MyOpenALSupport.h"
 
void* MyGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei*    outSampleRate)
{
    OSStatus                        err = noErr;    
    SInt64                          theFileLengthInFrames = 0;
    AudioStreamBasicDescription     theFileFormat;
    UInt32                          thePropertySize = sizeof(theFileFormat);
    ExtAudioFileRef                 extRef = NULL;
    void*                           theData = NULL;
    AudioStreamBasicDescription     theOutputFormat;
 
    // Open a file with ExtAudioFileOpen()
    err = ExtAudioFileOpenURL(inFileURL, &extRef);
    if(err) { printf("MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; }
    
    // Get the audio data format
    err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
    if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", err); goto Exit; }
    if (theFileFormat.mChannelsPerFrame > 2)  { printf("MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit;}
 
    // Set the client format to 16 bit signed integer (native-endian) data
    // Maintain the channel count and sample rate of the original source format
    theOutputFormat.mSampleRate = theFileFormat.mSampleRate;
    theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame;
 
    theOutputFormat.mFormatID = kAudioFormatLinearPCM;
    theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
    theOutputFormat.mFramesPerPacket = 1;
    theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
    theOutputFormat.mBitsPerChannel = 16;
    theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
    
    // Set the desired client (output) data format
    err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
    if(err) { printf("MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", err); goto Exit; }
    
    // Get the total frame count
    thePropertySize = sizeof(theFileLengthInFrames);
    err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
    if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", err); goto Exit; }
    
    // Read all the data into memory
    UInt32 theFramesToRead = (UInt32)theFileLengthInFrames;     
    UInt32 dataSize = theFramesToRead * theOutputFormat.mBytesPerFrame;;
    theData = malloc(dataSize);
    if (theData)
    {
        AudioBufferList     theDataBuffer;
        theDataBuffer.mNumberBuffers = 1;
        theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
        theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
        theDataBuffer.mBuffers[0].mData = theData;
        
        // Read the data into an AudioBufferList
        err = ExtAudioFileRead(extRef, &theFramesToRead, &theDataBuffer);
        if(err == noErr)
        {
            // success
            *outDataSize = (ALsizei)dataSize;
            *outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
            *outSampleRate = (ALsizei)theOutputFormat.mSampleRate;
        }
        else 
        { 
            // failure
            free (theData);
            theData = NULL; // make sure to return NULL
            printf("MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit;
        }   
    }
    
Exit:
    // Dispose the ExtAudioFileRef, it is no longer needed
    if (extRef) ExtAudioFileDispose(extRef);
    return theData;
}
6. MyOpenGLView.h
/*
     File: MyOpenGLView.h
 Abstract: MyOpenGLView.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import <Cocoa/Cocoa.h>
#import "Scene.h"
 
@interface MyOpenGLView : NSOpenGLView {
     Scene* scene;
}
 
- (id)      initWithFrame: (NSRect) frame;  //called when MyOpenGLView is a "Custom View"
- (void)    updateProjection;
 
- (Scene *) scene;
- (void)    setScene:(Scene *)value;
 
 
@end
7. MyOpenGLView.m
/*
     File: MyOpenGLView.m
 Abstract: MyOpenGLView.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import "MyOpenGLView.h"
 
@implementation MyOpenGLView
 
//////////////////////////////////////////////////////
//Override NSView's initWithFrame: to specify our pixel format:
//Note: initWithFrame is called only if a "Custom View" is used in Interface BBuilder 
//and the custom class is a subclass of NSView. For more information on resource loading
//see: developer.apple.com (ADC Home > Documentation > Cocoa > Resource Management > Loading Resources) 
- (id) initWithFrame: (NSRect) frame
{
    GLuint attribs[] = 
    {
        NSOpenGLPFAAccelerated,
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFANoRecovery,
        NSOpenGLPFAColorSize, 32,
        NSOpenGLPFADepthSize, 16,
        0
    };
    
    NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*) attribs]; 
    
    if (!fmt)
        NSLog(@"No OpenGL pixel format");
    
    self = [super initWithFrame:frame pixelFormat: [fmt autorelease]];
    
    if (self)
        scene = [[Scene alloc] init];
    
    return self;
}
 
- (void) dealloc
{
    //remember to clean up!
    [scene release];
    [super dealloc];
}
 
#pragma mark OpenGL drawing
 
// update the projection matrix based on view size
- (void) updateProjection {
    //get bounds
    NSRect bounds = [self bounds];
    
    //define the viewport
    glViewport(0, 0, (GLsizei) bounds.size.width, (GLsizei)bounds.size.height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    //define "the world" window
    gluOrtho2D(0.0, bounds.size.width, 0.0, bounds.size.height);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
//  Override the view's drawRect: to draw our GL content. 
- (void) drawRect: (NSRect) rect
{
    [[self openGLContext] makeCurrentContext];
    [self updateProjection];
    
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    
    //draw Objects
    [scene drawObjects];
    
    [[self openGLContext] flushBuffer];
}
 
#pragma mark Mouse Click Handling 
- (void)mouseUp:(NSEvent *)theEvent {
    [scene resetCurrentObject]; //selects "No object"
    
    /*
        could return a bool and if yes then redraw, it means that an object had to be manually relocated to not be out of bounds
        
    */
    
    
}
 
//View Accepts Mouse down events
- (void)mouseDown:(NSEvent*) event {
    NSPoint eventLocation = [self convertPoint:[event locationInWindow] fromView:nil];
 
    //set the listener position to the new mouse location
    if([scene selectCurrentObject:&eventLocation] >=0) {
        [scene setObjectPosition:&eventLocation];
    }   
    
    //redraw screen, calls drawRect
    [self setNeedsDisplay:YES];
}
 
- (void) mouseDragged:(NSEvent*) event {
    [self mouseDown:event];
}
 
#pragma mark FirstResponder Changes
 
- (BOOL)acceptsFirstResponder
{
    return YES;
}
 
- (BOOL)becomeFirstResponder
{
    return  YES;
}
 
- (BOOL)resignFirstResponder
{
    return YES;
}
#pragma mark Get/Set
 
- (Scene *)scene {
    return [[scene retain] autorelease];
}
 
- (void)setScene:(Scene *)value {
    if (scene != value) {
        [scene release];
        scene = [value copy];
    }
}
 
@end
8.Scene.h
/*
     File: Scene.h
 Abstract: Scene.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>
 
#import <OpenAL/al.h>
#import <OpenAL/alc.h>
 
#include "MyOpenALSupport.h"
 
@interface Scene : NSObject {
@public
 
    bool    mHasInput;
    bool    mHasASAExtension;
    int     mCurrentObject;
    float   mCenterOffset;
    float   mVelocityScaler;
    float   mListenerElevation;
    float   mAngle;                 // listener direction in degrees
    int     mSourceOn[5];           // play state
    float   mSourceDirection[5];    // angle in degrees
    float   mSourceVelocityScaler[5];
    float   mSourceOuterConeGain[5];
    float   mSourceInnerConeAngle[5];
    float   mSourceOuterConeAngle[5];
}
 
- (id)   init;
- (void) initOpenAL; 
 
// OpenGLView
- (void) drawObjects;
- (void) drawListener;
- (void) drawSourceWithDirection :(int)inTag;
- (void) drawSources;
- (void) resetCurrentObject;
- (bool) pointInCircle:(NSPoint *)point x:(float)x  y:(float)y  r:(float)r;
- (void) setObjectPosition:(NSPoint *)point;
- (int)  selectCurrentObject:(NSPoint *)point;
- (void) setListenerPosition:(NSPoint *)point;
- (void) setSourcePositionFromPoint:(NSPoint *)point;
- (void )setSourcePositionX:(int) inTag : (float)inX;
- (void )setSourcePositionY:(int) inTag : (float)inY;
- (void )setSourcePositionZ:(int) inTag : (float)inZ;
 
- (void) getCurrentObjectPosition:(int*)outCurObject : (float*) outX : (float*) outZ;
- (void) getObjectPosition:(int)inObject : (float*) outX : (float*) outZ;
 
// Context Settings
 
- (void) setListenerPositionX: (float)inX;
- (void) setListenerPositionZ: (float)inZ;
- (void) setListenerOrientation: (float)angle : (float*) outX : (float*) outZ;
- (void) setListenerElevation: (float)elevation;
- (void) setListenerVelocity:(float) inVelocity : (float*) outX : (float*) outZ;
- (void) setListenerGain :(float)inGain;
 
- (void) setDopplerFactor :(float)inValue;
- (void) setSpeedOfSound :(float)inValue;
- (void) setDistanceModel:(int)inTag;
 
- (void) setReverbOn:(int)inCheckBoxValue;
- (void) setGlobalReverb :(float)inReverbLevel;
- (void) setReverbRoomType:(int)inTag controlIndex:(int) inIndex title:(NSString*) inTitle;
- (void) setReverbQuality:(int)inTag;
- (void) setReverbEQGain:(float)inLevel;
- (void) setReverbEQBandwidth:(float)inLevel;
- (void) setReverbEQFrequency:(float)inLevel;
 
- (void) setRenderChannels:(int)inCheckBoxValue;
- (void) setRenderQuality:(int)inCheckBoxValue;
 
// Source Settings
 
- (void) setSourcePlayState:(int)inTag :(int)inCheckBoxValue;
 
- (void) setSourcePitch:(int)inTag :(float)inPitch;
- (void) setSourceGain:(int)inTag :(float)inGain;
 
- (void) setSourceRolloffFactor:(int)inTag :(float)inRolloff;
- (float) getSourceRolloffFactor:(int)inTag;
 
- (void) setSourceReferenceDistance:(int)inTag :(float)inReferenceDistance;
- (float) getSourceReferenceDistance:(int)inTag;
 
- (void) setSourceMaxDistance:(int)inTag :(float)inMaxDistance;
- (float) getSourceMaxDistance:(int)inTag;
 
- (void) setSourceDirectionOnOff:(int)inTag :(int)inCheckBoxValue;
- (void) setSourceReverb:(int)inTag :(float)inReverbSendLevel;
- (void) setSourceOcclusion:(int)inTag :(float)inLevel;
- (void) setSourceObstruction:(int)inTag :(float)inLevel;
 
- (void) getSourceVelocities:(int)inTag : (float*) outX : (float*) outZ;
- (void) getSourceDirections:(int)inTag : (float*) outX : (float*) outZ;
 
- (void) setSourceAngle:(int)inTag :(float)inAngle;
- (void) setSourceDirection:(int)inTag;
- (void) setSourceVelocity:(int)inTag :(float) inVelocity;
 
- (void) setSourceOuterConeGain:(int)inTag :(float) inGain;
- (void) setSourceInnerConeAngle:(int)inTag :(float) inAngle;
- (void) setSourceOuterConeAngle:(int)inTag :(float) inAngle;
 
 
- (void) captureSamples :(int*)outValue;
- (bool) hasInput;
- (bool) hasASAExtension;
 
@end
9.Scene.m
/*
     File: Scene.m
 Abstract: Scene.h
  Version: 1.2
 
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
 Inc. ("Apple") in consideration of your agreement to the following
 terms, and your use, installation, modification or redistribution of
 this Apple software constitutes acceptance of these terms.  If you do
 not agree with these terms, please do not use, install, modify or
 redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and
 subject to these terms, Apple grants you a personal, non-exclusive
 license, under Apple's copyrights in this original Apple software (the
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
 Software, with or without modifications, in source and/or binary forms;
 provided that if you redistribute the Apple Software in its entirety and
 without modifications, you must retain this notice and the following
 text and disclaimers in all such redistributions of the Apple Software.
 Neither the name, trademarks, service marks or logos of Apple Inc. may
 be used to endorse or promote products derived from the Apple Software
 without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or
 implied, are granted by Apple herein, including but not limited to any
 patent rights that may be infringed by your derivative works or by other
 works in which the Apple Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 
 Copyright (C) 2012 Apple Inc. All Rights Reserved.
 
*/
#import "Scene.h"
#include <math.h>
 
#define DEG2RAD(x) (0.0174532925 * (x))
#define RAD2DEG(x) (57.295779578 * (x))
 
#define kSquareSize             500     // needs to be the size of the custom NIB object
#define kSourceCircleRadius     10.0
#define kListenerCircleRadius   20.0
#define kDefaultDistance        175.0
#define NUM_BUFFERS_SOURCES     5       // this test app has 4 Source Objects and 4 Buffer Objects
 
#define kCaptureSamples             44100 * 5 // capture 5 seconds of data at 44k
#define kCaptureSourceIndex         4
#define kCapturedAudioSampleRate    44100
 
#define kListenerIndex          5
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Globals
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCdevice   *gCaptureDevice = NULL;
UInt8*      gCaptureData = NULL;
 
float       gListenerPos[3] = {0.0,  0.0,  0.0};        // default position is centered
float       gListenerDirection = 0;
int         gSourceDirectionOnOff[NUM_BUFFERS_SOURCES] = {0, 0, 0, 0, 0};
float       gSourceAngle[NUM_BUFFERS_SOURCES] = {225, 315, 135, 45, 180}; // each source is now facing the center
float       gSourcePos[NUM_BUFFERS_SOURCES][3]  = { {kDefaultDistance, 0.0, -kDefaultDistance},
                                                        {kDefaultDistance, 0.0, kDefaultDistance},
                                                        {-kDefaultDistance , 0.0, -kDefaultDistance},
                                                        {-kDefaultDistance , 0.0, kDefaultDistance},
                                                        {0.0 , 0.0, -kDefaultDistance}      }; 
 
char *  gSourceFile[NUM_BUFFERS_SOURCES - 1];           // only the 1st 4 sources use data from a file
ALuint  gBuffer[NUM_BUFFERS_SOURCES];
ALuint  gSource[NUM_BUFFERS_SOURCES];
 
float gSourceInnerConeAngle[NUM_BUFFERS_SOURCES] = {90, 90, 90, 90, 90};
float gSourceOuterConeAngle[NUM_BUFFERS_SOURCES] = {180, 180, 180, 180, 180};
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Extension API Procs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALvoid  AL_APIENTRY (*alMacOSXRenderChannelCountProcPtr) (const ALint value);
ALvoid  alMacOSXRenderChannelCountProc(const ALint value)
{
    static  alMacOSXRenderChannelCountProcPtr   proc = NULL;
    
    if (proc == NULL) {
        proc = (alMacOSXRenderChannelCountProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alMacOSXRenderChannelCount");
    }
    
    if (proc)
        proc(value);
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALvoid  AL_APIENTRY (*alcMacOSXRenderingQualityProcPtr) (const ALint value);
ALvoid  alcMacOSXRenderingQualityProc(const ALint value)
{
    static  alcMacOSXRenderingQualityProcPtr    proc = NULL;
    
    if (proc == NULL) {
        proc = (alcMacOSXRenderingQualityProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXRenderingQuality");
    }
    
    if (proc)
        proc(value);
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALvoid  AL_APIENTRY (*alcMacOSXMixerOutputRateProcPtr) (const ALdouble value);
ALvoid  alcMacOSXMixerOutputRateProc(const ALdouble value)
{
    static  alcMacOSXMixerOutputRateProcPtr proc = NULL;
    
    if (proc == NULL) {
        proc = (alcMacOSXMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXMixerOutputRate");
    }
    
    if (proc)
        proc(value);
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALdouble (*alcMacOSXGetMixerOutputRateProcPtr) ();
ALdouble  alcMacOSXGetMixerOutputRateProc()
{
    static  alcMacOSXGetMixerOutputRateProcPtr  proc = NULL;
    
    if (proc == NULL) {
        proc = (alcMacOSXGetMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXGetMixerOutputRate");
    }
    
    if (proc)
        return proc();
 
    return 0.0;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALvoid  AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq);
ALvoid  alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq)
{
    static  alBufferDataStaticProcPtr   proc = NULL;
    
    if (proc == NULL) {
        proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic");
    }
    
    if (proc)
        proc(bid, format, data, size, freq);
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef OSStatus    (*alcASASetSourceProcPtr)   (const ALuint property, ALuint source, ALvoid *data, ALuint dataSize);
OSStatus  alcASASetSourceProc(const ALuint property, ALuint source, ALvoid *data, ALuint dataSize)
{
    OSStatus    err = noErr;
    static  alcASASetSourceProcPtr  proc = NULL;
    
    if (proc == NULL) {
        proc = (alcASASetSourceProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcASASetSource");
    }
    
    if (proc)
        err = proc(property, source, data, dataSize);
    return (err);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef OSStatus    (*alcASASetListenerProcPtr) (const ALuint property, ALvoid *data, ALuint dataSize);
OSStatus  alcASASetListenerProc(const ALuint property, ALvoid *data, ALuint dataSize)
{
    OSStatus    err = noErr;
    static  alcASASetListenerProcPtr    proc = NULL;
    
    if (proc == NULL) {
        proc = (alcASASetListenerProcPtr) alcGetProcAddress(NULL, "alcASASetListener");
    }
    
    if (proc)
        err = proc(property, data, dataSize);
    return (err);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef ALCdevice*  (*alcCaptureOpenDeviceProcPtr)  (const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
ALCdevice*  alcCaptureOpenDeviceProc(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
{
    ALCdevice*  device = NULL;
    device = alcCaptureOpenDevice (devicename, frequency, format, buffersize);
    return (device);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef void    (*alcCaptureStartProcPtr)   (ALCdevice* device);
void  alcCaptureStartProc(ALCdevice* device)
{
    alcCaptureStart (device);   
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef void    (*alcCaptureSamplesProcPtr) (ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
void  alcCaptureSamplesProc(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
{
    alcCaptureSamples (device, buffer, samples);    
 
    return;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize OpenAL -Get an Audio Device and Set Current OpenAL Context
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALvoid*     gStaticBufferData = NULL;
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TeardownOpenAL()
{
    ALCcontext  *context = NULL;
    ALCdevice   *device = NULL;
    ALuint      returnedNames[NUM_BUFFERS_SOURCES];
 
    // Delete the Sources
    alDeleteSources(NUM_BUFFERS_SOURCES, returnedNames);
    // Delete the Buffers
    alDeleteBuffers(NUM_BUFFERS_SOURCES, returnedNames);
    
    //Get active context
    context = alcGetCurrentContext();
    //Get device for active context
    device = alcGetContextsDevice(context);
    //Release context
    alcDestroyContext(context);
    //Close device
    alcCloseDevice(device);
    if (gStaticBufferData)
        free(gStaticBufferData);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void    InitializeBuffers() 
{
    ALenum  error = AL_NO_ERROR;
    ALenum  format;
    ALvoid* data;
    ALsizei size;
    ALsizei freq;
    UInt32  i;
    
    // only the 1st 4 sources get data from a file. The 5th source gets data from capture
    for (i = 0; i < NUM_BUFFERS_SOURCES - 1; i ++)
    {   
        //Get the current path to the audio file (which is contained in the application bundle) 
        NSString* fileString = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%s", gSourceFile[i]] ofType:@"wav"];
        // get some audio data from a wave file
        CFURLRef fileURL = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)fileString, NULL);
        data = MyGetOpenALAudioData(fileURL, &size, &format, &freq);
        
        CFRelease(fileURL);
        
        if((error = alGetError()) != AL_NO_ERROR) {
            printf("error loading %s: ", gSourceFile[i]);
            exit(1);
        }
        
        if (i == 0)
        {
            // use the static buffer data API once for testing
            gStaticBufferData = (ALvoid*)malloc(size);
            memcpy(gStaticBufferData, data, size);
            alBufferDataStaticProc(gBuffer[i], format, gStaticBufferData, size, freq);
        }
        else
        {
            // Attach Audio Data to OpenAL Buffer
            alBufferData(gBuffer[i], format, data, size, freq);
        }
        
        // Release the audio data
        free(data);
        
        if((error = alGetError()) != AL_NO_ERROR) {
            printf("error unloading %s: ", gSourceFile[i]);
        }   
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void InitializeSourcesAndPlay() 
{
    UInt32 i;
    ALenum error = AL_NO_ERROR;
    alGetError(); // Clear the error
    
    for (i = 0; i < NUM_BUFFERS_SOURCES; i++)
    {
        // Turn Looping ON
        alSourcei(gSource[i], AL_LOOPING, AL_TRUE);
        // Set Source Position
        alSourcefv(gSource[i], AL_POSITION, gSourcePos[i]);
        // Set Source Reference Distance
        alSourcef(gSource[i],AL_REFERENCE_DISTANCE, 5.0f);
 
        // only load data and start playing the non capture sources
        if (i < NUM_BUFFERS_SOURCES-1)
        {
            // attach OpenAL Buffer to OpenAL Source
            alSourcei(gSource[i], AL_BUFFER, gBuffer[i]);
            // Start Playing Sound
            alSourcePlay(gSource[i]);
        }
    }
            
    if((error = alGetError()) != AL_NO_ERROR) {
        printf("Error attaching buffer to source");
        exit(1);
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SCENE class
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@implementation Scene
 
- (id) init
{
    if((self = [super init])) {
        
        mHasASAExtension = false;
        mHasInput = false;
        
        //4 WAV files in the application bundle resources
        gSourceFile[0] = "sound_engine";
        gSourceFile[1] = "sound_voices";
        gSourceFile[2] = "sound_bubbles";
        gSourceFile[3] = "sound_electric";
    
        mCurrentObject = -1;
        mCenterOffset = kSquareSize/2.0;
        mVelocityScaler = 0.0;
        mAngle = 0.0;
        mListenerElevation = 0.0;
 
        mSourceOn[0] = 1;
        mSourceOn[1] = 1;
        mSourceOn[2] = 1;
        mSourceOn[3] = 1;
        mSourceOn[4] = 0; // capture
 
        mSourceDirection[0] = 0.0;
        mSourceDirection[1] = 0.0;
        mSourceDirection[2] = 0.0;
        mSourceDirection[3] = 0.0;
        mSourceDirection[4] = 0.0; // capture
 
        mSourceVelocityScaler[0] = 0.0;
        mSourceVelocityScaler[1] = 0.0;
        mSourceVelocityScaler[2] = 0.0;
        mSourceVelocityScaler[3] = 0.0;
        mSourceVelocityScaler[4] = 0.0; // capture
 
        mSourceOuterConeGain[0] = 0.0;
        mSourceOuterConeGain[1] = 0.0;
        mSourceOuterConeGain[2] = 0.0;
        mSourceOuterConeGain[3] = 0.0;
        mSourceOuterConeGain[4] = 0.0; // capture
        
        mSourceInnerConeAngle[0] = 90.0;
        mSourceInnerConeAngle[1] = 90.0;
        mSourceInnerConeAngle[2] = 90.0;
        mSourceInnerConeAngle[3] = 90.0;
        mSourceInnerConeAngle[4] = 90.0; // capture
 
        mSourceOuterConeAngle[0] = 180.0;
        mSourceOuterConeAngle[1] = 180.0;
        mSourceOuterConeAngle[2] = 180.0;
        mSourceOuterConeAngle[3] = 180.0;
        mSourceOuterConeAngle[4] = 180.0; // capture
 
        [self initOpenAL];
        [self setListenerOrientation:0 : NULL : NULL];
        [self setListenerVelocity:0 : NULL : NULL];
        [self setListenerGain:0.5];
    }
    return self;
}
 
- (void) dealloc {
    TeardownOpenAL();
    [super dealloc];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//draws a simple filled circle using quick glu calls
static void drawCircle(GLdouble x, GLdouble y, GLdouble r, GLfloat red, GLfloat grn, GLfloat blu){
 
    // A GRADIENT CIRCLE - looks better
    glPushMatrix();
        glTranslatef(x, y, 0.0);
        glBegin(GL_TRIANGLE_FAN);
 
            glColor3f(red, grn, blu);       
            glVertex3f(0.0, 0.0, 0.0);      
            {
                UInt32  i;
                float   x, y;
                float   stepAngle = 20;
                double  theAngle = -90;
                for (i = 0; i <= 18; i++)
                {
                    glColor3f(red/2, grn/2, blu/2);     // gradient
                    float   rads = DEG2RAD(theAngle);
                    x = cos(rads) * r;
                    y = sin(rads) * r;
                    glVertex3f(x, y, 0.0);
                    theAngle += stepAngle;
                    glColor3f(red, grn, blu);           // gradient
                }
            }
 
        glEnd();
    glPopMatrix();
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) drawObjects {
        
    // layer the objects correctly
    if (mListenerElevation > 0)
    {
        [self drawSources];
        [self drawListener];
    }
    else
    {
        [self drawListener];
        [self drawSources];
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) drawListener {
    
    float   elevationSizeScaler = (abs(mListenerElevation) / 200.0)/2; // -1 to 1
    // translate that to .5 to 1.5
    if (mListenerElevation > 0)
        elevationSizeScaler = 1 + elevationSizeScaler;
    else
        elevationSizeScaler = 1 - elevationSizeScaler;
    
    // draw a triangle (nose)
    glPushMatrix();
        glTranslatef(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 0.0);
        //Rotate to show the listeners current orientation
        glRotatef(gListenerDirection, 0.0, 0.0, -1.0);
        glBegin(GL_TRIANGLES);
            glColor3f(0.0, 1.0, 0.0);
            glVertex3f(-6.0 * elevationSizeScaler, 0.0, 0.0);
            glVertex3f(6.0 * elevationSizeScaler, 0.0, 0.0);
            glColor3f(1.0, 0.0, 0.0);
            glVertex3f(0.0, 35.0 * elevationSizeScaler, 0.0);
        glEnd();
    glPopMatrix();
 
 
    // ears
    glPushMatrix();
        glTranslatef(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 0.0);
        //Rotate to show the listeners current orientation
        glRotatef(gListenerDirection, 0.0, 0.0, -1.0);
        glBegin(GL_QUADS);
            glColor3f(0.0, 0.0, 0.8);
            glVertex3f(-25.0 * elevationSizeScaler, 8.0 * elevationSizeScaler, 0.0);
            glVertex3f(-25.0 * elevationSizeScaler, -8.0 * elevationSizeScaler, 0.0);
            glVertex3f(24.5 * elevationSizeScaler, -8.0 * elevationSizeScaler, 0.0);
            glVertex3f(24.5 * elevationSizeScaler, 8.0 * elevationSizeScaler, 0.0);
        glEnd();
    glPopMatrix();
    
    // minor adjustments to position circle
    drawCircle(gListenerPos[0]- .5 + mCenterOffset, -gListenerPos[2] - 1 + mCenterOffset, 20 * elevationSizeScaler, 0 , 0, 1);
 
    if (mListenerElevation != 0.0)
        drawCircle(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 3, 0 , 0, .6);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define kArcSteps           16
#define kInnerArcRadius     32  // larger but partially transparent
#define kOuterArcRadius     26  // smaller with gradient
 
- (void) drawSourceWithDirection :(int)inTag
{
    
    glEnable(GL_BLEND); // blend the cones so both can be seen, top cone (INNER) is partially transparent
                        // bottom cone (OUTER) has a gradient
                
    // CONE DRAWING - OUTER
    if (gSourceDirectionOnOff[inTag])
    {
        float   x, z;
        [self getSourceDirections:inTag : &x : &z];
 
        glPushMatrix();
            glTranslatef((gSourcePos[inTag][0] + mCenterOffset) + x, (-gSourcePos[inTag][2] + mCenterOffset) + z, 0.0);
            glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0);
            glBegin(GL_TRIANGLE_FAN);
                glColor3f(0.0, 0.5, 0.0);       
                glVertex3f(0.0, 0.0, 0.0);      
                {
                    UInt32  i;
                    float   x, y;
                    float   stepAngle = mSourceOuterConeAngle[inTag]/kArcSteps;
                    double  theAngle = -(mSourceOuterConeAngle[inTag]/2) + 90;
                    for (i = 0; i <= kArcSteps; i++)
                    {
                        glColor3f(0.0, 0.2, 0.0);       // gradient
                        float   rads = DEG2RAD(theAngle);
                        x = cos(rads) * kOuterArcRadius;
                        y = sin(rads) * kOuterArcRadius;
 
                        glVertex3f(x, y, 0.0);
                        theAngle += stepAngle;
                        glColor3f(0.0, 0.8, 0.0);       // gradient
                    }
                }
 
 
            glEnd();
        glPopMatrix();
    }
 
    // CONE DRAWING - INNER
    if (gSourceDirectionOnOff[inTag])
    {
        float   x, z;
        [self getSourceDirections:inTag : &x : &z];
 
        glPushMatrix();
            glTranslatef((gSourcePos[inTag][0] + mCenterOffset) + x, (-gSourcePos[inTag][2] + mCenterOffset) + z, 0.0);
            glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0);
            glBegin(GL_TRIANGLE_FAN);
                glColor4f(0.0, 1.0, 0.0, .4); // transparency (.4)
                glVertex3f(0.0, 0.0, 0.0);
                {
                    UInt32  i;
                    float   x, y;
                    float   stepAngle = mSourceInnerConeAngle[inTag]/kArcSteps;
                    double  theAngle = -(mSourceInnerConeAngle[inTag]/2) + 90;
                    for (i = 0; i <= kArcSteps; i++)
                    {
                        float   rads = DEG2RAD(theAngle);
                        x = cos(rads) * kInnerArcRadius;
                        y = sin(rads) * kInnerArcRadius;
                        glVertex3f(x, y, 0.0);
                        theAngle += stepAngle;
                    }
                }
 
            glEnd();
        glPopMatrix();
    }
    
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);          // blend the cones
    glDisable(GL_BLEND);                                        // blending is done
 
    // draw direction triangle if there is any velocity setting above zero
    if (mSourceVelocityScaler[inTag] > 0)
    {
        float   triangleLength = kSourceCircleRadius*2;
        triangleLength += (mSourceVelocityScaler[inTag]/686.0) * (kSourceCircleRadius*2);
        
        glPushMatrix();
            glTranslatef(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, 0.0);
            glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0);
            glBegin(GL_TRIANGLES);
                glColor3f(0.0, 1.0, 0.0);
                glVertex3f(-4.0, 0.0, 0.0);
                glVertex3f(4.0, 0.0, 0.0);
                glColor3f(1.0, 0.0, 0.0);
                glVertex3f(0.0, triangleLength, 0.0);
            glEnd();
        glPopMatrix();
    }
    
    //minor adjustments to position circle
    if (mSourceOn[inTag] == 0)
    {
        // draw a gray circle if source is not playing
        drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, .5 , .5, .5); // capture circle is different color
    }
    else
    {
        if (inTag == kCaptureSourceIndex)
            drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, 1 , 1, 0); // capture circle is different color
        else
            drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, 1 , 0, 0);
    }
 
    if (gSourcePos[inTag][1] != 0.0)
        drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2]+ mCenterOffset, 3, .5 , 0, 0);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) drawSources
{
    //draw sources as 4 red circles
    [self drawSourceWithDirection: 0];
    [self drawSourceWithDirection: 1];
    [self drawSourceWithDirection: 2];
    [self drawSourceWithDirection: 3];
 
    [self drawSourceWithDirection: kCaptureSourceIndex]; // capture
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(void) resetCurrentObject
{
    //set current object to -1 to designate no object selected.
    mCurrentObject = -1;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(int) selectCurrentObject:(NSPoint *)point
{
    //find the object (circle) that contains the point
    //return -1 if none are found
    
    if(mCurrentObject != -1)
      return mCurrentObject;
      
    if([self pointInCircle:point x:gSourcePos[0][0] + mCenterOffset y:-gSourcePos[0][2] + mCenterOffset r:kSourceCircleRadius]){
        mCurrentObject = 0;
    }else if    ([self pointInCircle:point x:gSourcePos[1][0] + mCenterOffset y:-gSourcePos[1][2] + mCenterOffset r:kSourceCircleRadius])
        mCurrentObject = 1;
    else if ([self pointInCircle:point x:gSourcePos[2][0] + mCenterOffset y:-gSourcePos[2][2] + mCenterOffset r:kSourceCircleRadius])
        mCurrentObject = 2;
    else if ([self pointInCircle:point x:gSourcePos[3][0] + mCenterOffset y:-gSourcePos[3][2] + mCenterOffset r:kSourceCircleRadius])
        mCurrentObject = 3; 
    else if ([self pointInCircle:point x:gSourcePos[4][0] + mCenterOffset y:-gSourcePos[4][2] + mCenterOffset r:kSourceCircleRadius])
        mCurrentObject = kCaptureSourceIndex;       // CAPTURE SOURCE
    else if ([self pointInCircle:point x:gListenerPos[0] + mCenterOffset y:-gListenerPos[2] + mCenterOffset r:kListenerCircleRadius])
        mCurrentObject = kListenerIndex;
                
    return mCurrentObject;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// need to detect if point is in a source circle
// if so, return the source pos ID
// if not, return -1
- (bool) pointInCircle:(NSPoint *)point x:(float)x  y:(float)y  r:(float)r
{
   float x1 =point->x;
   float y1 = point->y;
 
   float dist  =0;
   //calculate distance from the center of the circle to the point clcked
   dist =(((x1 - x )*(x1 - x ))   +   ((y1 - y)*(y1 - y)));
 
    //Here we can test this for each of the sources
    
    //if the distance is less than the radius (squared), then the point is inside the circle
    if (dist <= r*r)
      return TRUE;
    else
     return FALSE;  
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(void) setObjectPosition:(NSPoint *)point
{   
    if(mCurrentObject < kListenerIndex){
        [self setSourcePositionFromPoint:point];
    } 
    else if (mCurrentObject == kListenerIndex ) //listener
    {
        [self setListenerPosition:point];
    }
    
    // NOTIFY: Post a notification that object mCurrentObject has moved so the coordinate text can be updated
    [[NSNotificationCenter defaultCenter] postNotificationName: @"OALNotify" object: self]; 
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) getCurrentObjectPosition:(int*)outCurObject : (float*) outX : (float*) outZ
{
    if(mCurrentObject < kListenerIndex){
        if(outX) *outX = gSourcePos[mCurrentObject][0];
        if(outX) *outZ = gSourcePos[mCurrentObject][2];
    } 
    else if (mCurrentObject == kListenerIndex ) //listener
    {
        if(outX) *outX = gListenerPos[0];
        if(outX) *outZ = gListenerPos[2];
 
    }
    if(outCurObject) *outCurObject = mCurrentObject;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) getObjectPosition:(int)inObject : (float*) outX : (float*) outZ;
{
    if(inObject < kListenerIndex){
        if(outX) *outX = gSourcePos[inObject][0];
        if(outX) *outZ = gSourcePos[inObject][2];
    } 
    else if (inObject == kListenerIndex ) //listener
    {
        if(outX) *outX = gListenerPos[0];
        if(outX) *outZ = gListenerPos[2];
 
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize OpenAL Context, Buffers, Listener & Sources
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) initOpenAL {
        
    ALenum          error;
    ALCcontext      *newContext = NULL;
    ALCdevice       *newDevice = NULL;
 
    // Create a new OpenAL Device
    // Pass NULL to specify the systemÕs default output device
    newDevice = alcOpenDevice(NULL);
    if (newDevice != NULL)
    {
        // Create a new OpenAL Context
        // The new context will render to the OpenAL Device just created 
        newContext = alcCreateContext(newDevice, 0);
        if (newContext != NULL)
        {
            // Make the new context the Current OpenAL Context
            alcMakeContextCurrent(newContext);
 
            // Create some OpenAL Buffer Objects
            alGenBuffers(NUM_BUFFERS_SOURCES, gBuffer);
            if((error = alGetError()) != AL_NO_ERROR) {
                printf("Error Generating Buffers: ");
                exit(1);
            }
 
            // Create some OpenAL Source Objects
            alGenSources(NUM_BUFFERS_SOURCES, gSource);
            if(alGetError() != AL_NO_ERROR) 
            {
                printf("Error generating sources! \n");
                exit(1);
            }
        }
    }
 
    // Capture
    if (alcIsExtensionPresent( NULL, "ALC_EXT_CAPTURE" ))
    {
        // Setup a Capture Device
        gCaptureDevice = alcCaptureOpenDeviceProc( NULL, kCapturedAudioSampleRate, AL_FORMAT_MONO16, kCaptureSamples );
        if(gCaptureDevice)
        {
            // Capture is supported and there is an input device
            alcCaptureStartProc(gCaptureDevice);        
 
            mSourceOn[4] = 1; // capture
            mHasInput = true;
        }
        else
            mHasInput = false;  // Capture is supported but there is no input device
    }
    else
        mHasInput = false;  // Capture Not Supported by this OAL version
    
    // Reverb and Effects
    if (alcIsExtensionPresent( NULL, "ALC_EXT_ASA" ))
        mHasASAExtension = true;
    else
        mHasASAExtension = false;
        
    alGetError();
    
    InitializeBuffers();
    InitializeSourcesAndPlay();
}
 
- (bool) hasInput
{
    return mHasInput;
}
 
- (bool) hasASAExtension
{
    return mHasASAExtension;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Orientation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setListenerOrientation: (float) angle : (float*) outX : (float*) outZ
{
    mAngle = angle;
    ALenum  error = AL_NO_ERROR;
    float   rads = DEG2RAD(mAngle);
    float   orientation[6] = {  0.0, 0.0, -1.0,    // direction
                                0.0, 1.0, 0.0   }; //up 
                                 
    orientation[0] = cos(rads);
    orientation[1] = sin(rads);     // No Change to the Z vector
    gListenerDirection = RAD2DEG(atan2(orientation[1], orientation[0]));
    
    // Change OpenAL Listener's Orientation
    orientation[0] = sin(rads);
    orientation[1] = 0.0;           // No Change to the Y vector
    orientation[2] = -cos(rads);    
 
    alListenerfv(AL_ORIENTATION, orientation);
    if((error = alGetError()) != AL_NO_ERROR)
        printf("Error Setting Listener Orientation");
        
    // set the listener velocity as well, in this app we are always syncing the velocity to the direction that the listener is facing
    [self setListenerVelocity: mVelocityScaler : outX : outZ];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Listener Velocity Gain
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setListenerVelocity:(float) inVelocity : (float*) outX : (float*) outZ
{
    mVelocityScaler = inVelocity;
    
    ALenum  error = AL_NO_ERROR;
    float   rads = DEG2RAD(mAngle);
    float   velocity[3] = { 0.0, 0.0, 0.0}; //up    
                                    
    // Change OpenAL Listener's Orientation
    velocity[0] = sin(rads) * mVelocityScaler;
    velocity[1] = 0.0;          // No Change to the Y vector
    velocity[2] = -cos(rads) * mVelocityScaler;
    
    if (outX) *outX = velocity[0];  
    if (outZ) *outZ = velocity[2];  
 
    alListenerfv(AL_VELOCITY, velocity);
    if((error = alGetError()) != AL_NO_ERROR)
        printf("Error Setting Listener Velocity");
 
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Position
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setSourcePositionFromPoint:(NSPoint *)point
{
    gSourcePos[mCurrentObject][0] = point->x - mCenterOffset;
    gSourcePos[mCurrentObject][2] = -point->y + mCenterOffset;  // top view only in this demo!
    
    alSourcefv(gSource[mCurrentObject], AL_POSITION, gSourcePos[mCurrentObject]);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setSourcePositionX:(int) inTag : (float)inX
{
    gSourcePos[inTag][0] = inX;
    alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]);
    [self drawSourceWithDirection :inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setSourcePositionY:(int) inTag : (float)inY
{
    gSourcePos[inTag][1] = inY;
    alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setSourcePositionZ:(int) inTag : (float)inZ
{
    gSourcePos[inTag][2] = inZ;
    alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]);
    [self drawSourceWithDirection :inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setListenerPosition:(NSPoint *) point
{
    gListenerPos[0] = point->x - mCenterOffset;
    gListenerPos[1] = mListenerElevation;
    gListenerPos[2] = -point->y + mCenterOffset;                // top view only in this demo!
 
    alListenerfv(AL_POSITION, gListenerPos);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setListenerElevation: (float)elevation
{
    mListenerElevation = elevation;
    
    gListenerPos[1] = mListenerElevation;
    // do not change x or z 
    
    alListenerfv(AL_POSITION, gListenerPos);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setListenerPositionX: (float)inX
{
    gListenerPos[0] = inX;
    alListenerfv(AL_POSITION, gListenerPos);
    [self drawListener];
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void)setListenerPositionZ: (float)inX
{
    gListenerPos[2] = inX;
    alListenerfv(AL_POSITION, gListenerPos);
    [self drawListener];
}
 
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourcePlayState:(int)inTag :(int)inCheckBoxValue
{
    if (mSourceOn[inTag] == inCheckBoxValue)
        return;
    
    mSourceOn[inTag] = inCheckBoxValue;
    
    if (mSourceOn[inTag])
        alSourcePlay(gSource[inTag]);
    else
        alSourceStop(gSource[inTag]);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  Pitch
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourcePitch:(int)inTag :(float)inPitch
{
    alSourcef(gSource[inTag], AL_PITCH, inPitch);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Gain
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceGain:(int)inTag :(float)inGain
{
    alSourcef(gSource[inTag], AL_GAIN, inGain);
    // alSourcef (gSource[inTag], AL_SEC_OFFSET, 1.0); // quick way to test the set offset API until controls can be added to UI
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Rolloff
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceRolloffFactor:(int)inTag :(float)inRolloff
{
    alSourcef(gSource[inTag], AL_ROLLOFF_FACTOR, inRolloff);
}
 
- (float) getSourceRolloffFactor:(int)inTag
{
    float   ro;
    alGetSourcef(gSource[inTag], AL_ROLLOFF_FACTOR, &ro);
    return ro;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Reference Distance
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceReferenceDistance:(int)inTag :(float)inReferenceDistance
{
    alSourcef(gSource[inTag], AL_REFERENCE_DISTANCE, inReferenceDistance);
}
 
- (float) getSourceReferenceDistance:(int)inTag
{
    float   rd;
    alGetSourcef(gSource[inTag], AL_REFERENCE_DISTANCE, &rd);
    return rd;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Max Distance
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceMaxDistance:(int)inTag :(float)inMaxDistance
{
    alSourcef(gSource[inTag], AL_MAX_DISTANCE, inMaxDistance);
}
 
- (float) getSourceMaxDistance:(int)inTag
{
    float   md;
    alGetSourcef(gSource[inTag], AL_MAX_DISTANCE, &md);
    return md;
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Direction & Velocity
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceVelocity:(int)inTag :(float) inVelocity
{
    mSourceVelocityScaler[inTag] = inVelocity;
 
    float   velocities[3];
    velocities[1] = 0;  // No Change to the Y vector
    [self getSourceVelocities: inTag : &velocities[0] : &velocities[2]];
    
    alSourcefv(gSource[inTag], AL_VELOCITY, velocities);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceDirection:(int)inTag
{
    float   directions[3];
    directions[1] = 0;      // No Change to the Y vector
    
    if (gSourceDirectionOnOff[inTag] == false)
    {
        directions[0] = 0;
        directions[2] = 0;
        alSourcefv(gSource[inTag], AL_DIRECTION, directions);
        
        alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, 360.0);
        alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, 360.0);
        alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, 0.0);
    }
    else
    {
        [self getSourceDirections: inTag : &directions[0] : &directions[2]];
        
        alSourcefv(gSource[inTag], AL_DIRECTION, directions);
        alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, 90   );
        alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, 180);
        alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, mSourceOuterConeGain[inTag]   );
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceOuterConeGain:(int)inTag :(float) inGain
{
    mSourceOuterConeGain[inTag] = inGain;
    
    alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, mSourceOuterConeGain[inTag]);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceInnerConeAngle:(int)inTag :(float) inAngle
{
    mSourceInnerConeAngle[inTag] = inAngle;
    
    alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, mSourceInnerConeAngle[inTag]);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceOuterConeAngle:(int)inTag :(float) inAngle
{
    mSourceOuterConeAngle[inTag] = inAngle;
    
    alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, mSourceOuterConeAngle[inTag]);
    [self drawSourceWithDirection :inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceDirectionOnOff:(int)inTag :(int)inCheckBoxValue
{
    if (gSourceDirectionOnOff[inTag] == inCheckBoxValue)
        return;
    
    gSourceDirectionOnOff[inTag] = inCheckBoxValue;
    [self setSourceDirection: inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceAngle:(int)inTag :(float)inAngle
{
    gSourceAngle[inTag] = inAngle;
 
    [self setSourceVelocity: inTag : mSourceVelocityScaler[inTag]];
    [self setSourceDirection: inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) getSourceVelocities:(int)inTag : (float*) outX : (float*) outZ
{
    float   rads = DEG2RAD(gSourceAngle[inTag]);
                                     
    if (outX) *outX = sin(rads) * mSourceVelocityScaler[inTag];
    if (outZ) *outZ = -cos(rads) * mSourceVelocityScaler[inTag];
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) getSourceDirections:(int)inTag : (float*) outX : (float*) outZ
{
    float   rads = DEG2RAD(gSourceAngle[inTag]);
                                     
    if (outX) *outX = sin(rads);        
    if (outZ) *outZ = -cos(rads);
}
 
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Listener Gain
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setListenerGain:(float)inGain
{
    alListenerf(AL_GAIN, inGain);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Render Channels
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setRenderChannels:(int)inCheckBoxValue
{
    // Global Setting:
    // Used to Force OpenAL to render to stereo, even if the user's default audio hw is multichannel
 
    UInt32      setting = (inCheckBoxValue == 0) ? alcGetEnumValue(NULL, "ALC_RENDER_CHANNEL_COUNT_MULTICHANNEL") : alcGetEnumValue(NULL, "ALC_RENDER_CHANNEL_COUNT_STEREO");
    
    alMacOSXRenderChannelCountProc((const ALint) setting);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Render Quality
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setRenderQuality:(int)inCheckBoxValue
{
    // Global Setting:
    // Used to turn on HRTF Rendering when OpenAL is rendering to stereo
    
    UInt32      setting = (inCheckBoxValue == 0) ? alcGetEnumValue(NULL, "ALC_SPATIAL_RENDERING_QUALITY_LOW") : alcGetEnumValue(NULL, "ALC_SPATIAL_RENDERING_QUALITY_HIGH");
    
    alcMacOSXRenderingQualityProc((const ALint) setting);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Reverb Level
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceReverb:(int)inTag :(float)inReverbSendLevel
{
    ALfloat     level = inReverbSendLevel;
    alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_SEND_LEVEL"), gSource[inTag], &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Reverb Level
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceOcclusion:(int)inTag :(float)inLevel
{
    ALfloat     level = inLevel;
    alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_OCCLUSION"), gSource[inTag], &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source Reverb Level
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSourceObstruction:(int)inTag :(float)inReverbSendLevel
{
    ALfloat     level = inReverbSendLevel;
    alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_OBSTRUCTION"), gSource[inTag], &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Global Reverb Level
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setGlobalReverb :(float)inReverbLevel
{
    ALfloat     level = inReverbLevel;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_GLOBAL_LEVEL"), &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Reverb ON
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbOn:(int)inCheckBoxValue
{
    UInt32      setting = (inCheckBoxValue == 0) ? 0 : 1;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_ON"), &setting, sizeof(setting));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbEQGain:(float)inLevel
{
    ALfloat     level = inLevel;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_GAIN"), &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbEQBandwidth:(float)inLevel
{
    ALfloat     level = inLevel;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_BANDWITH"), (ALvoid *) &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbEQFrequency:(float)inLevel
{
    ALfloat     level = inLevel;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_FREQ"), &level, sizeof(level));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbRoomType:(int)inTag controlIndex:(int) inIndex title:(NSString*) inTitle
{
    UInt32      roomtype = inTag;
    UInt32      roomIndex = inIndex;
    if (roomIndex < 12)
    {
        // the 1st 12 menu items have the proper reverb constant in the tag value
        alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_ROOM_TYPE"), &roomtype, sizeof(roomtype));
    }
    else
    {
        const char *fullPathToFile;
        fullPathToFile =[[[NSBundle mainBundle] pathForResource:inTitle ofType:@"aupreset" inDirectory:@"ReverbPresets"]UTF8String];
 
        alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_PRESET"), (void *) fullPathToFile, strlen(fullPathToFile));
    }
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setReverbQuality:(int)inTag
{
    UInt32      quality = inTag;
    alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_QUALITY"), &quality, sizeof(quality));
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Distance Model
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setDistanceModel:(int)inTag
{
    alDistanceModel(inTag); 
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Doppler Factor
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setDopplerFactor :(float)inValue
{
    alDopplerFactor(inValue);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Speed Of Sound
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) setSpeedOfSound :(float)inValue
{
    alSpeedOfSound(inValue);
}
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CAPTURE
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (void) captureSamples :(int*)outValue
{
    if (!gCaptureData)
    {
        gCaptureData = (UInt8*) calloc(1, kCaptureSamples * 2); // 1 second of 44k mono 16 bit data
    }
    
    alGetError(); // reset
 
    alcGetIntegerv( gCaptureDevice, ALC_CAPTURE_SAMPLES, 1, outValue );
 
    // get some new sample, free gCaptureData if this fails
    alcCaptureSamplesProc( gCaptureDevice, gCaptureData, *outValue );
 
    UInt32  err = alGetError();
    if (err)
        return;
 
    alSourceStop(gSource[4]);
    alSourcei(gSource[4], AL_BUFFER, AL_NONE);
    
    ALint   count = 1;
    while (count > 0)
        alGetSourcei(gSource[4], AL_BUFFERS_QUEUED, &count);
 
    alBufferData(gBuffer[4], AL_FORMAT_MONO16, gCaptureData, *outValue * 2, kCapturedAudioSampleRate);
    alSourcei(gSource[4], AL_BUFFER, gBuffer[4]);
    alSourcePlay(gSource[4]);
}
 
@end

后记

未完,待续~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容