/*	Copyright © 2007 Apple Inc. All Rights Reserved.
	
	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.
*/
#import "Controller.h"

@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: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]];

		[mCaptureSourceInnerConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", 90.0]];
		[mCaptureSourceOuterConeAngle setStringValue: [NSString stringWithFormat: @"%.2f", 180.0]];
		[mCaptureSourceOuterConeGain setStringValue: [NSString stringWithFormat: @"%.2f", 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:[NSString stringWithCString:"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, bd, freq;
	UInt32	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
