1/**********************************************************************************************************************************
2*
3*   OpenAL cross platform audio library
4*	Copyright (c) 2004, Apple Computer, Inc., Copyright (c) 2012, Apple Inc. All rights reserved.
5*
6*   Redistribution and use in source and binary forms, with or without modification, are permitted provided
7*   that the following conditions are met:
8*
9*   1.  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10*   2.  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
11*       disclaimer in the documentation and/or other materials provided with the distribution.
12*   3.  Neither the name of Apple Inc. ("Apple") nor the names of its contributors may be used to endorse or promote
13*       products derived from this software without specific prior written permission.
14*
15*   THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
17*   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18*   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
20*   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21*
22**********************************************************************************************************************************/
23
24/*
25	Each OALSource object maintains a BufferQueue and an ACMap. The buffer queue is an ordered list of BufferInfo structs.
26	These structs contain an OAL buffer and other pertinent data. The ACMap is a multimap of ACInfo structs. These structs each contain an
27	AudioConverter and the input format of the AudioConverter. The AudioConverters are created as needed each time a buffer with a new
28    format is added to the queue. This allows differently formatted data to be queued seemlessly. The correct AC is used for each
29    buffer as the BufferInfo keeps track of the appropriate AC to use.
30*/
31
32#include "oalSource.h"
33#include "oalBuffer.h"
34#include "oalImp.h"
35
36#define		LOG_PLAYBACK				0
37#define		LOG_VERBOSE					0
38#define		LOG_BUFFER_QUEUEING			0
39#define		LOG_DOPPLER                 0
40#define		LOG_MESSAGE_QUEUE           0
41
42#define		CALCULATE_POSITION	1	// this should be true except for testing
43
44// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45#define MIXER_PARAMS_UNDEFINED 0
46
47#if MIXER_PARAMS_UNDEFINED
48typedef struct MixerDistanceParams {
49			Float32		mReferenceDistance;
50			Float32		mMaxDistance;
51			Float32		mMaxAttenuation;
52} MixerDistanceParams;
53
54enum {
55	kAudioUnitProperty_3DMixerDistanceParams   = 3010
56};
57#endif
58
59inline bool zapBadness(Float32&		inValue)
60{
61	Float32		absInValue = fabs(inValue);
62
63	if (!(absInValue > 1e-15 && absInValue < 1e15)){
64		// inValue was one of the following: 0.0, infinity, denormal or NaN
65		inValue = 0.0;
66		return true;
67	}
68
69	return false;
70}
71
72// if dopplerShift = inifinity then peg to 16 (4 octaves up)
73// if dopplershift is a denormal then peg to .125 (3 octaves down)
74// if nan, then set to 1.0 (no doppler)
75// if 0.0 then set to 1.0 which is no shift
76inline bool zapBadnessForDopplerShift(Float32&		inValue)
77{
78	Float32		absInValue = fabs(inValue);
79
80	if (isnan(inValue) || (inValue == 0.0))
81		inValue = 1.0;
82	else if (absInValue > 1e15)
83		inValue = 16.0;
84	else if (absInValue < 1e-15)
85		inValue = .125;
86
87	return false;
88}
89
90// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92// OALSource
93// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95
96// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97#pragma mark ***** PUBLIC *****
98// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99OALSource::OALSource (ALuint 	 	inSelfToken, OALContext	*inOwningContext)
100	: 	mSelfToken (inSelfToken),
101		mSafeForDeletion(false),
102		mOwningContext(inOwningContext),
103		mIsSuspended(false),
104		mCalculateDistance(true),
105		mResetBusFormat(true),
106        mResetBus(false),
107        mResetPitch(true),
108		mBufferQueueActive(NULL),
109		mBufferQueueInactive(NULL),
110        mBufferQueueTemp(NULL),
111        mQueueLength(0),
112        mTempQueueLength(0),
113		mBuffersQueuedForClear(0),
114		mCurrentBufferIndex(0),
115		mQueueIsProcessed(true),
116		mInUseFlag(0),
117		mSourceLock("OAL:SourceLock"),
118		mCurrentPlayBus (kSourceNeedsBus),
119		mACMap(NULL),
120		mOutputSilence(false),
121		mLooping(AL_FALSE),
122		mSourceRelative(AL_FALSE),
123		mSourceType(AL_UNDETERMINED),
124		mConeInnerAngle(360.0),
125		mConeOuterAngle(360.0),
126		mConeOuterGain(0.0),
127		mConeGainScaler(1.0),
128		mAttenuationGainScaler(1.0),
129        mReadIndex(0.0),
130        mTempSourceStorageBufferSize(2048),             // only used if preferred mixer is unavailable
131		mState(AL_INITIAL),
132		mGain(1.0),
133		mPitch(1.0),                                    // this is the user pitch setting changed via the OAL APIs
134        mDopplerScaler(1.0),
135		mRollOffFactor(kDefaultRolloff),
136		mReferenceDistance(kDefaultReferenceDistance),
137		mMaxDistance(kDefaultMaximumDistance),          // ***** should be MAX_FLOAT
138		mMinGain(0.0),
139		mMaxGain(1.0),
140		mRampState(kNoRamping),
141		mBufferCountToUnqueueInPostRender(0),
142		mTransitioningToFlushQ(false),
143		mASAReverbSendLevel(0.0),
144		mASAOcclusion(0.0),
145		mASAObstruction(0.0),
146        mRenderQuality(ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_LOW),
147		mRogerBeepNode(0),
148		mRogerBeepAU(0),
149		mASARogerBeepEnable(false),
150		mASARogerBeepOn(true),								// RogerBeep AU does not bypass by default
151		mASARogerBeepGain(0.0),
152		mASARogerBeepSensitivity(0),
153		mASARogerBeepType(0),
154		mASARogerBeepPreset(0),
155		mDistortionNode(0),
156		mDistortionAU(0),
157		mASADistortionEnable(false),
158		mASADistortionOn(true),							// Distortion AU does not bypass by default
159		mASADistortionMix(0.0),
160		mASADistortionType(0),
161		mASADistortionPreset(0),
162		mSourceNotifications(NULL)
163{
164#if LOG_VERBOSE
165	DebugMessageN1("OALSource::OALSource() - OALSource = %ld", (long int) mSelfToken);
166#endif
167
168    mPosition[0] = 0.0;
169    mPosition[1] = 0.0;
170    mPosition[2] = 0.0;
171
172    mVelocity[0] = 0.0;
173    mVelocity[1] = 0.0;
174    mVelocity[2] = 0.0;
175
176    mConeDirection[0] = 0.0;
177    mConeDirection[1] = 0.0;
178    mConeDirection[2] = 0.0;
179
180    mBufferQueueActive = new BufferQueue();
181	mBufferQueueActive->Reserve(512);
182
183    mBufferQueueInactive = new BufferQueue();
184	mBufferQueueInactive->Reserve(512);
185
186    mBufferQueueTemp = new BufferQueue();
187	mBufferQueueTemp->Reserve(128);
188
189    mACMap = new ACMap();
190
191    mReferenceDistance = mOwningContext->GetDefaultReferenceDistance();
192    mMaxDistance = mOwningContext->GetDefaultMaxDistance();
193
194    mRenderQuality = mOwningContext->GetRenderQuality();
195
196    if (Get3DMixerVersion() < k3DMixerVersion_2_0)
197    {
198        // since the preferred mixer is not available, some temporary storgae will be needed for SRC
199        // for now assume that sources will not have more than 2 channels of data
200        mTempSourceStorage = (AudioBufferList *) malloc ((offsetof(AudioBufferList, mBuffers)) + (2 * sizeof(AudioBuffer)));
201
202		mTempSourceStorage->mBuffers[0].mDataByteSize = mTempSourceStorageBufferSize;
203        mTempSourceStorage->mBuffers[0].mData = malloc(mTempSourceStorageBufferSize);
204
205        mTempSourceStorage->mBuffers[1].mDataByteSize = mTempSourceStorageBufferSize;
206        mTempSourceStorage->mBuffers[1].mData = malloc(mTempSourceStorageBufferSize);
207    }
208	else
209	{
210	   mTempSourceStorage = NULL;
211	}
212}
213
214// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
215OALSource::~OALSource()
216{
217#if LOG_VERBOSE
218	DebugMessageN1("OALSource::~OALSource() - OALSource = %ld", (long int) mSelfToken);
219#endif
220
221    // release the 3DMixer bus if necessary
222	if (mCurrentPlayBus != kSourceNeedsBus)
223	{
224		ReleaseNotifyAndRenderProcs();
225		mOwningContext->SetBusAsAvailable (mCurrentPlayBus);
226		mCurrentPlayBus = kSourceNeedsBus;
227	}
228
229    // empty the two queues
230	FlushBufferQueue();
231
232	// empty the message queue
233	ClearMessageQueue();
234
235	if (mTempSourceStorage)
236		free(mTempSourceStorage);
237
238    delete (mBufferQueueInactive);
239    delete (mBufferQueueActive);
240    delete (mBufferQueueTemp);
241
242	// remove all the AudioConverters that were created for the buffer queue of this source object
243    if (mACMap)
244	{
245		mACMap->RemoveAllConverters();
246		delete (mACMap);
247	}
248
249    if (mSourceNotifications)
250        delete mSourceNotifications;
251}
252
253// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
254// this is only callled by the context when removing a source, which is thread protected already
255void	OALSource::SetUpDeconstruction()
256{
257#if LOG_VERBOSE
258	DebugMessageN1("OALSource::SetUpDeconstruction() - OALSource = %ld", (long int) mSelfToken);
259#endif
260
261	try {
262		// wait if in render, then prevent rendering til completion
263		OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
264
265		// don't allow synchronous source manipulation
266		CAGuard::Locker sourceLock(mSourceLock);
267
268		switch (mState)
269		{
270			// if rendering is occurring right now, then let the PostRender tear things down and set mSafeForDeletion to true
271			// all transition states represent a source that is actually rendering data
272			case AL_PLAYING:
273			case kTransitionToStop:
274			case kTransitionToPlay:
275			case kTransitionToPause:
276			case kTransitionToRewind:
277			case kTransitionToRetrigger:
278			case kTransitionToResume:
279			{
280#if	LOG_MESSAGE_QUEUE
281                DebugMessageN1("OALSource::SetUpDeconstruction  ADDING : kMQ_Stop - OALSource = %ld", (long int) mSelfToken);
282#endif
283				AddPlaybackMessage(kMQ_DeconstructionStop, NULL, 0);
284				break;
285			}
286
287			default:
288				mSafeForDeletion = true;
289				break;
290		}
291
292		SetPlaybackState(kTransitionToStop);
293		mTransitioningToFlushQ = true;
294	}
295	catch (OSStatus	result) {
296		DebugMessageN2("SetUpDeconstruction FAILED source = %d, err = %d\n", (int) mSelfToken, (int)result);
297		throw (result);
298	}
299}
300
301// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
302void	OALSource::Suspend ()
303{
304}
305
306// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
307void	OALSource::Unsuspend ()
308{
309}
310
311// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
312// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
313// SET METHODS
314// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
315// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
316void	OALSource::SetPitch (float	inPitch)
317{
318#if LOG_VERBOSE
319	DebugMessageN2("OALSource::SetPitch() - OALSource:inPitch = %ld:%f", (long int) mSelfToken, inPitch);
320#endif
321	if (inPitch < 0.0f)
322		throw ((OSStatus) AL_INVALID_VALUE);
323
324	// don't allow synchronous source manipulation
325	CAGuard::Locker sourceLock(mSourceLock);
326
327    if ((inPitch == mPitch) && (mResetPitch == false))
328		return;			// nothing to do
329
330	mPitch = inPitch;
331
332     // 1.3 3DMixer does not work properly when doing SRC on a mono bus
333	 if (Get3DMixerVersion() < k3DMixerVersion_2_0)
334        return;
335
336	Float32     newPitch = mPitch * mDopplerScaler;
337    if (mCurrentPlayBus != kSourceNeedsBus)
338	{
339		BufferInfo		*oalBuffer = mBufferQueueActive->Get(mCurrentBufferIndex);
340
341		if (oalBuffer != NULL)
342		{
343#if LOG_GRAPH_AND_MIXER_CHANGES
344    DebugMessageN2("OALSource::SetPitch: k3DMixerParam_PlaybackRate called - OALSource:mPitch = %ld:%f\n", mSelfToken, mPitch );
345#endif
346
347			OSStatus    result = AudioUnitSetParameter (mOwningContext->GetMixerUnit(), k3DMixerParam_PlaybackRate, kAudioUnitScope_Input, mCurrentPlayBus, newPitch, 0);
348            if (result != noErr)
349                DebugMessageN3("OALSource::SetPitch: k3DMixerParam_PlaybackRate called - OALSource = %ld mPitch = %f result = %d\n", (long int) mSelfToken, mPitch, (int)result );
350        }
351
352		mResetPitch = false;
353	}
354	else
355		mResetPitch = true; // the source is not currently connected to a bus, so make this change when play is called
356}
357
358// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
359void	OALSource::SetGain (float	inGain)
360{
361#if LOG_VERBOSE
362	DebugMessageN2("OALSource::SetGain() - OALSource:inGain = %ld:%f", (long int) mSelfToken, inGain);
363#endif
364	if (inGain < 0.0f)
365		throw ((OSStatus) AL_INVALID_VALUE);
366
367	// don't allow synchronous source manipulation
368	CAGuard::Locker sourceLock(mSourceLock);
369
370	if (mGain != inGain)
371	{
372		mGain = inGain;
373		UpdateBusGain();
374	}
375}
376
377// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
378void	OALSource::SetMinGain (Float32	inMinGain)
379{
380#if LOG_VERBOSE
381	DebugMessageN2("OALSource::SetMinGain - OALSource:inMinGain = %ld:%f\n", (long int) mSelfToken, inMinGain);
382#endif
383	if ((inMinGain < 0.0f) || (inMinGain > 1.0f))
384		throw ((OSStatus) AL_INVALID_VALUE);
385
386	// don't allow synchronous source manipulation
387	CAGuard::Locker sourceLock(mSourceLock);
388
389	if (mMinGain != inMinGain)
390	{
391		mMinGain = inMinGain;
392		UpdateMinBusGain();
393	}
394}
395
396// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
397void	OALSource::SetMaxGain (Float32	inMaxGain)
398{
399#if LOG_VERBOSE
400	DebugMessageN2("OALSource::SetMaxGain - OALSource:inMaxGain = %ld:%f\n", (long int) mSelfToken, inMaxGain);
401#endif
402
403	if ((inMaxGain < 0.0f) || (inMaxGain > 1.0f))
404		throw ((OSStatus) AL_INVALID_VALUE);
405
406	// don't allow synchronous source manipulation
407	CAGuard::Locker sourceLock(mSourceLock);
408
409	if (mMaxGain != inMaxGain)
410	{
411		mMaxGain = inMaxGain;
412		UpdateMaxBusGain();
413	}
414}
415
416// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
417Float32		OALSource::GetMaxAttenuation(Float32	inRefDistance, Float32 inMaxDistance, Float32 inRolloff)
418{
419#if LOG_VERBOSE
420	DebugMessageN4("OALSource::GetMaxAttenuation() - OALSource:inRefDistance:inMaxDistance:inRolloff = %ld:%f:%f:%f", (long int) mSelfToken, inRefDistance, inMaxDistance, inRolloff);
421#endif
422	Float32		returnValue = 20 * log10(inRefDistance / (inRefDistance + (inRolloff * (inMaxDistance -  inRefDistance))));
423
424	if (returnValue < 0.0)
425		returnValue *= -1.0;
426	else
427		returnValue = 0.0;   // if db result was positive, clamp it to zero
428
429	return returnValue;
430}
431
432// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433OSStatus	OALSource::SetDistanceParams(bool	inChangeReferenceDistance, bool inChangeMaxDistance)
434{
435#if LOG_VERBOSE
436	DebugMessageN3("OALSource::SetDistanceParams() - OALSource:inChangeReferenceDistance:inChangeMaxDistance = %ld:%d:%d", (long int) mSelfToken, inChangeReferenceDistance, inChangeMaxDistance);
437#endif
438	OSStatus	result = noErr;
439
440	// don't allow synchronous source manipulation
441	CAGuard::Locker sourceLock(mSourceLock);
442
443	if (Get3DMixerVersion() < k3DMixerVersion_2_0)
444	{
445		// the pre-2.0 3DMixer does not accept kAudioUnitProperty_3DMixerDistanceParams, it has do some extra work and use the DistanceAtten property instead
446		mOwningContext->SetDistanceAttenuation(mCurrentPlayBus, mReferenceDistance, mMaxDistance, mRollOffFactor);
447	}
448	else
449	{
450		MixerDistanceParams		distanceParams;
451		UInt32					propSize = sizeof(distanceParams);
452		result = AudioUnitGetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_3DMixerDistanceParams, kAudioUnitScope_Input, mCurrentPlayBus, &distanceParams, &propSize);
453		if (result == noErr)
454		{
455			Float32     rollOff = mRollOffFactor;
456
457			if (mOwningContext->IsDistanceScalingRequired())
458			{
459				// scale the reference distance
460				distanceParams.mReferenceDistance = (mReferenceDistance/mMaxDistance) * kDistanceScalar;
461				// limit the max distance
462				distanceParams.mMaxDistance = kDistanceScalar;
463				// scale the rolloff
464				rollOff *= (kDistanceScalar/mMaxDistance);
465			}
466			else
467			{
468				if (inChangeReferenceDistance)
469					distanceParams.mReferenceDistance = mReferenceDistance;
470				else if (inChangeMaxDistance)
471					distanceParams.mMaxDistance = mMaxDistance;
472			}
473
474			distanceParams.mMaxAttenuation = GetMaxAttenuation(distanceParams.mReferenceDistance, distanceParams.mMaxDistance, rollOff);
475
476			if ((mReferenceDistance == mMaxDistance) && (Get3DMixerVersion() < k3DMixerVersion_2_2))
477				distanceParams.mMaxDistance = distanceParams.mReferenceDistance + .01; // pre 2.2 3DMixer may crash  if max and reference distances are equal
478
479			result = AudioUnitSetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_3DMixerDistanceParams, kAudioUnitScope_Input, mCurrentPlayBus, &distanceParams, sizeof(distanceParams));
480		}
481	}
482
483	return result;
484}
485
486// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
487void	OALSource::SetReferenceDistance (Float32	inReferenceDistance)
488{
489#if LOG_VERBOSE
490	DebugMessageN2("OALSource::SetReferenceDistance - OALSource:inReferenceDistance = %ld:%f\n", (long int) mSelfToken, inReferenceDistance);
491#endif
492
493	if (inReferenceDistance < 0.0f)
494		throw ((OSStatus) AL_INVALID_VALUE);
495
496	// don't allow synchronous source manipulation
497	CAGuard::Locker sourceLock(mSourceLock);
498
499	if (inReferenceDistance == mReferenceDistance)
500		return; // nothing to do
501
502	mReferenceDistance = inReferenceDistance;
503
504	if (!mOwningContext->DoSetDistance())
505		return; // nothing else to do?
506
507    if (mCurrentPlayBus != kSourceNeedsBus)
508    {
509		SetDistanceParams(true, false);
510	}
511}
512
513// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
514void	OALSource::SetMaxDistance (Float32	inMaxDistance)
515{
516#if LOG_VERBOSE
517	DebugMessageN2("OALSource::SetMaxDistance - OALSource:inMaxDistance = %ld:%f\n", (long int) mSelfToken, inMaxDistance);
518#endif
519
520	if (inMaxDistance < 0.0f)
521		throw ((OSStatus) AL_INVALID_VALUE);
522
523	// don't allow synchronous source manipulation
524	CAGuard::Locker sourceLock(mSourceLock);
525
526	if (inMaxDistance == mMaxDistance)
527		return; // nothing to do
528
529	mMaxDistance = inMaxDistance;
530
531	if (!mOwningContext->DoSetDistance())
532		return; // nothing else to do?
533
534    if (mCurrentPlayBus != kSourceNeedsBus)
535    {
536		SetDistanceParams(false, true);
537    }
538}
539
540// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
541void	OALSource::SetRollOffFactor (Float32	inRollOffFactor)
542{
543#if LOG_VERBOSE
544	DebugMessageN2("OALSource::SetRollOffFactor - OALSource:inRollOffFactor = %ld:%f\n", (long int) mSelfToken, inRollOffFactor);
545#endif
546
547	if (inRollOffFactor < 0.0f)
548		throw ((OSStatus) AL_INVALID_VALUE);
549
550	// don't allow synchronous source manipulation
551	CAGuard::Locker sourceLock(mSourceLock);
552
553	if (inRollOffFactor == mRollOffFactor)
554		return; // nothing to do
555
556	mRollOffFactor = inRollOffFactor;
557
558	if (!mOwningContext->DoSetDistance())
559		return; // nothing else to do?
560
561    if (mCurrentPlayBus != kSourceNeedsBus)
562    {
563		SetDistanceParams(false, false);
564    }
565}
566
567// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
568void	OALSource::SetLooping (UInt32	inLooping)
569{
570#if LOG_VERBOSE
571	DebugMessageN2("OALSource::SetLooping called - OALSource:inLooping = %ld:%ld\n", (long int) mSelfToken, (long int) inLooping);
572#endif
573
574	// don't allow synchronous source manipulation
575	CAGuard::Locker sourceLock(mSourceLock);
576
577    mLooping = inLooping;
578}
579
580// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
581void	OALSource::SetPosition (Float32 inX, Float32 inY, Float32 inZ)
582{
583#if LOG_VERBOSE
584	DebugMessageN4("OALSource::SetPosition called - OALSource:X:Y:Z = %ld:%f:%f:%f\n", (long int) mSelfToken, inX, inY, inZ);
585#endif
586
587	if (isnan(inX) || isnan(inY) || isnan(inZ))
588		throw ((OSStatus) AL_INVALID_VALUE);
589
590	// don't allow synchronous source manipulation
591	CAGuard::Locker sourceLock(mSourceLock);
592
593	mPosition[0] = inX;
594	mPosition[1] = inY;
595	mPosition[2] = inZ;
596
597	mCalculateDistance = true;  // change the distance next time the PreRender proc or a new Play() is called
598}
599
600// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
601void	OALSource::SetVelocity (Float32 inX, Float32 inY, Float32 inZ)
602{
603#if LOG_VERBOSE
604	DebugMessageN4("OALSource::SetVelocity called - OALSource:inX:inY:inY = %ld:%f:%f:%f", (long int) mSelfToken, inX, inY, inZ);
605#endif
606
607	// don't allow synchronous source manipulation
608	CAGuard::Locker sourceLock(mSourceLock);
609
610	mVelocity[0] = inX;
611	mVelocity[1] = inY;
612	mVelocity[2] = inZ;
613
614	mCalculateDistance = true;  // change the velocity next time the PreRender proc or a new Play() is called
615}
616
617// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
618void	OALSource::SetDirection (Float32 inX, Float32 inY, Float32 inZ)
619{
620#if LOG_VERBOSE
621	DebugMessageN4("OALSource::SetDirection called - OALSource:inX:inY:inY = %ld:%f:%f:%f", (long int) mSelfToken, inX, inY, inZ);
622#endif
623
624	// don't allow synchronous source manipulation
625	CAGuard::Locker sourceLock(mSourceLock);
626
627	mConeDirection[0] = inX;
628	mConeDirection[1] = inY;
629	mConeDirection[2] = inZ;
630
631	mCalculateDistance = true;  // change the direction next time the PreRender proc or a new Play() is called
632}
633
634// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
635void	OALSource::SetSourceRelative (UInt32	inSourceRelative)
636{
637#if LOG_VERBOSE
638	DebugMessageN2("OALSource::SetSourceRelative called - OALSource:inSourceRelative = %ld:%ld", (long int) mSelfToken, (long int) inSourceRelative);
639#endif
640
641	if ((inSourceRelative != AL_FALSE) && (inSourceRelative != AL_TRUE))
642		throw ((OSStatus) AL_INVALID_VALUE);
643
644	// don't allow synchronous source manipulation
645	CAGuard::Locker sourceLock(mSourceLock);
646
647	mSourceRelative = inSourceRelative;
648	mCalculateDistance = true;  // change the source relative next time the PreRender proc or a new Play() is called
649}
650
651// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
652void	OALSource::SetChannelParameters ()
653{
654#if LOG_VERBOSE
655	DebugMessageN1("OALSource::SetChannelParameters called - OALSource = %ld\n", (long int) mSelfToken);
656#endif
657
658	SetReferenceDistance(mReferenceDistance);
659	SetMaxDistance(mMaxDistance);
660	SetRollOffFactor(mRollOffFactor);
661
662	mCalculateDistance = true;
663}
664
665// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666void	OALSource::SetConeInnerAngle (Float32	inConeInnerAngle)
667{
668#if LOG_VERBOSE
669	DebugMessageN2("OALSource::SetConeInnerAngle called - OALSource:inConeInnerAngle = %ld:%f\n", (long int) mSelfToken, inConeInnerAngle);
670#endif
671
672	// don't allow synchronous source manipulation
673	CAGuard::Locker sourceLock(mSourceLock);
674
675    if (mConeInnerAngle != inConeInnerAngle)
676	{
677		mConeInnerAngle = inConeInnerAngle;
678		mCalculateDistance = true;
679	}
680}
681
682// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
683void	OALSource::SetConeOuterAngle (Float32	inConeOuterAngle)
684{
685#if LOG_VERBOSE
686	DebugMessageN2("OALSource::SetConeOuterAngle called - OALSource:inConeOuterAngle = %ld:%f\n", (long int) mSelfToken, inConeOuterAngle);
687#endif
688
689	// don't allow synchronous source manipulation
690	CAGuard::Locker sourceLock(mSourceLock);
691
692    if (mConeOuterAngle != inConeOuterAngle)
693	{
694		mConeOuterAngle = inConeOuterAngle;
695		mCalculateDistance = true;
696	}
697}
698
699// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700void	OALSource::SetConeOuterGain (Float32	inConeOuterGain)
701{
702#if LOG_VERBOSE
703	DebugMessageN2("OALSource::SetConeOuterGain called - OALSource:inConeOuterGain = %ld:%f\n", (long int) mSelfToken, inConeOuterGain);
704#endif
705	if (inConeOuterGain < 0.0f)
706		throw ((OSStatus) AL_INVALID_VALUE);
707
708	if (inConeOuterGain <= 1.0)
709	{
710		// don't allow synchronous source manipulation
711		CAGuard::Locker sourceLock(mSourceLock);
712
713		if (mConeOuterGain != inConeOuterGain)
714		{
715			mConeOuterGain = inConeOuterGain;
716			mCalculateDistance = true;
717		}
718	}
719}
720
721// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
722// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
723// GET METHODS
724// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
725// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
726Float32	OALSource::GetPitch ()
727{
728#if LOG_VERBOSE
729	DebugMessageN1("OALSource::GetPitch called - OALSource = %ld\n", (long int) mSelfToken);
730#endif
731    return mPitch;
732}
733
734// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
735Float32	OALSource::GetDopplerScaler ()
736{
737#if LOG_VERBOSE
738	DebugMessageN1("OALSource::GetDopplerScaler called - OALSource = %ld\n", (long int) mSelfToken);
739#endif
740    return mDopplerScaler;
741}
742
743// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
744Float32	OALSource::GetGain ()
745{
746#if LOG_VERBOSE
747	DebugMessageN1("OALSource::GetGain called - OALSource = %ld\n", (long int) mSelfToken);
748#endif
749    return mGain;
750}
751
752// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
753Float32	OALSource::GetMinGain ()
754{
755#if LOG_VERBOSE
756	DebugMessageN1("OALSource::GetMinGain called - OALSource = %ld\n", (long int) mSelfToken);
757#endif
758    return mMinGain;
759}
760
761// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
762Float32	OALSource::GetMaxGain ()
763{
764#if LOG_VERBOSE
765	DebugMessageN1("OALSource::GetMaxGain called - OALSource = %ld\n", (long int) mSelfToken);
766#endif
767    return mMaxGain;
768}
769
770// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
771Float32	OALSource::GetReferenceDistance ()
772{
773#if LOG_VERBOSE
774	DebugMessageN1("OALSource::GetReferenceDistance called - OALSource = %ld\n", (long int) mSelfToken);
775#endif
776    return mReferenceDistance;
777}
778
779// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
780Float32	OALSource::GetMaxDistance ()
781{
782#if LOG_VERBOSE
783	DebugMessageN1("OALSource::GetMaxDistance called - OALSource = %ld\n", (long int) mSelfToken);
784#endif
785    return mMaxDistance;
786}
787
788// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
789Float32	OALSource::GetRollOffFactor ()
790{
791#if LOG_VERBOSE
792	DebugMessageN1("OALSource::GetRollOffFactor called - OALSource = %ld\n", (long int) mSelfToken);
793#endif
794    return mRollOffFactor;
795}
796
797// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
798UInt32	OALSource::GetLooping ()
799{
800#if LOG_VERBOSE
801	DebugMessageN1("OALSource::GetLooping called - OALSource = %ld\n", (long int) mSelfToken);
802#endif
803    return mLooping;
804}
805
806// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
807void	OALSource::GetPosition (Float32 &inX, Float32 &inY, Float32 &inZ)
808{
809#if LOG_VERBOSE
810	DebugMessageN1("OALSource::GetPosition called - OALSource = %ld\n", (long int) mSelfToken);
811#endif
812
813	inX = mPosition[0];
814	inY = mPosition[1];
815	inZ = mPosition[2];
816}
817
818// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
819void	OALSource::GetVelocity (Float32 &inX, Float32 &inY, Float32 &inZ)
820{
821#if LOG_VERBOSE
822	DebugMessageN1("OALSource::GetVelocity called - OALSource = %ld\n", (long int) mSelfToken);
823#endif
824
825	inX = mVelocity[0];
826	inY = mVelocity[1];
827	inZ = mVelocity[2];
828}
829
830// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
831void	OALSource::GetDirection (Float32 &inX, Float32 &inY, Float32 &inZ)
832{
833#if LOG_VERBOSE
834	DebugMessageN1("OALSource::GetDirection called - OALSource = %ld\n", (long int) mSelfToken);
835#endif
836
837	inX = mConeDirection[0];
838	inY = mConeDirection[1];
839	inZ = mConeDirection[2];
840}
841
842// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
843UInt32	OALSource::GetSourceRelative ()
844{
845#if LOG_VERBOSE
846	DebugMessageN1("OALSource::GetSourceRelative called - OALSource = %ld\n", (long int) mSelfToken);
847#endif
848    return mSourceRelative;
849}
850
851// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
852UInt32	OALSource::GetSourceType ()
853{
854#if LOG_VERBOSE
855	DebugMessageN1("OALSource::GetSourceType called - OALSource = %ld\n", (long int) mSelfToken);
856#endif
857    return mSourceType;
858}
859
860// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
861Float32	OALSource::GetConeInnerAngle ()
862{
863#if LOG_VERBOSE
864	DebugMessageN1("OALSource::GetConeInnerAngle called - OALSource = %ld\n", (long int) mSelfToken);
865#endif
866    return mConeInnerAngle;
867}
868
869// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
870Float32	OALSource::GetConeOuterAngle ()
871{
872#if LOG_VERBOSE
873	DebugMessageN1("OALSource::GetConeOuterAngle called - OALSource = %ld\n", (long int) mSelfToken);
874#endif
875    return mConeOuterAngle;
876}
877
878// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
879Float32	OALSource::GetConeOuterGain ()
880{
881#if LOG_VERBOSE
882	DebugMessageN1("OALSource::GetConeOuterGain called - OALSource = %ld\n", (long int) mSelfToken);
883#endif
884    return mConeOuterGain;
885}
886
887// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
888UInt32	OALSource::GetState()
889{
890#if LOG_VERBOSE
891	DebugMessageN1("OALSource::GetState called - OALSource = %ld\n", (long int) mSelfToken);
892#endif
893    // if the source is in any of the transition states, return its immediate future state
894	// else return its actual state
895	switch(mState)
896	{
897		case kTransitionToPlay:
898		case kTransitionToRetrigger:
899		case kTransitionToResume:
900			return AL_PLAYING;
901			break;
902
903		case kTransitionToStop:
904			return AL_STOPPED;
905			break;
906
907		case kTransitionToPause:
908			return AL_PAUSED;
909			break;
910
911		case kTransitionToRewind:
912			return AL_INITIAL;
913			break;
914
915		default:
916			break;
917	}
918
919	return mState;
920}
921// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
922ALuint	OALSource::GetToken()
923{
924#if LOG_VERBOSE
925	DebugMessageN1("OALSource::GetToken called - OALSource = %ld\n", (long int) mSelfToken);
926#endif
927    return mSelfToken;
928}
929
930// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
931// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
932// BUFFER QUEUE METHODS
933// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
934// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
935UInt32	OALSource::GetQLengthPriv()
936{
937#if LOG_VERBOSE
938	DebugMessageN1("OALSource::GetQLengthPriv() called - OALSource = %ld", (long int) mSelfToken);
939#endif
940
941    // the Q length is the size of the inactive & active lists
942    return mQueueLength;
943}
944
945// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
946
947UInt32	OALSource::GetQLength()
948{
949#if LOG_VERBOSE
950	DebugMessageN1("OALSource::GetQLength() called OALSource = %ld", (long int) mSelfToken);
951#endif
952
953	if(IsSourceTransitioningToFlushQ())
954        return mTempQueueLength;
955
956    // the Q length is the size of the inactive & active lists
957    return mQueueLength;
958}
959
960// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
961UInt32	OALSource::GetBuffersProcessed()
962{
963#if LOG_VERBOSE
964	DebugMessageN1("OALSource::GetBuffersProcessed called - OALSource = %ld\n", (long int) mSelfToken);
965#endif
966	if (mState == AL_INITIAL)
967        return 0;
968
969    if(IsSourceTransitioningToFlushQ())
970        return 0;
971
972	if ((mState == AL_INITIAL) 			||
973		(mState == AL_STOPPED) 			||
974		(mState == kTransitionToStop) 	||
975		(mState == kTransitionToRewind) )
976		return GetQLength();
977
978	if (mQueueIsProcessed)
979	{
980		// fixes 4085888
981		// When the Q ran dry it might not have been possible to modify the Buffer Q Lists
982		// This means that there could be one left over buffer in the active Q list which should not be there
983
984        // wait if in render, then prevent rendering til completion
985        OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
986
987        // don't allow synchronous source manipulation
988        CAGuard::Locker sourceLock(mSourceLock);
989
990		ClearActiveQueue();
991	}
992
993	return mBufferQueueInactive->GetQueueSize();
994}
995
996// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
997void	OALSource::SetBuffer (ALuint inBufferToken, OALBuffer	*inBuffer)
998{
999#if LOG_VERBOSE
1000	DebugMessageN3("OALSource::SetBuffer called - OALSource:inBufferToken:inBuffer = %ld:%ld:%p\n", (long int) mSelfToken, (long int) inBufferToken, inBuffer);
1001#endif
1002	if (inBuffer == NULL)
1003		return;	// invalid case
1004
1005	// wait if in render, then prevent rendering til completion
1006	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1007
1008	// don't allow synchronous source manipulation
1009	CAGuard::Locker sourceLock(mSourceLock);
1010
1011	switch (mState)
1012	{
1013		case AL_PLAYING:
1014		case AL_PAUSED:
1015		case kTransitionToPlay:
1016		case kTransitionToRetrigger:
1017		case kTransitionToResume:
1018		case kTransitionToPause:
1019            throw (OSStatus)AL_INVALID_OPERATION;
1020			break;
1021
1022		case kTransitionToStop:
1023		case kTransitionToRewind:
1024		{
1025            if (inBufferToken == 0)
1026			{
1027				mSourceType = AL_UNDETERMINED;
1028				mTransitioningToFlushQ = true;
1029                mTempQueueLength = 0;   //reset the temp queue length
1030                FlushTempBufferQueue();
1031			}
1032
1033#if	LOG_MESSAGE_QUEUE
1034			DebugMessageN1("OALSource::SetBuffer - kMQ_SetBuffer added to MQ - OALSource = %ld", (long int) mSelfToken);
1035#endif
1036            inBuffer->SetIsInPostRenderMessageQueue(true);
1037			AddPlaybackMessage(kMQ_SetBuffer, inBuffer, 0);
1038			break;
1039		}
1040
1041		default:
1042		{
1043            // In the initial or stopped state it is ok to flush the buffer Qs and add this new buffer right now, so empty the two queues
1044			FlushBufferQueue();
1045
1046			// if inBufferToken == 0, do nothing, passing NONE to this method is legal and should merely empty the queue
1047			if (inBufferToken != 0)
1048			{
1049				AppendBufferToQueue(inBufferToken, inBuffer);
1050				mSourceType = AL_STATIC;
1051			}
1052			else
1053				mSourceType = AL_UNDETERMINED;
1054		}
1055	}
1056}
1057
1058// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1059// this should only be called when the source is render and edit protected
1060void	OALSource::FlushBufferQueue()
1061{
1062#if LOG_VERBOSE
1063	DebugMessageN1("OALSource::FlushBufferQueue called - OALSource = %ld\n", (long int) mSelfToken);
1064#endif
1065	UInt32	count = mBufferQueueInactive->GetQueueSize();
1066	for (UInt32	i = 0; i < count; i++)
1067	{
1068		mBufferQueueInactive->RemoveQueueEntryByIndex(this, 0, true);
1069		mBuffersQueuedForClear = 0;
1070	}
1071
1072	count = mBufferQueueActive->GetQueueSize();
1073	for (UInt32	i = 0; i < count; i++)
1074	{
1075		mBufferQueueActive->RemoveQueueEntryByIndex(this, 0, true);
1076	}
1077
1078    //now that both queues have been modified, the queue length can be set
1079    SetQueueLength();
1080}
1081
1082// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1083void	OALSource::FlushTempBufferQueue()
1084{
1085#if LOG_VERBOSE
1086	DebugMessageN1("OALSource::FlushTempBufferQueue() - OALSource = %ld", (long int) mSelfToken);
1087#endif
1088
1089	UInt32	count = mBufferQueueTemp->GetQueueSize();
1090	for (UInt32	i = 0; i < count; i++)
1091		mBufferQueueInactive->RemoveQueueEntryByIndex(this, 0, false);
1092}
1093
1094// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1095ALuint	OALSource::GetBuffer()
1096{
1097#if LOG_VERBOSE
1098	DebugMessageN2("OALSource::GetBuffer called - OALSource:currentBuffer = %ld:%ld\n", (long int)mSelfToken, (long int)mBufferQueueActive->GetBufferTokenByIndex(mCurrentBufferIndex));
1099#endif
1100	// wait if in render, then prevent rendering til completion
1101	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1102
1103	// need to make sure no other thread touches the active queue
1104	CAGuard::Locker sourceLock(mSourceLock);
1105
1106	// it isn't clear what this should return if there is a buffer queue (AL_STREAMING),
1107	// so only return a value when in AL_STATIC mode
1108	ALuint	bufferID = 0;
1109	if (mSourceType == AL_STATIC)
1110	{
1111		if (mBufferQueueActive->GetQueueSize() > 0)
1112			bufferID = mBufferQueueActive->GetBufferTokenByIndex(0);
1113		else if (mBufferQueueInactive->GetQueueSize() > 0)
1114			bufferID = mBufferQueueInactive->GetBufferTokenByIndex(0);
1115	}
1116
1117	return bufferID;
1118}
1119
1120// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1121// public method
1122void	OALSource::AddToQueue(ALuint	inBufferToken, OALBuffer	*inBuffer)
1123{
1124#if LOG_VERBOSE
1125	DebugMessageN3("OALSource::AddToQueue called - OALSource:inBufferToken:inBuffer = %ld:%ld:%p\n", (long int) mSelfToken, (long int) inBufferToken, inBuffer);
1126#endif
1127	// wait if in render, then prevent rendering til completion
1128	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1129
1130	// don't allow synchronous source manipulation
1131	CAGuard::Locker sourceLock(mSourceLock);
1132
1133	if (mSourceType == AL_STATIC)
1134		throw (OSStatus)AL_INVALID_OPERATION;
1135
1136	if (mSourceType == AL_UNDETERMINED)
1137		mSourceType = AL_STREAMING;
1138
1139	AppendBufferToQueue(inBufferToken, inBuffer);
1140}
1141
1142// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1143void	OALSource::AddToTempQueue(ALuint	inBufferToken, OALBuffer	*inBuffer)
1144{
1145#if LOG_VERBOSE
1146	DebugMessageN3("OALSource::AddToQueue called - OALSource:inBufferToken:inBuffer = %ld:%ld:%p\n", (long int) mSelfToken, (long int) inBufferToken, inBuffer);
1147#endif
1148	// wait if in render, then prevent rendering til completion
1149	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1150
1151	// don't allow synchronous source manipulation
1152	CAGuard::Locker sourceLock(mSourceLock);
1153
1154    mBufferQueueTemp->AppendBuffer(this, inBufferToken, inBuffer, 0);
1155    //Protect the buffer so it can't be deleted. This lock is released when the buffer is handed off to the active queue
1156    inBuffer->UseThisBuffer(this);
1157    ++mTempQueueLength;
1158	AddPlaybackMessage(kMQ_AddBuffersToQueue, NULL, 1);
1159}
1160
1161// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1162// this should only be called when the source is render and edit protected
1163void	OALSource::AppendBufferToQueue(ALuint	inBufferToken, OALBuffer	*inBuffer)
1164{
1165#if LOG_VERBOSE
1166	DebugMessageN3("OALSource::AppendBufferToQueue called (START) - OALSource:inBufferToken:inBuffer = %ld:%ld:%p", (long int)mSelfToken, (long int)inBufferToken, inBuffer);
1167#endif
1168	OSStatus	result = noErr;
1169#if LOG_BUFFER_QUEUEING
1170	DebugMessageN2("OALSource::AppendBufferToQueue called (START) - OALSource:inBufferToken = %ld:%ld", (long int)mSelfToken, (long int)inBufferToken);
1171#endif
1172
1173	try {
1174		if (mBufferQueueActive->Empty())
1175		{
1176			mCurrentBufferIndex = 0;	// this is the first buffer in the queue
1177			mQueueIsProcessed = false;
1178		}
1179
1180		// do we need an AC for the format of this buffer?
1181		if (inBuffer->HasBeenConverted())
1182		{
1183			// the data was already convertered to the mixer format, no AC is necessary (as indicated by the ACToken setting of zero)
1184			mBufferQueueActive->AppendBuffer(this, inBufferToken, inBuffer, 0);
1185            SetQueueLength();
1186		}
1187		else
1188		{
1189			// check the format against the real format of the data, NOT the input format of the converter which may be subtly different
1190			// both in SampleRate and Interleaved flags
1191			ALuint		outToken = 0;
1192			mACMap->GetACForFormat(inBuffer->GetFormat(), outToken);
1193			if (outToken == 0)
1194			{
1195				// create an AudioConverter for this format because there isn't one yet
1196				AudioConverterRef				converter = 0;
1197				CAStreamBasicDescription		inFormat;
1198
1199				inFormat.SetFrom(*(inBuffer->GetFormat()));
1200
1201				// if the source is mono, set the flags to be non interleaved, so a reinterleaver does not get setup when
1202				// completely unnecessary - since the flags on output are always set to non interleaved
1203				if (inFormat.NumberChannels() == 1)
1204					inFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
1205
1206				// output should have actual number of channels, but frame/packet size is for single channel
1207				// this is to make de interleaved data work correctly with > 1 channel
1208				CAStreamBasicDescription 	outFormat;
1209				outFormat.mChannelsPerFrame = inFormat.NumberChannels();
1210				outFormat.mSampleRate = inFormat.mSampleRate;
1211				outFormat.mFormatID = kAudioFormatLinearPCM;
1212				outFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
1213				outFormat.mBytesPerPacket = sizeof (Float32);
1214				outFormat.mFramesPerPacket = 1;
1215				outFormat.mBytesPerFrame = sizeof (Float32);
1216				outFormat.mBitsPerChannel = sizeof (Float32) * 8;
1217
1218				result = AudioConverterNew(&inFormat, &outFormat, &converter);
1219					THROW_RESULT
1220
1221				ACInfo	info;
1222				info.mInputFormat = *(inBuffer->GetFormat());
1223				info.mConverter = converter;
1224
1225				// add this AudioConverter to the source's ACMap
1226				ALuint	newACToken = GetNewToken();
1227				mACMap->Add(newACToken, &info);
1228				// add the buffer to the queue - each buffer now knows which AC to use when it is converted in the render proc
1229				mBufferQueueActive->AppendBuffer(this, inBufferToken, inBuffer, newACToken);
1230                SetQueueLength();
1231			}
1232			else
1233			{
1234				// there is already an AC for this buffer's data format, so just append the buffer to the queue
1235				mBufferQueueActive->AppendBuffer(this, inBufferToken, inBuffer, outToken);
1236                SetQueueLength();
1237			}
1238		}
1239
1240		inBuffer->UseThisBuffer(this);
1241	}
1242	catch (OSStatus	 result) {
1243		DebugMessageN1("APPEND BUFFER FAILED %ld\n", (long int) mSelfToken);
1244		throw (result);
1245	}
1246
1247#if LOG_BUFFER_QUEUEING
1248	DebugMessageN2("OALSource::AppendBufferToQueue called (END) - OALSource:QLength = %ld:%ld", (long int)mSelfToken, mBufferQueueInactive->Size() + mBufferQueueActive->Size());
1249#endif
1250
1251	return;
1252}
1253
1254// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1255// Do NOT call this from the render thread
1256void	OALSource::RemoveBuffersFromQueue(UInt32	inCount, ALuint	*outBufferTokens)
1257{
1258#if LOG_VERBOSE
1259	DebugMessageN2("OALSource::RemoveBuffersFromQueue called - OALSource:inCount = %ld:%ld\n", (long int) mSelfToken, (long int) inCount);
1260#endif
1261	if (inCount == 0)
1262		return;
1263
1264#if LOG_BUFFER_QUEUEING
1265	DebugMessageN2("OALSource::RemoveBuffersFromQueue called (START) - OALSource:inCount = %ld:%ld", (long int)mSelfToken, inCount);
1266#endif
1267
1268	try {
1269
1270		// wait if in render, then prevent rendering til completion
1271		OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1272
1273		// don't allow synchronous source manipulation
1274		CAGuard::Locker sourceLock(mSourceLock);
1275
1276        //this check also accounts for the case when the source might be transitioning to flush the Qs
1277		if (inCount > GetQLength())
1278			throw ((OSStatus) AL_INVALID_OPERATION);
1279
1280		if (outBufferTokens == NULL)
1281			throw ((OSStatus) AL_INVALID_OPERATION);
1282
1283		// 1) determine if it is a legal request
1284		// 2) determine if buffers can be removed now or at PostRender time
1285		// 3) get the buffer names that will be removed and if safe, remove them now
1286
1287		//If the source is transitioning to flush, then that's the first case to check because mState could contain a stale value
1288        if (IsSourceTransitioningToFlushQ())
1289        {
1290#if LOG_BUFFER_QUEUEING
1291            DebugMessageN2("	OALSource::RemoveBuffersFromQueue IsSourceTransitioningToFlushQ() - OALSource:inCount = %ld:%ld", (long int)mSelfToken, inCount);
1292#endif
1293            AddPlaybackMessage((UInt32) kMQ_ClearBuffersFromQueue, NULL, inCount);
1294        }
1295        else if ((mState == AL_PLAYING) || (mState == AL_PAUSED))
1296		{
1297			if (mLooping == true)
1298				throw ((OSStatus) AL_INVALID_OPERATION);
1299			else if (inCount > (UInt32)mBufferQueueInactive->GetQueueSize())
1300				throw ((OSStatus) AL_INVALID_OPERATION);
1301		}
1302		else if ((mState == AL_STOPPED) || (mState == AL_INITIAL))
1303		{
1304			ClearActiveQueue();
1305			if (inCount > (UInt32)mBufferQueueInactive->GetQueueSize())
1306			{
1307				DebugMessageN3("	OALSource::RemoveBuffersFromQueue mState == AL_STOPPED - OALSource:GetQLength():mBufferQueueInactive->Size() = %d:%d:%d", (int) mSelfToken, (int)GetQLength(), (int)mBufferQueueInactive->GetQueueSize());
1308				throw ((OSStatus) AL_INVALID_OPERATION);
1309			}
1310		}
1311		else if((mState == kTransitionToStop) || (mState == kTransitionToRewind))
1312		{
1313#if LOG_BUFFER_QUEUEING
1314			DebugMessageN2("	RemoveBuffersFromQueue kTransitionState - OALSource:inCount = %ld:%ld", (long int)mSelfToken, inCount);
1315#endif
1316#if	LOG_MESSAGE_QUEUE
1317			DebugMessageN1("	RemoveBuffersFromQueue ADDING : kMQ_ClearBuffersFromQueue - OALSource = %ld", (long int) mSelfToken);
1318#endif
1319
1320			AddPlaybackMessage(kMQ_ClearBuffersFromQueue, NULL, inCount);
1321		}
1322
1323		for (UInt32	i = mBuffersQueuedForClear; i < mBuffersQueuedForClear+inCount; i++)
1324		{
1325			//If the source is transitioning to flush, then that's the first case to check because mState could contain a stale value
1326            if (IsSourceTransitioningToFlushQ())
1327            {
1328                //get the buffer token from the temp queue
1329                outBufferTokens[i] = mBufferQueueTemp->GetBufferTokenByIndex(i);
1330                --mTempQueueLength;
1331            }
1332            else if ((mState == kTransitionToStop) || (mState == kTransitionToRewind))
1333			{
1334				//DebugMessageN1("	* RemoveBuffersFromQueue kTransitionState - GetQLengthPriv() = %ld", (long int) GetQLengthPriv());
1335				// we're transitioning, so let the caller know what buffers will be removed, but don't actually do it until the deferred message is acted on
1336				// first return the token for the buffers in the inactive queue, then the active queue
1337				if (i < (UInt32)mBufferQueueInactive->GetQueueSize())
1338				{
1339					outBufferTokens[i-mBuffersQueuedForClear] = mBufferQueueInactive->GetBufferTokenByIndex(i);
1340					//DebugMessageN1("	DEFERRED * RemoveBuffersFromQueue kTransitionState - mBufferQueueInactive->GetBufferTokenByIndex(i) = %ld", (long int) outBufferTokens[i]);
1341				}
1342				else
1343				{
1344					outBufferTokens[i-mBuffersQueuedForClear] = mBufferQueueActive->GetBufferTokenByIndex(i - mBufferQueueInactive->GetQueueSize());
1345					//DebugMessageN1("	DEFERRED * RemoveBuffersFromQueue kTransitionState - mBufferQueueActive->GetBufferTokenByIndex(i) = %ld", (long int) outBufferTokens[i]);
1346				}
1347			}
1348			else
1349			{
1350				ALuint	outToken = 0;
1351				// it is safe to remove the buffers from the inactive Q
1352				outToken = mBufferQueueInactive->RemoveQueueEntryByIndex(this, 0, true);
1353				mBuffersQueuedForClear = 0;
1354                SetQueueLength();
1355				#if	LOG_MESSAGE_QUEUE
1356					DebugMessageN1("	Just Removed Buffer Id from inactive Q = %ld", (long int) outToken);
1357				#endif
1358				outBufferTokens[i] = outToken;
1359			}
1360		}
1361
1362		if ((mState == kTransitionToStop) || (mState == kTransitionToRewind))
1363		{
1364			// we need to keep track of how many buffers need to be clear but have not yet
1365			mBuffersQueuedForClear+= inCount;
1366            SetQueueLength();
1367		}
1368
1369		if (GetQLength() == 0)
1370			mSourceType = AL_UNDETERMINED;	// Q has been cleared and is now available for both static or streaming usage
1371
1372	}
1373	catch (OSStatus	 result) {
1374		DebugMessageN1("	REMOVE BUFFER FAILED, OALSource = %ld\n", (long int) mSelfToken);
1375		throw (result);
1376	}
1377
1378#if LOG_BUFFER_QUEUEING
1379	DebugMessageN2("	OALSource:RemoveBuffersFromQueue called (END) - OALSource:QLength = %ld:%ld", (long int)mSelfToken, mBufferQueueInactive->Size() + mBufferQueueActive->Size());
1380#endif
1381
1382	return;
1383}
1384
1385// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1386// Called Only From The Post Render Proc
1387// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1388void	OALSource::PostRenderRemoveBuffersFromQueue(UInt32	inBuffersToUnqueue)
1389{
1390#if LOG_VERBOSE
1391	DebugMessageN2("OALSource::PostRenderRemoveBuffersFromQueue called - OALSource:inBuffersToUnqueue = %ld:%ld\n", (long int) mSelfToken, (long int) inBuffersToUnqueue);
1392#endif
1393
1394#if LOG_BUFFER_QUEUEING
1395	DebugMessageN2("OALSource::PostRenderRemoveBuffersFromQueue called (START) - OALSource:inCount = %ld:%ld", (long int)mSelfToken, inBuffersToUnqueue);
1396#endif
1397
1398	try {
1399		ClearActiveQueue();
1400
1401		if (inBuffersToUnqueue > (UInt32)mBufferQueueInactive->GetQueueSize())
1402		{
1403			DebugMessageN3("	OALSource::PostRenderRemoveBuffersFromQueue mState == AL_STOPPED - OALSource:GetQLength():mBufferQueueInactive->Size() = %d:%d:%d", (int) mSelfToken, (int)GetQLength(), (int)mBufferQueueInactive->GetQueueSize());
1404			throw ((OSStatus) AL_INVALID_OPERATION);
1405		}
1406
1407		for (UInt32	i = 0; i < inBuffersToUnqueue; i++)
1408		{
1409			mBufferQueueInactive->RemoveQueueEntryByIndex(this, 0, true);
1410			// we have now cleared all buffers slated for removal, so we can reset the queued for clear index
1411			mBuffersQueuedForClear = 0;
1412            SetQueueLength();
1413			//DebugMessageN1("***** OALSource::PostRenderRemoveBuffersFromQueue buffer removed = %ld", bufferToken);
1414		}
1415
1416		if (GetQLength() == 0)
1417			mSourceType = AL_UNDETERMINED;	// Q has been cleared and is now available for both static or streaming usage
1418
1419	}
1420	catch (OSStatus	 result) {
1421		DebugMessageN1("	REMOVE BUFFER FAILED, OALSource = %ld\n", (long int) mSelfToken);
1422		throw (result);
1423	}
1424
1425#if LOG_BUFFER_QUEUEING
1426	DebugMessageN2("	OALSource:PostRenderRemoveBuffersFromQueue called (END) - OALSource:QLength = %ld:%ld\n", (long int)mSelfToken, mBufferQueueInactive->Size() + mBufferQueueActive->Size());
1427#endif
1428
1429	return;
1430}
1431
1432// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1433void	OALSource::PostRenderAddBuffersToQueue (UInt32 inNumBuffersToQueue)
1434{
1435#if LOG_VERBOSE
1436	DebugMessageN3("OALSource::PostRenderAddBuffersToQueue - OALSource:inBufferToken:inBuffer = %ld:%ld:%p", (long int) mSelfToken, (long int) inBufferToken, inBuffer);
1437#endif
1438
1439    try
1440    {
1441        if (mSourceType == AL_STATIC)
1442            throw (OSStatus) AL_INVALID_OPERATION;
1443
1444        if (mSourceType == AL_UNDETERMINED)
1445            mSourceType = AL_STREAMING;
1446
1447        while (inNumBuffersToQueue--)
1448        {
1449            // Get buffer #i from Temp List
1450            BufferInfo* bufferInfo = mBufferQueueTemp->Get(0);
1451            // Append it to Active List
1452            AppendBufferToQueue(bufferInfo->mBufferToken, bufferInfo->mBuffer);
1453            // Remove it from Temp List
1454            mBufferQueueTemp->RemoveQueueEntryByIndex(this, 0, true);
1455        }
1456    }
1457    catch (OSStatus	 result) {
1458		DebugMessageN1("	REMOVE BUFFER FAILED, OALSource = %ld\n", (long int) mSelfToken);
1459		throw (result);
1460	}
1461}
1462
1463// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1464void	OALSource::PostRenderSetBuffer (ALuint inBufferToken, OALBuffer	*inBuffer)
1465{
1466#if LOG_VERBOSE
1467	DebugMessageN3("OALSource::PostRenderSetBuffer - OALSource:inBufferToken:inBuffer = %ld:%ld:%p", (long int) mSelfToken, (long int) inBufferToken, inBuffer);
1468#endif
1469	FlushBufferQueue();
1470
1471	// if inBufferToken == 0, do nothing, passing NONE to this method is legal and should merely empty the queue
1472	if (inBufferToken != 0)
1473	{
1474		AppendBufferToQueue(inBufferToken, inBuffer);
1475		mSourceType = AL_STATIC;
1476	}
1477	else
1478    {
1479		mSourceType = AL_UNDETERMINED;
1480        mTransitioningToFlushQ = false;
1481    }
1482}
1483
1484// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1485// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1486// PLAYBACK METHODS
1487// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1488// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1489
1490void	OALSource::SetupMixerBus()
1491{
1492#if LOG_VERBOSE
1493	DebugMessageN1("OALSource::SetupMixerBus called - OALSource = %ld\n", (long int) mSelfToken);
1494#endif
1495	OSStatus					result = noErr;
1496	CAStreamBasicDescription    desc;
1497	UInt32						propSize = 0;
1498	BufferInfo*					buffer = mBufferQueueActive->Get(mCurrentBufferIndex);
1499
1500	try {
1501		if (buffer == NULL)
1502			throw (OSStatus)-1;
1503
1504		if (mCurrentPlayBus == kSourceNeedsBus)
1505		{
1506			// the bus stream format will get set if necessary while getting the available bus
1507			mCurrentPlayBus = (buffer->mBuffer->GetNumberChannels() == 1) ? mOwningContext->GetAvailableMonoBus(mSelfToken) : mOwningContext->GetAvailableStereoBus(mSelfToken);
1508			if (mCurrentPlayBus == -1)
1509				throw (OSStatus) -1;
1510
1511			if (Get3DMixerVersion() >= k3DMixerVersion_2_0)
1512			{
1513//				Float32     rollOff = mRollOffFactor;
1514				Float32     refDistance = mReferenceDistance;
1515				Float32     maxDistance = mMaxDistance;
1516
1517				if (mOwningContext->IsDistanceScalingRequired())
1518				{
1519					refDistance = (mReferenceDistance/mMaxDistance) * kDistanceScalar;
1520					maxDistance = kDistanceScalar;
1521//					rollOff *= (kDistanceScalar/mMaxDistance);
1522				}
1523
1524				Float32	testAttenuation = GetMaxAttenuation(mReferenceDistance, mMaxDistance, mRollOffFactor);
1525
1526				// Set the MixerDistanceParams for the new bus if necessary
1527				MixerDistanceParams		distanceParams;
1528				propSize = sizeof(distanceParams);
1529				result = AudioUnitGetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_3DMixerDistanceParams, kAudioUnitScope_Input, mCurrentPlayBus, &distanceParams, &propSize);
1530
1531				if  ((result == noErr) 	&& ((distanceParams.mReferenceDistance != refDistance)      ||
1532											(distanceParams.mMaxDistance != maxDistance)            ||
1533											(distanceParams.mMaxAttenuation != testAttenuation)))
1534				{
1535					distanceParams.mMaxAttenuation = testAttenuation;
1536
1537					if (mOwningContext->IsDistanceScalingRequired())
1538					{
1539
1540						distanceParams.mReferenceDistance = (mReferenceDistance/mMaxDistance) * kDistanceScalar;
1541						// limit the max distance
1542						distanceParams.mMaxDistance = kDistanceScalar;
1543						distanceParams.mMaxAttenuation = testAttenuation;
1544					}
1545					else
1546					{
1547						distanceParams.mReferenceDistance = mReferenceDistance;
1548						distanceParams.mMaxDistance = mMaxDistance;
1549					}
1550
1551					if ((mReferenceDistance == mMaxDistance) && (Get3DMixerVersion() < k3DMixerVersion_2_2))
1552						distanceParams.mMaxDistance = distanceParams.mReferenceDistance + .01; // pre 2.2 3DMixer may crash  if max and reference distances are equal
1553
1554					/*result =*/ AudioUnitSetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_3DMixerDistanceParams, kAudioUnitScope_Input, mCurrentPlayBus, &distanceParams, sizeof(distanceParams));
1555				}
1556			}
1557			else
1558			{
1559				// the pre-2.0 3DMixer does not accept kAudioUnitProperty_3DMixerDistanceParams, it has do some extra work and use the DistanceAtten property instead
1560				mOwningContext->SetDistanceAttenuation(mCurrentPlayBus, mReferenceDistance, mMaxDistance, mRollOffFactor);
1561			}
1562
1563			UpdateBusReverb();
1564			UpdateBusOcclusion();
1565			UpdateBusObstruction();
1566		}
1567
1568		// get the sample rate of the bus
1569		propSize = sizeof(desc);
1570		/*result =*/ AudioUnitGetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, mCurrentPlayBus, &desc, &propSize);
1571
1572		mResetPitch = true;
1573		mCalculateDistance = true;
1574		if (desc.mSampleRate != buffer->mBuffer->GetSampleRate())
1575			mResetBusFormat = true;     // only reset the bus stream format if it is different than sample rate of the data
1576
1577		// *************************** Set properties for the mixer bus
1578
1579		ChangeChannelSettings();
1580		UpdateBusGain();
1581        UpdateBusRenderQuality();
1582	}
1583	catch (OSStatus	 result) {
1584		DebugMessageN2("	SetupMixerBus FAILED, OALSource:error = %d:%d\n", (int) mSelfToken, (int)result);
1585		throw (result);
1586	}
1587	catch (...) {
1588		DebugMessageN1("	SetupMixerBus FAILED, OALSource = %ld\n", (long int) mSelfToken);
1589		throw;
1590	}
1591
1592	return;
1593}
1594
1595// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1596void	OALSource::ResetMixerBus()
1597{
1598#if LOG_VERBOSE
1599	DebugMessageN1("OALSource::ResetMixerBus() - OALSource = %ld", (long int) mSelfToken);
1600#endif
1601    OSStatus result = noErr;
1602    try {
1603        //this should only get called when the source has a bus
1604
1605        if (mCurrentPlayBus != kSourceNeedsBus)
1606        {
1607            //a mixer bus should be setup with the desired parameters before it is reset
1608            //setup is handled by the SetupMixerBus method
1609            result = AudioUnitReset(mOwningContext->GetMixerUnit(), kAudioUnitScope_Input, mCurrentPlayBus);
1610                THROW_RESULT
1611        }
1612    }
1613
1614    catch (OSStatus	 result) {
1615		DebugMessageN2("	ResetMixerBus FAILED, OALSource:error = %d:%d\n", (int) mSelfToken, (int)result);
1616		throw (result);
1617	}
1618	catch (...) {
1619		DebugMessageN1("	ResetMixerBus FAILED, OALSource = %ld\n", (long int) mSelfToken);
1620		throw;
1621	}
1622
1623	return;
1624}
1625
1626// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1627void OALSource::SetupRogerBeepAU()
1628{
1629#if LOG_VERBOSE
1630	DebugMessageN1("OALSource::SetupRogerBeepAU called - OALSource = %ld\n", (long int) mSelfToken);
1631#endif
1632
1633	ComponentDescription desc;
1634	desc.componentFlags = 0;
1635	desc.componentFlagsMask = 0;
1636	desc.componentType = kAudioUnitType_Effect;
1637	desc.componentSubType = kRogerBeepType;
1638	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1639
1640	// CREATE NEW NODE FOR THE GRAPH
1641	OSStatus result = AUGraphNewNode (mOwningContext->GetGraph(), &desc, 0, NULL, &mRogerBeepNode);
1642		THROW_RESULT
1643
1644	result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, 0, 0, 0, &mRogerBeepAU);
1645		THROW_RESULT
1646}
1647
1648void OALSource::SetupDistortionAU()
1649{
1650#if LOG_VERBOSE
1651	DebugMessageN1("OALSource::SetupDistortionAU called - OALSource = %ld\n", (long int) mSelfToken);
1652#endif
1653	ComponentDescription desc;
1654	desc.componentFlags = 0;
1655	desc.componentFlagsMask = 0;
1656	desc.componentType = kAudioUnitType_Effect;
1657	desc.componentSubType = kDistortionType;
1658	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1659
1660	// CREATE NEW NODE FOR THE GRAPH
1661	OSStatus result = AUGraphNewNode (mOwningContext->GetGraph(), &desc, 0, NULL, &mDistortionNode);
1662		THROW_RESULT
1663
1664	result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mDistortionNode, 0, 0, 0, &mDistortionAU);
1665		THROW_RESULT
1666}
1667
1668// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1669// returns false if there is no data to play
1670bool	OALSource::PrepBufferQueueForPlayback()
1671{
1672#if LOG_VERBOSE
1673	DebugMessageN1("OALSource::PrepBufferQueueForPlayback called - OALSource = %ld\n", (long int) mSelfToken);
1674#endif
1675    BufferInfo		*buffer = NULL;
1676
1677	JoinBufferLists();
1678
1679	if (mBufferQueueActive->Empty())
1680		return false; // there isn't anything to do
1681
1682	// Get the format for the first buffer in the queue
1683	buffer = NextPlayableBufferInActiveQ();
1684	if (buffer == NULL)
1685		return false; // there isn't anything to do
1686
1687#if LOG_PLAYBACK
1688	DebugMessage("OALSource::PrepBufferQueueForPlayback called - Format of 1st buffer in the Q =\n");
1689	buffer->mBuffer->PrintFormat();
1690#endif
1691
1692	// WARM THE BUFFERS
1693	// when playing, touch all the audio data in memory once before it is needed in the render proc  (RealTime thread)
1694	{
1695		volatile UInt32	X;
1696		UInt32		*start = (UInt32 *)buffer->mBuffer->GetDataPtr();
1697		UInt32		*end = (UInt32 *)(buffer->mBuffer->GetDataPtr() + (buffer->mBuffer->GetDataSize() &0xFFFFFFFC));
1698		while (start < end)
1699		{
1700			X = *start;
1701			start += 1024;
1702		}
1703	}
1704
1705	if (buffer->mBuffer->HasBeenConverted() == false)
1706		AudioConverterReset(mACMap->Get(buffer->mACToken));
1707
1708	return true;
1709}
1710
1711// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1712void	OALSource::Play()
1713{
1714#if LOG_VERBOSE
1715	DebugMessageN1("OALSource::Play called - OALSource = %ld\n", (long int) mSelfToken);
1716#endif
1717#if LOG_PLAYBACK
1718	DebugMessageN2("OALSource::Play called - OALSource:mState = %ld:%ld\n", (long int) mSelfToken, mState);
1719#endif
1720	try {
1721		// wait if in render, then prevent rendering til completion
1722		OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1723
1724		// don't allow synchronous source manipulation
1725		CAGuard::Locker sourceLock(mSourceLock);
1726
1727		if (GetQLengthPriv() == 0)
1728			return; // nothing to do
1729
1730		switch (mState)
1731		{
1732			case AL_PLAYING:
1733			case kTransitionToPlay:
1734			case kTransitionToResume:
1735			case kTransitionToRetrigger:
1736				if (mRampState != kRampingComplete)
1737				{
1738					mRampState = kRampDown;
1739#if	LOG_MESSAGE_QUEUE
1740					DebugMessageN1("OALSource::Play (AL_PLAYING state)  - kMQ_Retrigger added to MQ - OALSource = %ld", (long int) mSelfToken);
1741#endif
1742					AddPlaybackMessage(kMQ_Retrigger, NULL, 0);
1743					SetPlaybackState(kTransitionToRetrigger);
1744			 	}
1745				break;
1746
1747			case AL_PAUSED:
1748				Resume();
1749				break;
1750
1751			case kTransitionToPause:
1752#if	LOG_MESSAGE_QUEUE
1753                DebugMessageN1("OALSource::Play (kTransitionToPause state)  - kMQ_Resume added to MQ - OALSource = %ld", (long int) mSelfToken);
1754#endif
1755				AddPlaybackMessage((UInt32) kMQ_Resume, NULL, 0);
1756				SetPlaybackState(kTransitionToResume);
1757				break;
1758
1759			case kTransitionToStop:
1760			case kTransitionToRewind:
1761				if (mRampState != kRampingComplete)
1762				{
1763					mRampState = kRampDown;
1764#if	LOG_MESSAGE_QUEUE
1765					DebugMessageN1("OALSource::Play (kTransitionToStop/kTransitionToRewind state)  - kMQ_Play added to MQ - OALSource = %ld", (long int) mSelfToken);
1766#endif
1767					AddPlaybackMessage(kMQ_Play, NULL, 0);
1768					SetPlaybackState(kTransitionToPlay);
1769				}
1770				break;
1771
1772			default:
1773			{
1774				// get the buffer q in a ready state for playback
1775				PrepBufferQueueForPlayback();
1776
1777				// set up a mixer bus now
1778				SetupMixerBus();
1779				CAStreamBasicDescription	format;
1780				UInt32                      propSize = sizeof(format);
1781				OSStatus result = noErr;
1782
1783				if(mASARogerBeepEnable || mASADistortionEnable)
1784				{
1785					mRenderElement = 0;
1786					result = AudioUnitGetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, mCurrentPlayBus, &format, &propSize);
1787						THROW_RESULT
1788
1789					if(mASARogerBeepEnable)
1790					{
1791						// set AU format to mixer format for input/output
1792						result = AudioUnitSetProperty (mRogerBeepAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format));
1793							THROW_RESULT
1794						result = AudioUnitSetProperty (mRogerBeepAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof(format));
1795							THROW_RESULT
1796						result = AudioUnitInitialize(mRogerBeepAU);
1797							THROW_RESULT
1798						// connect roger beep AU to 3D Mixer
1799						result = AUGraphConnectNodeInput(mOwningContext->GetGraph(), mRogerBeepNode, 0, mOwningContext->GetMixerNode(), mCurrentPlayBus);
1800							THROW_RESULT
1801
1802						if(!mASADistortionEnable)
1803						{
1804							// connect render proc to unit if distortion is not enabled
1805							result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, 0, 0, 0, &mRenderUnit);
1806								THROW_RESULT;
1807						}
1808					}
1809
1810					if(mASADistortionEnable)
1811					{
1812
1813						// set AU format to mixer format for input/output
1814						result = AudioUnitSetProperty (mDistortionAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format));
1815							THROW_RESULT
1816						result = AudioUnitSetProperty (mDistortionAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof(format));
1817							THROW_RESULT
1818						result = AudioUnitInitialize(mDistortionAU);
1819							THROW_RESULT
1820
1821						// distortion unit will always be first if it exists
1822						result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mDistortionNode, 0, 0, 0, &mRenderUnit);
1823							THROW_RESULT
1824
1825						if(mASARogerBeepEnable)
1826							result = AUGraphConnectNodeInput(mOwningContext->GetGraph(), mDistortionNode, 0, mRogerBeepNode, 0);
1827						else
1828							result = AUGraphConnectNodeInput(mOwningContext->GetGraph(), mDistortionNode, 0, mOwningContext->GetMixerNode(), mCurrentPlayBus);
1829
1830							THROW_RESULT
1831					}
1832
1833					result = AUGraphUpdate(mOwningContext->GetGraph(), NULL);
1834						THROW_RESULT
1835				}
1836				else
1837				{
1838					mRenderUnit = mOwningContext->GetMixerUnit();
1839					mRenderElement = mCurrentPlayBus;
1840				}
1841					THROW_RESULT
1842
1843				SetPlaybackState(AL_PLAYING,true);
1844                if (mRampState != kRampingComplete)
1845                    mRampState = kRampUp;
1846                mResetBus = true;
1847				mQueueIsProcessed = false;
1848				// attach the notify and render procs to the first unit in the sequence
1849				AddNotifyAndRenderProcs();
1850			}
1851		}
1852	}
1853	catch (OSStatus	result) {
1854		DebugMessageN2("PLAY FAILED source = %ld, err = %ld\n", (long int) mSelfToken, (long int)result);
1855		throw (result);
1856	}
1857}
1858
1859// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1860void	OALSource::Rewind()
1861{
1862#if LOG_VERBOSE
1863	DebugMessageN1("OALSource::Rewind called - OALSource = %ld\n", (long int) mSelfToken);
1864#endif
1865#if LOG_PLAYBACK
1866	DebugMessageN2("OALSource::Rewind called - OALSource:mState = %ld:%ld\n", (long int) mSelfToken, mState);
1867#endif
1868
1869	// wait if in render, then prevent rendering til completion
1870	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1871
1872	// don't allow synchronous source manipulation
1873	CAGuard::Locker sourceLock(mSourceLock);
1874
1875	switch (mState)
1876	{
1877		case AL_PLAYING:
1878		{
1879#if	LOG_MESSAGE_QUEUE
1880			DebugMessageN1("Rewind(AL_PLAYING)  ADDING : kMQ_Rewind - OALSource = %ld", (long int) mSelfToken);
1881#endif
1882
1883			SetPlaybackState(kTransitionToRewind);
1884			if (mRampState != kRampingComplete)
1885				mRampState = kRampDown;
1886			AddPlaybackMessage(kMQ_Rewind, NULL, 0);
1887			break;
1888
1889		}
1890		case AL_PAUSED:
1891			if (mCurrentPlayBus != kSourceNeedsBus)
1892			{
1893				mOwningContext->SetBusAsAvailable (mCurrentPlayBus);
1894				mCurrentPlayBus = kSourceNeedsBus;
1895			}
1896			JoinBufferLists();	// just reset the buffer queue now
1897			SetPlaybackState(AL_INITIAL,true);
1898			break;
1899
1900		case AL_STOPPED:
1901			JoinBufferLists();	// just reset the buffer queue now
1902			SetPlaybackState(AL_INITIAL,true);
1903			break;
1904
1905		case kTransitionToPlay:
1906		case kTransitionToResume:
1907		case kTransitionToRetrigger:
1908		case kTransitionToStop:
1909		case kTransitionToPause:
1910		{
1911#if	LOG_MESSAGE_QUEUE
1912			DebugMessageN1("OALSource::Rewind - kMQ_Rewind added to MQ - OALSource = %ld", (long int) mSelfToken);
1913#endif
1914			SetPlaybackState(kTransitionToRewind);
1915			AddPlaybackMessage((UInt32) kMQ_Rewind, NULL, 0);
1916			break;
1917		}
1918
1919		case AL_INITIAL:
1920		case kTransitionToRewind:
1921			break;
1922	}
1923}
1924
1925// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1926void	OALSource::Pause()
1927{
1928#if LOG_VERBOSE
1929	DebugMessageN1("OALSource::Pause called - OALSource = %ld\n", (long int) mSelfToken);
1930#endif
1931#if LOG_PLAYBACK
1932	DebugMessageN2("OALSource::Pause called - OALSource:mState = %ld:%ld\n", (long int) mSelfToken, mState);
1933#endif
1934
1935	// wait if in render, then prevent rendering til completion
1936	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1937
1938	// don't allow synchronous source manipulation
1939	CAGuard::Locker sourceLock(mSourceLock);
1940
1941	switch (mState)
1942	{
1943		case AL_PLAYING:
1944		{
1945			if (mRampState != kRampingComplete)
1946				mRampState = kRampDown;
1947#if	LOG_MESSAGE_QUEUE
1948				DebugMessageN1("Pause(AL_PLAYING)  ADDING : kMQ_Pause - OALSource = %ld", (long int) mSelfToken);
1949#endif
1950			AddPlaybackMessage(kMQ_Pause, NULL, 0);
1951			SetPlaybackState(kTransitionToPause);
1952		}
1953		case AL_INITIAL:
1954		case AL_STOPPED:
1955		case AL_PAUSED:
1956		case kTransitionToPause:
1957		case kTransitionToStop:
1958		case kTransitionToRewind:
1959			break;
1960
1961		case kTransitionToPlay:
1962		case kTransitionToResume:
1963		case kTransitionToRetrigger:
1964		{
1965#if	LOG_MESSAGE_QUEUE
1966			DebugMessageN1("OALSource::Pause - kMQ_Pause added to MQ - OALSource = %ld", (long int) mSelfToken);
1967#endif
1968			AddPlaybackMessage((UInt32) kMQ_Pause, NULL, 0);
1969			SetPlaybackState(kTransitionToPause);
1970			break;
1971		}
1972
1973		default:
1974			// do nothing it's either stopped or initial right now
1975			break;
1976	}
1977}
1978
1979// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1980void	OALSource::Resume()
1981{
1982#if LOG_VERBOSE
1983	DebugMessageN1("OALSource::Resume called - OALSource = %ld\n", (long int) mSelfToken);
1984#endif
1985#if LOG_PLAYBACK
1986	DebugMessageN2("OALSource::Resume called - OALSource:mState = %ld:%ld\n", (long int) mSelfToken, mState);
1987#endif
1988
1989	// wait if in render, then prevent rendering til completion
1990	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
1991
1992	// don't allow synchronous source manipulation
1993	CAGuard::Locker sourceLock(mSourceLock);
1994
1995	switch (mState)
1996	{
1997		case AL_PLAYING:
1998		case AL_INITIAL:
1999		case AL_STOPPED:
2000		case kTransitionToPlay:
2001		case kTransitionToResume:
2002		case kTransitionToRetrigger:
2003		case kTransitionToStop:
2004		case kTransitionToRewind:
2005			break;
2006
2007		case AL_PAUSED:
2008			if (mRampState != kRampingComplete)
2009                mRampState = kRampUp;
2010			AddNotifyAndRenderProcs();
2011			SetPlaybackState(AL_PLAYING,true);
2012			break;
2013
2014		case kTransitionToPause:
2015#if	LOG_MESSAGE_QUEUE
2016			DebugMessageN1("OALSource::Resume - kMQ_Resume added to MQ - OALSource = %ld", (long int) mSelfToken);
2017#endif
2018			AddPlaybackMessage((UInt32) kMQ_Resume, NULL, 0);
2019			SetPlaybackState(kTransitionToResume);
2020			break;
2021	}
2022}
2023
2024// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025void	OALSource::Stop()
2026{
2027#if LOG_VERBOSE
2028	DebugMessageN1("OALSource::Stop called - OALSource = %ld\n", (long int) mSelfToken);
2029#endif
2030#if LOG_PLAYBACK
2031	DebugMessageN2("OALSource::Stop called - OALSource:mState = %ld:%ld\n", (long int) mSelfToken, mState);
2032#endif
2033
2034	// wait if in render, then prevent rendering til completion
2035	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
2036
2037	// don't allow synchronous source manipulation
2038	CAGuard::Locker sourceLock(mSourceLock);
2039
2040	switch (mState)
2041	{
2042		case AL_PAUSED:
2043		if (mCurrentPlayBus != kSourceNeedsBus)
2044		{
2045			mOwningContext->SetBusAsAvailable (mCurrentPlayBus);
2046			mCurrentPlayBus = kSourceNeedsBus;
2047			SetPlaybackState(AL_STOPPED,true);
2048			if(mBufferQueueActive->GetQueueSize() > 0)
2049			{
2050				if (mSourceNotifications)
2051					mSourceNotifications->CallSourceNotifications(AL_BUFFERS_PROCESSED);
2052			}
2053		}
2054			break;
2055		case AL_PLAYING:
2056		{
2057#if	LOG_MESSAGE_QUEUE
2058			DebugMessageN1("OALSource::Stop (AL_PLAYING state)  ADDING : kMQ_Stop - OALSource = %ld", (long int) mSelfToken);
2059#endif
2060			SetPlaybackState(kTransitionToStop);
2061			if (mRampState != kRampingComplete)
2062				mRampState = kRampDown;
2063			AddPlaybackMessage(kMQ_Stop, NULL, 0);
2064		}
2065			break;
2066
2067		case kTransitionToStop:
2068		case kTransitionToRewind:
2069			break;
2070
2071		case kTransitionToPlay:
2072		case kTransitionToResume:
2073		case kTransitionToRetrigger:
2074		case kTransitionToPause:
2075		{
2076#if	LOG_MESSAGE_QUEUE
2077			DebugMessageN1("OALSource::Stop (kTransitionState state)  ADDING : kMQ_Stop - OALSource = %ld", (long int) mSelfToken);
2078#endif
2079			AddPlaybackMessage(kMQ_Stop, NULL, 0);
2080			SetPlaybackState(kTransitionToStop);
2081			break;
2082		}
2083
2084		default:
2085			// do nothing it's either stopped or initial right now
2086			break;
2087	}
2088}
2089
2090// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2091UInt32	OALSource::SecondsToFrames(Float32	inSeconds)
2092{
2093#if LOG_VERBOSE
2094	DebugMessageN2("OALSource::SecondsToFrames called - OALSource:inSeconds = %ld:%f\n", (long int) mSelfToken, inSeconds);
2095#endif
2096	BufferInfo	*curBufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2097	UInt32 frames = 0;
2098
2099	if (curBufferInfo)
2100		frames = (UInt32)(inSeconds * curBufferInfo->mBuffer->GetSampleRate());
2101	// Check for uint overflow
2102	if ((SInt32) frames < (SInt32) inSeconds)
2103		throw (OSStatus) AL_INVALID_VALUE;
2104
2105	return frames;
2106}
2107
2108// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2109// this method should round off to the packet index that contains the requested frame offset
2110UInt32	OALSource::BytesToFrames(Float32	inBytes)
2111{
2112#if LOG_VERBOSE
2113	DebugMessageN2("OALSource::BytesToFrames called - OALSource:inBytes = %ld:%f\n", (long int) mSelfToken, inBytes);
2114#endif
2115	BufferInfo	*curBufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2116	if (curBufferInfo)
2117	{
2118		UInt32	frameIndex = (UInt32)(inBytes / curBufferInfo->mBuffer->GetBytesPerPacket());	// how many packets is this
2119		frameIndex *= curBufferInfo->mBuffer->GetFramesPerPacket();					// translate packets to frames
2120		return frameIndex;
2121	}
2122
2123	return 0;
2124}
2125
2126// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2127UInt32	OALSource::FramesToSecondsInt(UInt32	inFrames)
2128{
2129#if LOG_VERBOSE
2130	DebugMessageN2("OALSource::FramesToSecondsInt called - OALSource:inFrames = %ld:%d\n", (long int) mSelfToken, inFrames);
2131#endif
2132	BufferInfo	*curBufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2133	if (curBufferInfo == NULL)
2134		curBufferInfo = mBufferQueueInactive->Get(0); // if the active Q is dry, check the inactive Q
2135
2136	if (curBufferInfo)
2137		return (UInt32)(inFrames / curBufferInfo->mBuffer->GetSampleRate());
2138
2139	return 0;
2140}
2141
2142// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2143Float32	OALSource::FramesToSecondsFloat(UInt32	inFrames)
2144{
2145#if LOG_VERBOSE
2146	DebugMessageN2("OALSource::FramesToSecondsFloat called - OALSource:inFrames = %ld:%f\n", (long int) mSelfToken, inFrames);
2147#endif
2148	BufferInfo	*curBufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2149	if (curBufferInfo == NULL)
2150		curBufferInfo = mBufferQueueInactive->Get(0); // if the active Q is dry, check the inactive Q
2151
2152	if (curBufferInfo)
2153		return (inFrames / curBufferInfo->mBuffer->GetSampleRate());
2154
2155	return 0;
2156}
2157
2158// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2159UInt32	OALSource::FramesToBytes(UInt32	inFrames)
2160{
2161#if LOG_VERBOSE
2162	DebugMessageN2("OALSource::FramesToBytes called - OALSource:inFrames = %ld:%d\n", (long int) mSelfToken, inFrames);
2163#endif
2164	// any buffer in the q will do, they should all be the same
2165	BufferInfo	*curBufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2166	if (curBufferInfo == NULL)
2167		curBufferInfo = mBufferQueueInactive->Get(0); // the active Q must be empty, check the inactive Q
2168
2169	if (curBufferInfo)
2170	{
2171		if(curBufferInfo->mBuffer->GetFramesPerPacket() != 0)
2172			return (inFrames / curBufferInfo->mBuffer->GetFramesPerPacket()) * curBufferInfo->mBuffer->GetBytesPerPacket();
2173	}
2174
2175	return 0;
2176}
2177
2178// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2179UInt32	OALSource::GetQueueFrameOffset()
2180{
2181#if LOG_VERBOSE
2182	DebugMessageN1("OALSource::GetQueueFrameOffset called - OALSource = %ld\n", (long int) mSelfToken);
2183#endif
2184	UInt32		inInactiveQFrames = mBufferQueueInactive->GetQueueSizeInFrames();
2185	UInt32		inActiveQFrames = 0;
2186
2187	for (UInt32	i = 0; i < mCurrentBufferIndex; i++)
2188	{
2189		inActiveQFrames += mBufferQueueActive->GetBufferFrameCount(i);
2190	}
2191
2192	inActiveQFrames += mBufferQueueActive->GetCurrentFrame(mCurrentBufferIndex);
2193
2194	return inActiveQFrames + inInactiveQFrames;
2195}
2196
2197// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2198UInt32	OALSource::GetQueueOffset(UInt32	inOffsetType)
2199{
2200#if LOG_VERBOSE
2201	DebugMessageN2("OALSource::GetQueueOffset called - OALSource:GetQueueOffset = %ld:%d\n", (long int) mSelfToken, inOffsetType);
2202#endif
2203	CAGuard::Locker sourceLock(mSourceLock);
2204
2205	switch (inOffsetType)
2206	{
2207		case kSecondsOffset:
2208			return (FramesToSecondsInt(GetQueueFrameOffset()));
2209			break;
2210		case kSampleOffset:
2211			return (GetQueueFrameOffset());
2212			break;
2213		case kByteOffset:
2214			return (FramesToBytes(GetQueueFrameOffset()));
2215			break;
2216		default:
2217			break;
2218	}
2219
2220	return  0;
2221}
2222
2223// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2224Float32	OALSource::GetQueueOffsetSecondsFloat()
2225{
2226#if LOG_VERBOSE
2227	DebugMessageN1("OALSource::GetQueueOffsetSecondsFloat called - OALSource = %ld\n", (long int) mSelfToken);
2228#endif
2229	CAGuard::Locker sourceLock(mSourceLock);
2230
2231	return (FramesToSecondsFloat(GetQueueFrameOffset()));
2232}
2233
2234// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2235void	OALSource::SetQueueOffset(UInt32	inOffsetType,	Float32	inOffset)
2236{
2237#if LOG_VERBOSE
2238	DebugMessageN3("OALSource::SetQueueOffset called - OALSource:inOffsetType:inOffset = %ld:%d:%f\n", (long int) mSelfToken, inOffsetType, inOffset);
2239#endif
2240#if LOG_PLAYBACK
2241	DebugMessageN1("OALSource::SetQueueOffset - OALSource = %ld", (long int) mSelfToken);
2242#endif
2243	UInt32		frameOffset = 0;
2244
2245	if (inOffset < 0.0f)
2246		throw (OSStatus)AL_INVALID_VALUE;
2247
2248	// wait if in render, then prevent rendering til completion
2249	OALRenderLocker::RenderLocker locked(mRenderLocker, InRenderThread());
2250
2251	// don't allow synchronous source manipulation
2252	CAGuard::Locker sourceLock(mSourceLock);
2253
2254	// first translate the entered offset into a frame offset
2255	switch (inOffsetType)
2256	{
2257		case kSecondsOffset:
2258			frameOffset = SecondsToFrames(inOffset);
2259			break;
2260		case kSampleOffset:
2261			frameOffset = (UInt32) inOffset;	// samples = frames in this case
2262			break;
2263		case kByteOffset:
2264			frameOffset = BytesToFrames(inOffset);
2265			break;
2266		default:
2267			return;
2268			break;
2269	}
2270
2271	// move the queue to the requested offset either right now, or in the PostRender proc via a queued message
2272	switch (mState)
2273	{
2274		case AL_INITIAL:
2275		case AL_STOPPED:
2276		case AL_PAUSED:
2277		{
2278			Rewind();	// join the active and inactive lists
2279			AdvanceQueueToFrameIndex(frameOffset);
2280		}
2281			break;
2282
2283		case AL_PLAYING:
2284		case kTransitionToStop:
2285		case kTransitionToRewind:
2286		case kTransitionToPause:
2287		case kTransitionToResume:
2288		case kTransitionToRetrigger:
2289		case kTransitionToPlay:
2290		{
2291			// Check this here so we don't throw in the render thread
2292			if (frameOffset > mBufferQueueActive->GetQueueSizeInFrames())
2293				throw (OSStatus)AL_INVALID_VALUE;
2294			mRampState = kRampDown;
2295			// currently, no consideration for ramping the samples is being taken, so there could be clicks if playhead is moved during a playback
2296			// this is a bug, if SetQueueOffset is called multiple times between render cycles,
2297			// the offset will end up at zero in the post render when mPlaybackHeadPosition gets reset after the first message is addressed
2298			mPlaybackHeadPosition = frameOffset;
2299#if	LOG_MESSAGE_QUEUE
2300			DebugMessageN1("OALSource::SetQueueOffset - kMQ_SetFramePosition added to MQ - OALSource = %ld", (long int) mSelfToken);
2301#endif
2302			AddPlaybackMessage(kMQ_SetFramePosition, NULL, 0);
2303			break;
2304		}
2305
2306		default:
2307			break;
2308	}
2309}
2310
2311// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2312// this should only be called when the source is render and edit protected
2313void	OALSource::AdvanceQueueToFrameIndex(UInt32	inFrameOffset)
2314{
2315#if LOG_VERBOSE
2316	DebugMessageN2("OALSource::AdvanceQueueToFrameIndex called - OALSource:inFrameOffset = %ld:%d", (long int) mSelfToken, inFrameOffset);
2317#endif
2318	// Queue should be in an initial state right now.
2319	UInt32	totalQueueFrames = mBufferQueueActive->GetQueueSizeInFrames();
2320	if (inFrameOffset > totalQueueFrames)
2321		throw (OSStatus)AL_INVALID_VALUE;
2322
2323	// Walk through the buffers until we reach the one that contains this offset. Mark all preceeding buffers as processed and move to inActive Queue
2324
2325	UInt32		frameStartOfCurrentBuffer = 0;
2326
2327	UInt32		count = mBufferQueueActive->GetQueueSize();
2328	for (UInt32	i = 0; i < count; i++)
2329	{
2330		BufferInfo*		curBufferInfo = mBufferQueueActive->Get(0);							// get the first buffer info in the Q
2331		UInt32			bufferFrameCount = curBufferInfo->mBuffer->GetFrameCount();			// how many frames of data are in this buffer?
2332
2333		if (frameStartOfCurrentBuffer + bufferFrameCount > inFrameOffset)
2334		{
2335			// this is the buffer that contains the desired offset
2336			mBufferQueueActive->SetFirstBufferOffset(inFrameOffset - frameStartOfCurrentBuffer) ;
2337			break; // we're done
2338		}
2339		else
2340		{
2341			// not there yet. Mark this buffer as processed and move to inactive queue
2342			mBufferQueueActive->SetBufferAsProcessed(0);
2343			mBufferQueueActive->RemoveQueueEntryByIndex(this, 0, false);
2344			mBufferQueueInactive->AppendBuffer(this, curBufferInfo->mBufferToken, curBufferInfo->mBuffer, curBufferInfo->mACToken);
2345            SetQueueLength();
2346			if (mSourceNotifications)
2347				mSourceNotifications->CallSourceNotifications(AL_BUFFERS_PROCESSED);
2348		}
2349		frameStartOfCurrentBuffer += bufferFrameCount;
2350	}
2351
2352	return;
2353}
2354
2355// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2356#pragma mark ***** Source Notify Ext*****
2357// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2358// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2359
2360// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2361ALenum OALSource::AddNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData)
2362{
2363#if LOG_VERBOSE
2364	DebugMessageN4("OALSource::AddNotification called - OALSource:notificationID:notifyProc:userData = %ld:%ld:%p:%p\n", (long int) mSelfToken, (long int) notificationID, notifyProc, userData);
2365#endif
2366	ALenum err = AL_NO_ERROR;
2367
2368	if (mSourceNotifications == NULL)
2369		mSourceNotifications = new SourceNotifications(mSelfToken);
2370
2371	err = mSourceNotifications->AddSourceNotification(notificationID, notifyProc, userData);
2372
2373	return err;
2374}
2375
2376void OALSource::RemoveNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData)
2377{
2378#if LOG_VERBOSE
2379	DebugMessageN4("OALSource::RemoveNotification called - OALSource:notificationID:notifyProc:userData = %ld:%ld:%p:%p\n", (long int) mSelfToken, (long int) notificationID, notifyProc, userData);
2380#endif
2381	if (mSourceNotifications == NULL)
2382		return;
2383
2384	mSourceNotifications->RemoveSourceNotification(notificationID, notifyProc, userData);
2385}
2386
2387// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2388#pragma mark ***** Source Spatialization Ext*****
2389// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2390// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2391
2392// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2393OSStatus    OALSource::SetRenderQuality(ALuint inValue)
2394{
2395    OSStatus err = noErr;
2396    if (IsValidRenderQuality(inValue))
2397    {
2398        mRenderQuality = inValue;
2399        UpdateBusRenderQuality();
2400    }
2401    else
2402    {
2403        err = -50; //invalid render quality
2404    }
2405    return err;
2406}
2407
2408ALint       OALSource::GetRenderQuality()
2409{
2410    return mRenderQuality;
2411}
2412
2413// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2414// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2415#pragma mark ***** PRIVATE *****
2416// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2417// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2418
2419// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2420void OALSource::SwapBufferQueues()
2421{
2422#if LOG_VERBOSE
2423	DebugMessageN1("OALSource::SwapBufferQueues called - OALSource = %ld\n", (long int) mSelfToken);
2424#endif
2425	BufferQueue* tQ			= mBufferQueueActive;
2426	mBufferQueueActive		= mBufferQueueInactive;
2427	mBufferQueueInactive	= tQ;
2428
2429	//now that we have swapped, we have to reset the size variables
2430    mBufferQueueActive->SetQueueSize();
2431    mBufferQueueInactive->SetQueueSize();
2432    SetQueueLength();
2433
2434	mBufferQueueActive->ResetBuffers(); 	// mark all the buffers as unprocessed
2435    mCurrentBufferIndex = 0;                // start at the first buffer in the queue
2436    mQueueIsProcessed = false;
2437}
2438
2439// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2440void	OALSource::AddPlaybackMessage(UInt32 inMessage, OALBuffer* inBuffer, UInt32	inNumBuffers)
2441{
2442#if LOG_VERBOSE
2443	DebugMessageN4("OALSource::AddPlaybackMessage called - OALSource:inMessage:inDeferredAppendBuffer:inBuffersToUnqueue = %ld:%ld:%p:%ld\n", (long int) mSelfToken, (long int) inMessage, inDeferredAppendBuffer, (long int) inBuffersToUnqueue);
2444#endif
2445	PlaybackMessage*		pbm = new PlaybackMessage((UInt32) inMessage, inBuffer, inNumBuffers);
2446	mMessageQueue.push_atomic(pbm);
2447}
2448
2449// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2450void	OALSource::ClearMessageQueue()
2451{
2452#if LOG_VERBOSE
2453	DebugMessageN1("OALSource::ClearMessageQueue called - OALSource = %ld\n", (long int) mSelfToken);
2454#endif
2455	PlaybackMessage	*messages = mMessageQueue.pop_all_reversed();
2456	while (messages != NULL)
2457	{
2458		PlaybackMessage	*lastMessage = messages;
2459		messages = messages->next();
2460		delete (lastMessage); // made it, so now get rid of it
2461	}
2462}
2463
2464void	OALSource::SetPlaybackState(ALuint inState, bool sendSourceStateChangeNotification)
2465{
2466#if LOG_VERBOSE
2467	DebugMessageN1("OALSource::SetPlaybackState called - OALSource = %ld\n", (long int) mSelfToken);
2468#endif
2469#if LOG_PLAYBACK
2470    DebugMessageN2("OALSource::SetPlaybackState called - inState = %d - OALSource = %ld", inState, (long int) mSelfToken);
2471#endif
2472	mState = inState;
2473	//sendSourceStateChangeNotification is set to false by default
2474	if (mSourceNotifications && sendSourceStateChangeNotification)
2475		mSourceNotifications->CallSourceNotifications(AL_SOURCE_STATE);
2476}
2477
2478// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2479#pragma mark ***** Buffer Queue Methods *****
2480// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2481
2482void	OALSource::ClearActiveQueue()
2483{
2484#if LOG_VERBOSE
2485	DebugMessageN1("OALSource::ClearActiveQueue called - OALSource = %ld\n", (long int) mSelfToken);
2486#endif
2487	while (mBufferQueueActive->GetQueueSize() > 0)
2488	{
2489		// Get buffer #i from Active List
2490		BufferInfo	*staleBufferInfo = mBufferQueueActive->Get(0);
2491		if (staleBufferInfo)
2492		{
2493			mBufferQueueActive->SetBufferAsProcessed(0);
2494			// Append it to Inactive List
2495			mBufferQueueInactive->AppendBuffer(this, staleBufferInfo->mBufferToken, staleBufferInfo->mBuffer, staleBufferInfo->mACToken);
2496			// Remove it from Active List
2497			mBufferQueueActive->RemoveQueueEntryByIndex(this, 0, false);
2498            SetQueueLength();
2499		}
2500	}
2501
2502	mCurrentBufferIndex = 0;
2503    mQueueIsProcessed = false;
2504}
2505
2506// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2507// this method should only be called when a looping queue reaches it's end and needs to start over (called from render thread)
2508void	OALSource::LoopToBeginning()
2509{
2510#if LOG_VERBOSE
2511	DebugMessageN1("OALSource::LoopToBeginning called - OALSource = %ld\n", (long int) mSelfToken);
2512#endif
2513
2514	ClearActiveQueue();
2515
2516	// swap the list pointers now
2517	SwapBufferQueues();
2518
2519	// Send the notification if necessary
2520	if ((mSourceNotifications) && mLooping)
2521		mSourceNotifications->CallSourceNotifications(AL_QUEUE_HAS_LOOPED);
2522}
2523
2524// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2525// this method should only be called from a non playing state and is used to rejoin the 2 buffer Q lists
2526void	OALSource::JoinBufferLists()
2527{
2528#if LOG_VERBOSE
2529	DebugMessageN1("OALSource::JoinBufferLists called - OALSource = %ld\n", (long int) mSelfToken);
2530#endif
2531
2532	ClearActiveQueue();
2533
2534	// swap the list pointers now
2535	SwapBufferQueues();
2536
2537	return;
2538}
2539
2540// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2541// this is ONLY called from the render thread
2542void OALSource::UpdateQueue ()
2543{
2544#if LOG_VERBOSE
2545	DebugMessageN1("OALSource::UpdateQueue called - OALSource = %ld\n", (long int) mSelfToken);
2546#endif
2547	if (mCurrentBufferIndex > 0)
2548    {
2549		BufferInfo			*bufferInfo = NULL;
2550		for (UInt32 i = 0; i < mCurrentBufferIndex; i++)
2551		{
2552			// Get buffer #i from Active List
2553			bufferInfo = mBufferQueueActive->Get(0);
2554			if (bufferInfo)
2555			{
2556				// Append it to Inactive List
2557				mBufferQueueInactive->AppendBuffer(this, bufferInfo->mBufferToken, bufferInfo->mBuffer, bufferInfo->mACToken);
2558				// Remove it from Active List
2559				mBufferQueueActive->RemoveQueueEntryByIndex(this, 0, false);
2560                SetQueueLength();
2561				if (mSourceNotifications)
2562					mSourceNotifications->CallSourceNotifications(AL_BUFFERS_PROCESSED);
2563			}
2564		}
2565		mCurrentBufferIndex = 0;
2566    }
2567}
2568
2569// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2570bool	OALSource::IsSourceTransitioningToFlushQ()
2571{
2572#if LOG_VERBOSE
2573	DebugMessageN1("OALSource::IsSourceTransitioningToFlushQ called - OALSource = %ld\n", (long int) mSelfToken);
2574#endif
2575	return mTransitioningToFlushQ;
2576}
2577
2578// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2579#pragma mark ***** Mixer Bus Methods *****
2580// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2581void	OALSource::DisconnectFromBus()
2582{
2583#if LOG_VERBOSE
2584	DebugMessageN1("OALSource::DisconnectFromBus called - OALSource = %ld\n", (long int) mSelfToken);
2585#endif
2586	try {
2587		ReleaseNotifyAndRenderProcs();
2588//		OSStatus result = noErr;
2589
2590		// remove the connection between the AUs, if they exist
2591		if(mRogerBeepNode || mDistortionNode)
2592		{
2593			if(mRogerBeepNode && mDistortionNode)
2594				/*result =*/ AUGraphDisconnectNodeInput(mOwningContext->GetGraph(), mRogerBeepNode, 0);
2595			/*result =*/ AUGraphDisconnectNodeInput(mOwningContext->GetGraph(), mOwningContext->GetMixerNode(), mCurrentPlayBus);
2596			/*result =*/ AUGraphUpdate(mOwningContext->GetGraph(), NULL);
2597		}
2598
2599		if (mCurrentPlayBus != kSourceNeedsBus)
2600		{
2601			mOwningContext->SetBusAsAvailable (mCurrentPlayBus);
2602			mCurrentPlayBus = kSourceNeedsBus;
2603		}
2604	}
2605	catch (OSStatus	result) {
2606		// swallow the error
2607	}
2608}
2609
2610// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2611// must be called when the source has a mixer bus
2612void	OALSource::ChangeChannelSettings()
2613{
2614#if LOG_VERBOSE
2615	DebugMessageN1("OALSource::ChangeChannelSettings called - OALSource = %ld\n", (long int) mSelfToken);
2616#endif
2617#if CALCULATE_POSITION
2618
2619//	bool	coneGainChange = false;
2620//	bool	attenuationGainChange = false;
2621
2622	if (mCalculateDistance == true)
2623	{
2624        BufferInfo	*bufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2625		if (bufferInfo)
2626		{
2627#if LOG_GRAPH_AND_MIXER_CHANGES
2628	DebugMessageN1("OALSource::ChangeChannelSettings: k3DMixerParam_Azimuth/k3DMixerParam_Distance called - OALSource = %ld\n", mSelfToken);
2629#endif
2630			// only calculate position if sound is mono - stereo sounds get no location changes
2631			if ( bufferInfo->mBuffer->GetNumberChannels() == 1)
2632			{
2633				Float32 	rel_azimuth, rel_distance, rel_elevation, dopplerShift;
2634
2635				CalculateDistanceAndAzimuth(&rel_distance, &rel_azimuth, &rel_elevation, &dopplerShift);
2636
2637                if (dopplerShift != mDopplerScaler)
2638                {
2639                    mDopplerScaler = dopplerShift;
2640                    mResetPitch = true;
2641                }
2642
2643				// set azimuth
2644				AudioUnitSetParameter(mOwningContext->GetMixerUnit(), k3DMixerParam_Azimuth, kAudioUnitScope_Input, mCurrentPlayBus, rel_azimuth, 0);
2645				// set elevation
2646				AudioUnitSetParameter(mOwningContext->GetMixerUnit(), k3DMixerParam_Elevation, kAudioUnitScope_Input, mCurrentPlayBus, rel_elevation, 0);
2647
2648				mAttenuationGainScaler = 1.0;
2649				if (!mOwningContext->DoSetDistance())
2650				{
2651					AudioUnitSetParameter(mOwningContext->GetMixerUnit(), k3DMixerParam_Distance, kAudioUnitScope_Input, mCurrentPlayBus, mReferenceDistance, 0);///////
2652
2653					// If 1.3-2.1 Mixer AND it's Linear, Exponential DO calculate Gain scaler - DO NOT  set distance
2654					switch (mOwningContext->GetDistanceModel())
2655					{
2656						case AL_LINEAR_DISTANCE:
2657						case AL_LINEAR_DISTANCE_CLAMPED:
2658							if (mOwningContext->GetDistanceModel() == AL_LINEAR_DISTANCE_CLAMPED)
2659							{
2660								if (rel_distance < mReferenceDistance) rel_distance = mReferenceDistance;
2661								if (rel_distance > mMaxDistance) rel_distance = mMaxDistance;
2662							}
2663							mAttenuationGainScaler = (1 - mRollOffFactor * (rel_distance - mReferenceDistance) / (mMaxDistance-mReferenceDistance));
2664							DebugMessageN1("AL_LINEAR_DISTANCE scaler =  %f\n", mAttenuationGainScaler);
2665//							attenuationGainChange = true;
2666							break;
2667
2668						case AL_EXPONENT_DISTANCE:
2669						case AL_EXPONENT_DISTANCE_CLAMPED:
2670							if (mOwningContext->GetDistanceModel() == AL_EXPONENT_DISTANCE_CLAMPED)
2671							{
2672								if (rel_distance < mReferenceDistance) rel_distance = mReferenceDistance;
2673								if (rel_distance > mMaxDistance) rel_distance = mMaxDistance;
2674							}
2675							mAttenuationGainScaler = pow((rel_distance / mReferenceDistance), (-mRollOffFactor));
2676							DebugMessageN1("AL_EXPONENT_DISTANCE scaler =  %f\n", mAttenuationGainScaler);
2677//							attenuationGainChange = true;
2678							break;
2679
2680						case AL_NONE:
2681							mAttenuationGainScaler = 1.0;
2682							break;	// nothing to do
2683					}
2684				}
2685				else
2686				{
2687					// if 2.0 and Inverse, SCALE before setting distance
2688					if (mOwningContext->IsDistanceScalingRequired())	// only true for 2.0 mixer doing inverse curve
2689						rel_distance *= (kDistanceScalar/mMaxDistance);
2690
2691					// set distance
2692					AudioUnitSetParameter(mOwningContext->GetMixerUnit(), k3DMixerParam_Distance, kAudioUnitScope_Input, mCurrentPlayBus, rel_distance, 0);
2693				}
2694
2695				// Source Cone Support Here
2696				/*coneGainChange =*/ ConeAttenuation();
2697			}
2698		}
2699
2700		mCalculateDistance = false;
2701	}
2702
2703#endif	// end CALCULATE_POSITION
2704
2705	UpdateBusGain();
2706
2707	SetPitch (mPitch);
2708    UpdateBusFormat();
2709}
2710
2711// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2712void	OALSource::UpdateBusGain ()
2713{
2714#if LOG_VERBOSE
2715	DebugMessageN1("OALSource::UpdateBusGain called - OALSource = %ld\n", (long int) mSelfToken);
2716#endif
2717	if (mCurrentPlayBus != kSourceNeedsBus)
2718	{
2719		Float32		busGain = mGain;
2720
2721		busGain *= mConeGainScaler;
2722		busGain *= mAttenuationGainScaler;
2723
2724		// clamp the gain used to 0.0-1.0
2725        if (busGain > 1.0)
2726			busGain = 1.0;
2727		else if (busGain < 0.0)
2728			busGain = 0.0;
2729
2730		mOutputSilence = busGain > 0.0 ? false : true;
2731
2732		if (busGain > 0.0)
2733		{
2734			Float32	db = 20.0 * log10(busGain); 	// convert to db
2735			if (db < -120.0)
2736				db = -120.0;						// clamp minimum audible level at -120db
2737
2738//#if LOG_GRAPH_AND_MIXER_CHANGES
2739//	DebugMessageN3("OALSource::UpdateBusGain: k3DMixerParam_Gain called - OALSource:busGain:db = %ld:%f:%f\n", mSelfToken, busGain, db );
2740//#endif
2741
2742			OSStatus	result = AudioUnitSetParameter (	mOwningContext->GetMixerUnit(), k3DMixerParam_Gain, kAudioUnitScope_Input, mCurrentPlayBus, db, 0);
2743				THROW_RESULT
2744		}
2745	}
2746}
2747
2748// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2749void	OALSource::UpdateMinBusGain ()
2750{
2751#if VERBOSE
2752	DebugMessageN1("OALSource::UpdateMinBusGain called - OALSource = %ld", (long int) mSelfToken);
2753#endif
2754	if (mCurrentPlayBus != kSourceNeedsBus)
2755	{
2756		OSStatus	result = AudioUnitSetParameter (	mOwningContext->GetMixerUnit(), k3DMixerParam_MinGain, kAudioUnitScope_Input, mCurrentPlayBus, mMinGain, 0);
2757            THROW_RESULT
2758	}
2759}
2760
2761// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2762void	OALSource::UpdateMaxBusGain ()
2763{
2764#if VERBOSE
2765	DebugMessageN1("OALSource::UpdateMaxBusGain called - OALSource = %ld", (long int) mSelfToken);
2766#endif
2767	if (mCurrentPlayBus != kSourceNeedsBus)
2768	{
2769		OSStatus	result = AudioUnitSetParameter (	mOwningContext->GetMixerUnit(), k3DMixerParam_MaxGain, kAudioUnitScope_Input, mCurrentPlayBus, mMaxGain, 0);
2770        THROW_RESULT
2771	}
2772}
2773
2774// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2775void	OALSource::UpdateBusFormat ()
2776{
2777#if LOG_VERBOSE
2778		DebugMessageN1("OALSource::UpdateBusFormat - OALSource = %ld\n", (long int) mSelfToken);
2779#endif
2780
2781 	if (Get3DMixerVersion() < k3DMixerVersion_2_0)	// the pre-2.0 3DMixer cannot change stream formats once initialized
2782		return;
2783
2784    if (mResetBusFormat)
2785    {
2786        CAStreamBasicDescription    desc;
2787        UInt32  propSize = sizeof(desc);
2788        OSStatus result = AudioUnitGetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, mCurrentPlayBus, &desc, &propSize);
2789        if (result == noErr)
2790        {
2791            BufferInfo	*buffer = mBufferQueueActive->Get(mCurrentBufferIndex);
2792            if (buffer != NULL)
2793            {
2794                desc.mSampleRate = buffer->mBuffer->GetSampleRate();
2795                AudioUnitSetProperty(mOwningContext->GetMixerUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, mCurrentPlayBus, &desc, sizeof(desc));
2796                mResetBusFormat = false;
2797            }
2798        }
2799    }
2800}
2801
2802// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2803void	OALSource::UpdateBusRenderQuality ()
2804{
2805#if LOG_VERBOSE
2806    DebugMessageN1("OALSource::UpdateBusRenderQuality - OALSource = %ld\n", (long int) mSelfToken);
2807#endif
2808
2809	if (mCurrentPlayBus != kSourceNeedsBus)
2810	{
2811		mOwningContext->SetSourceDesiredRenderQualityOnBus(mRenderQuality, mCurrentPlayBus);
2812	}
2813}
2814
2815// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2816void	OALSource::UpdateBusReverb ()
2817{
2818#if LOG_VERBOSE
2819        DebugMessageN1("OALSource::UpdateBusReverb - OALSource = %ld\n", (long int) mSelfToken);
2820#endif
2821
2822	if (mCurrentPlayBus != kSourceNeedsBus)
2823	{
2824		if (mOwningContext->GetReverbState() == 0)	// either reverb is off or not available on this system
2825			return;
2826
2827		AudioUnitSetParameter(mOwningContext->GetMixerUnit(), 5 /*k3DMixerParam_ReverbBlend*/, kAudioUnitScope_Input, mCurrentPlayBus, mASAReverbSendLevel * 100.0, 0);
2828	}
2829}
2830
2831// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2832void	OALSource::UpdateBusOcclusion ()
2833{
2834#if LOG_VERBOSE
2835        DebugMessageN1("OALSource::UpdateBusOcclusion - OALSource = %ld\n", (long int) mSelfToken);
2836#endif
2837
2838	if (mCurrentPlayBus != kSourceNeedsBus)
2839	{
2840		if (Get3DMixerVersion() < k3DMixerVersion_2_2)	// the pre-2.2 3DMixer does not have occlusion
2841			return;
2842
2843		AudioUnitSetParameter(mOwningContext->GetMixerUnit(), 7 /*k3DMixerParam_OcclusionAttenuation*/, kAudioUnitScope_Input, mCurrentPlayBus, mASAOcclusion, 0);
2844	}
2845}
2846
2847// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2848void	OALSource::UpdateBusObstruction ()
2849{
2850#if LOG_VERBOSE
2851        DebugMessageN1("OALSource::UpdateBusObstruction - OALSource = %ld\n", (long int) mSelfToken);
2852#endif
2853
2854	if (mCurrentPlayBus != kSourceNeedsBus)
2855	{
2856		if (Get3DMixerVersion() < k3DMixerVersion_2_2)	// the pre-2.2 3DMixer does not have obstruction
2857			return;
2858
2859		AudioUnitSetParameter(mOwningContext->GetMixerUnit(), 8 /*k3DMixerParam_ObstructionAttenuation*/, kAudioUnitScope_Input, mCurrentPlayBus, mASAObstruction, 0);
2860	}
2861}
2862
2863// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2864#pragma mark ***** Render Proc Methods *****
2865// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2866void	OALSource::AddNotifyAndRenderProcs()
2867{
2868#if LOG_VERBOSE
2869    DebugMessageN1("OALSource::AddNotifyAndRenderProcs - OALSource = %ld\n", (long int) mSelfToken);
2870#endif
2871	if (mCurrentPlayBus == kSourceNeedsBus)
2872		return;
2873
2874	OSStatus	result = noErr;
2875
2876	mPlayCallback.inputProc = SourceInputProc;
2877	mPlayCallback.inputProcRefCon = this;
2878	result = AudioUnitSetProperty (	mRenderUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
2879							mRenderElement, &mPlayCallback, sizeof(mPlayCallback));
2880			THROW_RESULT
2881}
2882
2883// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2884void	OALSource::ReleaseNotifyAndRenderProcs()
2885{
2886#if LOG_VERBOSE
2887    DebugMessageN1("OALSource::ReleaseNotifyAndRenderProcs - OALSource = %ld\n", (long int) mSelfToken);
2888#endif
2889	OSStatus	result = noErr;
2890
2891	mPlayCallback.inputProc = 0;
2892	mPlayCallback.inputProcRefCon = 0;
2893
2894	result = AudioUnitSetProperty (	mRenderUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
2895							mRenderElement, &mPlayCallback, sizeof(mPlayCallback));
2896		THROW_RESULT
2897}
2898
2899// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2900#if USE_AU_TRACER
2901static UInt32 tracerStart = 0xca3d0000;
2902static UInt32 tracerEnd = 0xca3d0004;
2903#include <sys/syscall.h>
2904#include <unistd.h>
2905#endif
2906OSStatus	OALSource::SourceInputProc (	void 						*inRefCon,
2907											AudioUnitRenderActionFlags 	*inActionFlags,
2908											const AudioTimeStamp 		*inTimeStamp,
2909											UInt32 						inBusNumber,
2910											UInt32 						inNumberFrames,
2911											AudioBufferList 			*ioData)
2912{
2913#if LOG_VERBOSE
2914    DebugMessage("OALSource::ReleaseNotifyAndRenderProcs");
2915#endif
2916	OALSource* THIS = (OALSource*)inRefCon;
2917
2918	THIS->SetInUseFlag();
2919
2920	if (THIS->mOutputSilence)
2921		*inActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
2922	else
2923		*inActionFlags &= 0xEF; // the mask for the kAudioUnitRenderAction_OutputIsSilence bit
2924
2925#if USE_AU_TRACER
2926	syscall(180, tracerStart, inBusNumber, ioData->mNumberBuffers, 0, 0);
2927#endif
2928
2929	OSStatus result = noErr;
2930    if (Get3DMixerVersion() >= k3DMixerVersion_2_0)
2931        result = THIS->DoRender (ioData);       // normal case
2932    else
2933        result = THIS->DoSRCRender (ioData);    // pre 2.0 mixer case
2934
2935#if USE_AU_TRACER
2936	syscall(180, tracerEnd, inBusNumber, ioData->mNumberBuffers, 0, 0);
2937#endif
2938
2939	THIS->ClearInUseFlag();
2940
2941	return (result);
2942}
2943
2944// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2945OSStatus OALSource::DoPreRender ()
2946{
2947#if LOG_VERBOSE
2948    DebugMessageN1("OALSource::DoPreRender - OALSource = %ld\n", (long int) mSelfToken);
2949#endif
2950	BufferInfo	*bufferInfo = NULL;
2951	OSStatus	err = noErr;
2952
2953	OALRenderLocker::RenderTryer tried(mRenderLocker);
2954
2955	if (!tried.Acquired())
2956		return err;
2957
2958	bufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
2959	if (bufferInfo == NULL)
2960    {
2961        // if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
2962		mQueueIsProcessed = true;
2963        err = -1;	// there are no buffers
2964    }
2965
2966	return (err);
2967}
2968
2969// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2970OSStatus OALSource::ACComplexInputDataProc	(	AudioConverterRef				inAudioConverter,
2971												UInt32							*ioNumberDataPackets,
2972												AudioBufferList					*ioData,
2973												AudioStreamPacketDescription	**outDataPacketDescription,
2974												void*							inUserData)
2975{
2976#if LOG_VERBOSE
2977    DebugMessage("OALSource::DoPreRender - OALSource = %ld\n");
2978#endif
2979	OSStatus		err = noErr;
2980	OALSource* 		THIS = (OALSource*)inUserData;
2981    BufferInfo		*bufferInfo = THIS->mBufferQueueActive->Get(THIS->mCurrentBufferIndex);
2982    UInt32			sourcePacketsLeft = 0;
2983
2984	if (bufferInfo == NULL)
2985	{
2986		ioData->mBuffers[0].mData = NULL;				// return nothing
2987		ioData->mBuffers[0].mDataByteSize = 0;			// return nothing
2988		*ioNumberDataPackets = 0;
2989		return -1;
2990	}
2991
2992	sourcePacketsLeft = (bufferInfo->mBuffer->GetDataSize() - bufferInfo->mOffset) / bufferInfo->mBuffer->GetBytesPerPacket();
2993
2994    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2995	// BUFFER EMPTY: If the buffer is empty now, decide on returning an error based on what gets played next in the queue
2996	if (sourcePacketsLeft == 0)
2997	{
2998		bufferInfo->mProcessedState = kProcessed;	// this buffer is done
2999		bufferInfo->mOffset = 0;					// will be ready for the next time
3000
3001		THIS->mCurrentBufferIndex++;
3002		BufferInfo	*nextBufferInfo = THIS->NextPlayableBufferInActiveQ();
3003
3004		// see if there is a next buffer or if the queue is looping and should return to the start
3005		if ((nextBufferInfo != NULL) || (THIS->mLooping == true))
3006		{
3007			// either we will loop back to the beginning or will use a new buffer
3008			if (nextBufferInfo == NULL)
3009			{
3010				THIS->LoopToBeginning();
3011			}
3012
3013			err = OALSourceError_CallConverterAgain;
3014		}
3015		else
3016		{
3017			// looping is false and there are no more buffers so we are really out of data
3018			// return what we have and no error, the AC should then be reset in the RenderProc
3019			// and what ever data is in the AC should get returned
3020			THIS->mBufferQueueActive->SetBufferAsProcessed(THIS->mCurrentBufferIndex);
3021			THIS->mQueueIsProcessed = true;		// we are done now, the Q is dry
3022		}
3023
3024		ioData->mBuffers[0].mData = NULL;				// return nothing
3025		ioData->mBuffers[0].mDataByteSize = 0;			// return nothing
3026		*ioNumberDataPackets = 0;
3027	}
3028	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3029	// BUFFER HAS DATA
3030	else
3031	{
3032		// return the entire request or the remainder of the buffer
3033		if (sourcePacketsLeft < *ioNumberDataPackets)
3034			*ioNumberDataPackets = sourcePacketsLeft;
3035
3036		ioData->mBuffers[0].mData = bufferInfo->mBuffer->GetDataPtr() + bufferInfo->mOffset;	// point to the data we are providing
3037		ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets * bufferInfo->mBuffer->GetBytesPerPacket();
3038		bufferInfo->mOffset += ioData->mBuffers[0].mDataByteSize;
3039	}
3040
3041	return (err);
3042}
3043
3044// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3045// Find the next playable buffer in the Active Buffer Q
3046BufferInfo*  OALSource::NextPlayableBufferInActiveQ()// this method updates mCurrentBufferIndex as well
3047{
3048#if LOG_VERBOSE
3049    DebugMessageN1("OALSource::NextPlayableBufferInActiveQ - OALSource = %ld\n", (long int) mSelfToken);
3050#endif
3051	// try and walk through the active buffer list
3052	BufferInfo*		bufferInfo = NULL;
3053	bool			done = false;
3054
3055	while (!done)
3056	{
3057		bufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
3058		if (bufferInfo == NULL)
3059		{
3060			done = true;  // there are no more valid buffers in this list
3061        }
3062		else if (bufferInfo->mBufferToken == AL_NONE)
3063		{
3064			// mark as processed
3065			bufferInfo->mProcessedState = kProcessed;	// this buffer is done
3066			mCurrentBufferIndex++;
3067		}
3068		else if (bufferInfo->mBuffer->GetDataPtr() == NULL)
3069		{
3070			// mark as processed
3071			bufferInfo->mProcessedState = kProcessed;	// this buffer is done
3072			mCurrentBufferIndex++;
3073		}
3074		else
3075			return bufferInfo;
3076	}
3077	return NULL;
3078}
3079
3080// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3081OSStatus OALSource::DoRender (AudioBufferList 			*ioData)
3082{
3083    OSStatus   			err = noErr;
3084	UInt32				packetsRequestedFromRenderProc = ioData->mBuffers[0].mDataByteSize / sizeof(Float32);
3085	UInt32				packetsObtained = 0;
3086	UInt32				packetCount;
3087	struct {
3088			AudioBufferList	abl;
3089			AudioBuffer		buffer;
3090	}t;
3091	AudioBufferList	*	tBufferList = (AudioBufferList	*) &t.abl;
3092	UInt32				dataByteSize = ioData->mBuffers[0].mDataByteSize;
3093	BufferInfo			*bufferInfo = NULL;
3094
3095	tBufferList->mNumberBuffers = ioData->mNumberBuffers;
3096	// buffer 1
3097	tBufferList->mBuffers[0].mNumberChannels = ioData->mBuffers[0].mNumberChannels;
3098	tBufferList->mBuffers[0].mDataByteSize = ioData->mBuffers[0].mDataByteSize;
3099	tBufferList->mBuffers[0].mData = ioData->mBuffers[0].mData;
3100	if (tBufferList->mNumberBuffers > 1)
3101	{
3102		// buffer 2
3103		tBufferList->mBuffers[1].mNumberChannels = ioData->mBuffers[1].mNumberChannels;
3104		tBufferList->mBuffers[1].mDataByteSize = ioData->mBuffers[1].mDataByteSize;
3105		tBufferList->mBuffers[1].mData = ioData->mBuffers[1].mData;
3106	}
3107
3108	OALRenderLocker::RenderTryer tried(mRenderLocker);
3109
3110	if (!tried.Acquired())
3111	{
3112		// source is being edited. can't render, so the ioData buffers must be cleared out
3113		for (UInt32	i = 0; i < ioData->mNumberBuffers; i++)
3114			memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
3115		return noErr;
3116	}
3117
3118    //the bus attached to a source is reset whenever the source is played from an initial or stopped state
3119	if(mResetBus)
3120	{
3121		ResetMixerBus();
3122		mResetBus = false;
3123	}
3124
3125	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3126	// 1st move past any AL_NONE Buffers
3127
3128	// update the Q lists before returning any data
3129	UpdateQueue();
3130
3131    // if there are no more buffers in the active Q, go back to the beginning if in Loop mode, else pad zeroes and clean up in the PostRender proc
3132	bufferInfo = NextPlayableBufferInActiveQ();	// this method updates mCurrentBufferIndex as well
3133
3134	if ((bufferInfo == NULL) && (mLooping == true))
3135	{
3136		// swap the list pointers now
3137		SwapBufferQueues();
3138		bufferInfo = NextPlayableBufferInActiveQ();	// this method updates mCurrentBufferIndex as well
3139		if (bufferInfo == NULL)
3140			goto Finished;	// there are no buffers
3141
3142		// Send the notification if necessary
3143		if (mSourceNotifications)
3144			mSourceNotifications->CallSourceNotifications(AL_QUEUE_HAS_LOOPED);
3145	}
3146	else if (bufferInfo == NULL)
3147    {
3148        // if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
3149        mQueueIsProcessed = true;
3150        // stop rendering, there is no more data
3151        goto Finished;	// there are no buffers
3152    }
3153
3154    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3155
3156	ChangeChannelSettings();
3157
3158    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3159
3160	// walk through as many buffers as needed to satisfy the request AudioConverterFillComplexBuffer will
3161	// get called each time the data format changes until enough packets have been obtained or the q is empty.
3162	while ((packetsObtained < packetsRequestedFromRenderProc) && (mQueueIsProcessed == false))
3163	{
3164		BufferInfo	*bufferInfo = NextPlayableBufferInActiveQ();	// this method updates mCurrentBufferIndex as well
3165		if (bufferInfo == NULL)
3166		{
3167            // just zero out the remainder of the buffer
3168			// if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
3169            mQueueIsProcessed = true;
3170            goto Finished;
3171        }
3172
3173		bufferInfo->mProcessedState = kInProgress;
3174		// buffer 1
3175		UInt32	byteCount = packetsObtained * sizeof(Float32);
3176		tBufferList->mBuffers[0].mDataByteSize = dataByteSize - byteCount;
3177		tBufferList->mBuffers[0].mData = (Byte *) ioData->mBuffers[0].mData + byteCount;
3178		if (tBufferList->mNumberBuffers > 1)
3179		{
3180			// buffer 2
3181			tBufferList->mBuffers[1].mDataByteSize = tBufferList->mBuffers[0].mDataByteSize;
3182			tBufferList->mBuffers[1].mData = (Byte *) ioData->mBuffers[1].mData + byteCount;
3183		}
3184
3185		if (bufferInfo->mBuffer->HasBeenConverted() == false)
3186		{
3187			// CONVERT THE BUFFER DATA
3188			AudioConverterRef	converter = mACMap->Get(bufferInfo->mACToken);
3189
3190			packetCount = packetsRequestedFromRenderProc - packetsObtained;
3191			// if OALSourceError_CallConverterAgain is returned, there is nothing to do, just go around again and try and get the data
3192			err = AudioConverterFillComplexBuffer(converter, ACComplexInputDataProc, this, &packetCount, tBufferList, NULL);
3193			packetsObtained += packetCount;
3194
3195			if (mQueueIsProcessed == true)
3196			{
3197				AudioConverterReset(converter);
3198			}
3199			else if ((packetsObtained < packetsRequestedFromRenderProc) && (err == noErr))
3200			{
3201				// we didn't get back what we asked for, but no error implies we have used up the data of this format
3202				// so reset this converter so it will be ready for the next time
3203				AudioConverterReset(converter);
3204            }
3205        }
3206		else
3207		{
3208			// Data has already been converted to the mixer's format, so just do a copy (should be mono only)
3209			UInt32	bytesRemaining = bufferInfo->mBuffer->GetDataSize() - bufferInfo->mOffset;
3210			UInt32	framesRemaining = bytesRemaining / sizeof(Float32);
3211			UInt32	bytesToCopy = 0;
3212			UInt32	framesToCopy = packetsRequestedFromRenderProc - packetsObtained;
3213
3214			if (framesRemaining < framesToCopy)
3215				framesToCopy = framesRemaining;
3216
3217			bytesToCopy = framesToCopy * sizeof(Float32);
3218			// we're in a mono only case, so only copy the first buffer
3219			memcpy(tBufferList->mBuffers->mData, bufferInfo->mBuffer->GetDataPtr() + bufferInfo->mOffset, bytesToCopy);
3220			bufferInfo->mOffset += bytesToCopy;
3221			packetsObtained += framesToCopy;
3222
3223			// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3224			// this block of code is the same as that found in the fill proc -
3225			// it is for determining what to do when a buffer runs out of data
3226
3227			if (bufferInfo->mOffset == bufferInfo->mBuffer->GetDataSize())
3228			{
3229				mCurrentBufferIndex++;
3230				// see if there is a next buffer or if the queue is looping and should return to the start
3231				BufferInfo	*nextBufferInfo = NextPlayableBufferInActiveQ();	// this method updates mCurrentBufferIndex as well
3232				if ((nextBufferInfo != NULL) || (mLooping == true))
3233				{
3234					if (nextBufferInfo == NULL)
3235						LoopToBeginning();
3236				}
3237				else
3238				{
3239					// looping is false and there are no more buffers so we are really out of data
3240					// return what we have and no error
3241					// if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
3242					mQueueIsProcessed = true;		// we are done now, the Q is dry
3243				}
3244				// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3245			}
3246		}
3247	}
3248
3249Finished:
3250
3251	// if there wasn't enough data left, be sure to silence the end of the buffers
3252	if (packetsObtained < packetsRequestedFromRenderProc)
3253	{
3254		UInt32	byteCount = packetsObtained * sizeof(Float32);
3255		tBufferList->mBuffers[0].mDataByteSize = dataByteSize - byteCount;
3256		tBufferList->mBuffers[0].mData = (Byte *) ioData->mBuffers[0].mData + byteCount;
3257		memset(tBufferList->mBuffers[0].mData, 0, tBufferList->mBuffers[0].mDataByteSize);
3258		if (tBufferList->mNumberBuffers > 1)
3259		{
3260			tBufferList->mBuffers[1].mDataByteSize = tBufferList->mBuffers[0].mDataByteSize;
3261			tBufferList->mBuffers[1].mData = (Byte *) ioData->mBuffers[1].mData + byteCount;
3262			memset(tBufferList->mBuffers[1].mData, 0, tBufferList->mBuffers[1].mDataByteSize);
3263		}
3264	}
3265
3266	// ramp the buffer up or down to avoid any clicking
3267	if (mRampState == kRampDown)
3268	{
3269		// ramp down these samples to avoid any clicking - this is the last buffer before disconnecting in Post Render
3270		RampDown(ioData);
3271		mRampState = kRampingComplete;
3272	}
3273	else if (mRampState == kRampUp)
3274	{
3275		// this is the first buffer since resuming, so ramp these samples up
3276		RampUp(ioData);
3277		mRampState = kRampingComplete;
3278	}
3279
3280	return (noErr);
3281}
3282
3283// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3284OSStatus OALSource::DoPostRender ()
3285{
3286    bool				renderProcsRemoved = false;
3287	PlaybackMessage*	lastMessage;
3288
3289	OALRenderLocker::RenderTryer tried(mRenderLocker);
3290
3291	if (!tried.Acquired())
3292		return noErr;
3293
3294	try {
3295		// all messages must be executed after the last buffer has been ramped down
3296		if (mRampState == kRampingComplete)
3297		{
3298#if	LOG_MESSAGE_QUEUE
3299			DebugMessageN1("FLUSHING MESSAGE QUEUE START - OALSource = %ld", (long int) mSelfToken);
3300#endif
3301			PlaybackMessage	*messages = mMessageQueue.pop_all_reversed();
3302			while (messages != NULL)
3303			{
3304				switch (messages->mMessageID)
3305				{
3306					case kMQ_Stop:
3307#if	LOG_MESSAGE_QUEUE
3308						DebugMessage("     MQ:kMQ_Stop");
3309#endif
3310						if (mState != AL_STOPPED)
3311						{
3312							DisconnectFromBus();
3313							SetPlaybackState(AL_STOPPED, true);
3314							UInt32	count = mBufferQueueActive->GetQueueSize();
3315
3316							ClearActiveQueue();
3317							if((count > 0) && mSourceNotifications)
3318							{
3319								// since there were still pending buffers in the active queue, moving to stopped means there was
3320								// a change in buffers processed, and need for notification
3321								mSourceNotifications->CallSourceNotifications(AL_BUFFERS_PROCESSED);
3322							}
3323						}
3324						break;
3325
3326					case kMQ_Retrigger:
3327#if	LOG_MESSAGE_QUEUE
3328						DebugMessage("     MQ:kMQ_Retrigger");
3329#endif
3330						LoopToBeginning();
3331						if (renderProcsRemoved)
3332						{
3333							AddNotifyAndRenderProcs();
3334							renderProcsRemoved = false;
3335						}
3336
3337						// in case it was also paused while processing these Q commands
3338						if (mState != AL_PLAYING) {
3339							SetPlaybackState(AL_PLAYING, true);
3340						}
3341
3342						break;
3343
3344					case kMQ_Rewind:
3345#if	LOG_MESSAGE_QUEUE
3346						DebugMessage("     MQ:kMQ_Rewind");
3347#endif
3348						if (mState != AL_INITIAL)
3349						{
3350							JoinBufferLists();
3351							DisconnectFromBus();
3352							SetPlaybackState(AL_INITIAL, true);
3353							mQueueIsProcessed = false;
3354						}
3355						break;
3356
3357
3358					case kMQ_ClearBuffersFromQueue:
3359#if	LOG_MESSAGE_QUEUE
3360						DebugMessage("     MQ:kMQ_ClearBuffersFromQueue");
3361#endif
3362						// when unqueue buffers is called while a source is in transition, the action must be deferred so the audio data can finish up
3363						PostRenderRemoveBuffersFromQueue(messages->mNumBuffers);
3364						break;
3365
3366                    case kMQ_AddBuffersToQueue:
3367#if	LOG_MESSAGE_QUEUE
3368                        DebugMessageN1("     MQ:kMQ_AddBuffersToQueue: mBuffer->GetToken() = %ld", (long int) messages->mBuffer->GetToken());
3369#endif
3370                        //when queue buffers is called while a source is in transition, the action must be deferred so the audio data can finish up
3371                        PostRenderAddBuffersToQueue(messages->mNumBuffers);
3372                        mRampState = kNoRamping;
3373                        break;
3374
3375					case kMQ_SetBuffer:
3376#if	LOG_MESSAGE_QUEUE
3377						DebugMessageN1("     MQ:kMQ_SetBuffer: mAppendBuffer->GetToken() = %ld", (long int) messages->mAppendBuffer->GetToken());
3378#endif
3379						PostRenderSetBuffer(messages->mBuffer->GetToken(), messages->mBuffer);
3380						SetPlaybackState(AL_STOPPED, true);
3381						break;
3382
3383					case kMQ_Play:
3384#if	LOG_MESSAGE_QUEUE
3385						DebugMessage("     MQ:kMQ_Play");
3386#endif
3387						Play();
3388						break;
3389
3390					case kMQ_Pause:
3391#if	LOG_MESSAGE_QUEUE
3392						DebugMessage("     MQ:kMQ_Pause");
3393#endif
3394						SetPlaybackState(AL_PAUSED, true);
3395						ReleaseNotifyAndRenderProcs();
3396						renderProcsRemoved = true;
3397						break;
3398
3399                    case kMQ_Resume:
3400#if	LOG_MESSAGE_QUEUE
3401						DebugMessage("     MQ:kMQ_Pause");
3402#endif
3403                        if (mRampState != kRampingComplete)
3404                            mRampState = kRampUp;
3405                        AddNotifyAndRenderProcs();
3406                        SetPlaybackState(AL_PLAYING,true);
3407                        break;
3408
3409					case kMQ_SetFramePosition:
3410#if	LOG_MESSAGE_QUEUE
3411						DebugMessage("     MQ:kMQ_SetFramePosition");
3412#endif
3413						// Rewind the Buffer Q
3414						LoopToBeginning();
3415						AdvanceQueueToFrameIndex(mPlaybackHeadPosition);
3416						mPlaybackHeadPosition = 0;
3417						break;
3418
3419					case kMQ_DeconstructionStop:
3420					{
3421#if	LOG_MESSAGE_QUEUE
3422						DebugMessage("     MQ:kMQ_DeconstructionStop");
3423#endif
3424						DisconnectFromBus();
3425						SetPlaybackState(AL_STOPPED, true);
3426						FlushBufferQueue();				// release attachement to any buffers
3427						mSafeForDeletion = true;		// now the CleanUp Sources method of the context can safely delete this object
3428
3429						// before returning, delete all remaining messages on the queue so they do not get leaked when the object is deconstructed
3430						ClearMessageQueue();
3431
3432						goto Finished;					// skip any remaining MQ messages
3433					}
3434
3435                    default:
3436#if	LOG_MESSAGE_QUEUE
3437						DebugMessage("     MQ:WARNING - UNIMPLEMENTED MESSAGE...");
3438#endif
3439                        break;
3440				}
3441
3442				lastMessage = messages;
3443				messages = messages->next();
3444				delete (lastMessage); // made it, so now get rid of it
3445			}
3446			mRampState = kNoRamping;
3447#if	LOG_MESSAGE_QUEUE
3448			DebugMessageN1("FLUSHING MESSAGE QUEUE END - OALSource = %ld", (long int) mSelfToken);
3449#endif
3450		}
3451
3452Finished:
3453
3454		if (mQueueIsProcessed)
3455		{
3456			// this means that the data ran out on it's own and we are not stopped as a result of a queued message
3457			DisconnectFromBus();
3458			SetPlaybackState(AL_STOPPED,true);
3459			UInt32	count = mBufferQueueActive->GetQueueSize();
3460			ClearActiveQueue();
3461
3462			if((count > 0) && mSourceNotifications)
3463			{
3464				// since there were still pending buffers in the active queue, moving to stopped means there was
3465				// a change in buffers processed, and need for notification
3466				mSourceNotifications->CallSourceNotifications(AL_BUFFERS_PROCESSED);
3467			}
3468		}
3469	}
3470	catch(...){
3471		DebugMessageN1("OALSource::DoPostRender:ERROR - OALSource = %ld", (long int)  mSelfToken);
3472	}
3473
3474	return noErr;
3475}
3476
3477// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3478void OALSource::RampDown (AudioBufferList 			*ioData)
3479{
3480#if LOG_VERBOSE
3481    DebugMessageN1("OALSource::RampDown - OALSource = %ld\n", (long int) mSelfToken);
3482#endif
3483	UInt32		sampleCount = (ioData->mBuffers[0].mDataByteSize / sizeof (Float32));
3484
3485	Float32		slope = 1.0/sampleCount;
3486	for (UInt32	i = 0; i < ioData->mNumberBuffers; i++)
3487	{
3488		Float32		scalar = 1.0;
3489		Float32		*sample = (Float32*) ioData->mBuffers[i].mData;
3490		for (UInt32	count = sampleCount; count > 0 ; count--)
3491		{
3492			*sample *= scalar;
3493			scalar -= slope;
3494			sample++;
3495		}
3496	}
3497}
3498
3499// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3500void OALSource::RampUp (AudioBufferList 			*ioData)
3501{
3502#if LOG_VERBOSE
3503    DebugMessageN1("OALSource::RampUp - OALSource = %ld\n", (long int) mSelfToken);
3504#endif
3505	UInt32		sampleCount = (ioData->mBuffers[0].mDataByteSize / sizeof (Float32));
3506
3507	Float32		slope = 1.0/sampleCount;
3508	for (UInt32	i = 0; i < ioData->mNumberBuffers; i++)
3509	{
3510		Float32		scalar = 0.0;
3511		Float32		*sample = (Float32*) ioData->mBuffers[i].mData;
3512		for (UInt32	count = sampleCount; count > 0 ; count--)
3513		{
3514			*sample *= scalar;
3515			scalar += slope;
3516			sample++;
3517		}
3518	}
3519}
3520
3521// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3522// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3523// Support for Pre 2.0 3DMixer
3524//
3525// Pull the audio data by using DoRender(), and then Sample Rate Convert it to the mixer's
3526// output sample rate so the 1.3 mixer doesn't have to do any SRC.
3527// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3528// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3529
3530OSStatus	OALSource::DoSRCRender(	AudioBufferList 			*ioData )
3531{
3532#if LOG_VERBOSE
3533    DebugMessageN1("OALSource::DoSRCRender - OALSource = %ld\n", (long int) mSelfToken);
3534#endif
3535	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3536	BufferInfo	*bufferInfo = NULL;
3537
3538	OALRenderLocker::RenderTryer tried(mRenderLocker);
3539
3540	if (!tried.Acquired())
3541	{
3542		// source is being edited. can't render, so the ioData buffers must be cleared out
3543		for (UInt32	i = 0; i < ioData->mNumberBuffers; i++)
3544			memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
3545
3546		return noErr;
3547	}
3548
3549    //the bus attached to a source is reset whenever the source is played from an initial or stopped state
3550	if(mResetBus)
3551	{
3552		ResetMixerBus();
3553		mResetBus = false;
3554	}
3555
3556	// 1st move past any AL_NONE Buffers
3557	bufferInfo = NextPlayableBufferInActiveQ();
3558	if (bufferInfo == NULL)
3559	{
3560		// if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
3561		mQueueIsProcessed = true;
3562		return -1;	// there are no more buffers
3563	}
3564
3565	// update the Q lists before returning any data
3566	UpdateQueue();
3567
3568    // if there are no more buffers in the active Q, go back to the beginning if in Loop mode, else pad zeroes and clean up in the PostRender proc
3569	bufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
3570	if ((bufferInfo == NULL) && (mLooping == true))
3571	{
3572		// swap the list pointers now
3573		SwapBufferQueues();
3574		if (mSourceNotifications)
3575			mSourceNotifications->CallSourceNotifications(AL_QUEUE_HAS_LOOPED);
3576	}
3577	else if (bufferInfo == NULL)
3578    {
3579        // if there are no messages on the Q by now, then the source will be disconnected and reset in the PostRender Proc
3580        mQueueIsProcessed = true;
3581        // stop rendering, there is no more data
3582        return -1;	// there are no buffers
3583    }
3584
3585    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3586
3587	ChangeChannelSettings();
3588
3589    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3590
3591	double srcSampleRate; srcSampleRate = bufferInfo->mBuffer->GetSampleRate();
3592	double dstSampleRate; dstSampleRate = mOwningContext->GetMixerRate();
3593	double ratio; ratio = (srcSampleRate / dstSampleRate) * mPitch * mDopplerScaler;
3594
3595	int nchannels; nchannels = ioData->mNumberBuffers;
3596
3597	if (ratio == 1.0)
3598	{
3599		// no SRC necessary so just call the normal render proc and let it fill out the buffers
3600        return (DoRender(ioData));
3601 	}
3602
3603	// otherwise continue on to do dirty linear interpolation
3604	UInt32      inFramesToProcess; inFramesToProcess = ioData->mBuffers[0].mDataByteSize / sizeof(Float32);
3605	float readIndex; readIndex = mReadIndex;
3606
3607	int readUntilIndex; readUntilIndex = (int) (2.0 + readIndex + inFramesToProcess * ratio );
3608	int framesToPull; framesToPull = readUntilIndex - 2;
3609
3610	if (framesToPull == 0)
3611        return -1;
3612
3613    // set the buffer size so DoRender will get the correct amount of frames
3614    mTempSourceStorage->mBuffers[0].mDataByteSize = framesToPull * sizeof(UInt32);
3615    mTempSourceStorage->mBuffers[1].mDataByteSize = framesToPull * sizeof(UInt32);
3616
3617    // if the size of the buffers are too small, reallocate them now
3618    if (mTempSourceStorageBufferSize < (framesToPull * sizeof(UInt32)))
3619    {
3620        if (mTempSourceStorage->mBuffers[0].mData != NULL)
3621            free(mTempSourceStorage->mBuffers[0].mData);
3622
3623        if (mTempSourceStorage->mBuffers[1].mData != NULL)
3624            free(mTempSourceStorage->mBuffers[1].mData);
3625
3626        mTempSourceStorageBufferSize = (framesToPull * sizeof(UInt32));
3627        mTempSourceStorage->mBuffers[0].mData = malloc(mTempSourceStorageBufferSize);
3628        mTempSourceStorage->mBuffers[1].mData = malloc(mTempSourceStorageBufferSize);
3629    }
3630
3631	// get input source audio
3632    mTempSourceStorage->mNumberBuffers = ioData->mNumberBuffers;
3633    for (UInt32 i = 0; i < mTempSourceStorage->mNumberBuffers; i++)
3634    {
3635        mTempSourceStorage->mBuffers[i].mDataByteSize = framesToPull * sizeof(UInt32);
3636    }
3637
3638    OSStatus result; result = DoRender(mTempSourceStorage);
3639	if (result != noErr )
3640        return result;		// !!@ something bad happened (could return error code)
3641
3642	float *pullL; pullL = (float *) mTempSourceStorage->mBuffers[0].mData;
3643	float *pullR; pullR = nchannels > 1 ? (float *) mTempSourceStorage->mBuffers[1].mData: NULL;
3644
3645	// setup a small array of the previous two cached values, plus the first new input frame
3646	float tempL[4];
3647	float tempR[4];
3648	tempL[0] = mCachedInputL1;
3649	tempL[1] = mCachedInputL2;
3650	tempL[2] = pullL[0];
3651
3652	if (pullR)
3653	{
3654		tempR[0] = mCachedInputR1;
3655		tempR[1] = mCachedInputR2;
3656		tempR[2] = pullR[0];
3657	}
3658
3659	// in first loop start out getting source from this small array, then change sourceL/sourceR to point
3660	// to the buffers containing the new pulled input for the main loop
3661	float *sourceL; sourceL = tempL;
3662	float *sourceR; sourceR = tempR;
3663	if(!pullR)
3664        sourceR = NULL;
3665
3666	// keep around for next time
3667	mCachedInputL1 = pullL[framesToPull - 2];
3668	mCachedInputL2 = pullL[framesToPull - 1];
3669
3670	if(pullR)
3671	{
3672		mCachedInputR1 = pullR[framesToPull - 2];
3673		mCachedInputR2 = pullR[framesToPull - 1];
3674	}
3675
3676	// quick-and-dirty linear interpolation
3677	int n; n = inFramesToProcess;
3678
3679	float *destL; destL = (float *) ioData->mBuffers[0].mData;
3680	float *destR; destR = (float *) ioData->mBuffers[1].mData;
3681
3682	if (!sourceR)
3683	{
3684		// mono input
3685
3686		// generate output based on previous cached values
3687		while (readIndex < 2.0 &&  n > 0)
3688		{
3689			int iReadIndex = (int)readIndex;
3690			int iReadIndex2 = iReadIndex + 1;
3691
3692			float frac = readIndex - float(iReadIndex);
3693
3694			float s1 = sourceL[iReadIndex];
3695			float s2 = sourceL[iReadIndex2];
3696			float left  = s1 + frac * (s2-s1);
3697
3698			*destL++ = left;
3699
3700			readIndex += ratio;
3701
3702			n--;
3703		}
3704
3705		// generate output based on new pulled input
3706
3707		readIndex -= 2.0;
3708
3709		sourceL = pullL;
3710
3711		while (n--)
3712		{
3713			int iReadIndex = (int)readIndex;
3714			int iReadIndex2 = iReadIndex + 1;
3715
3716			float frac = readIndex - float(iReadIndex);
3717
3718			float s1 = sourceL[iReadIndex];
3719			float s2 = sourceL[iReadIndex2];
3720			float left  = s1 + frac * (s2-s1);
3721
3722			*destL++ = left;
3723
3724			readIndex += ratio;
3725		}
3726
3727		readIndex += 2.0;
3728	}
3729	else
3730	{
3731		// stereo input
3732		// generate output based on previous cached values
3733		while(readIndex < 2.0 &&  n > 0)
3734		{
3735			int iReadIndex = (int)readIndex;
3736			int iReadIndex2 = iReadIndex + 1;
3737
3738			float frac = readIndex - float(iReadIndex);
3739
3740			float s1 = sourceL[iReadIndex];
3741			float s2 = sourceL[iReadIndex2];
3742			float left  = s1 + frac * (s2-s1);
3743
3744			float s3 = sourceR[iReadIndex];
3745			float s4 = sourceR[iReadIndex2];
3746			float right  = s3 + frac * (s4-s3);
3747
3748			*destL++ = left;
3749			*destR++ = right;
3750
3751			readIndex += ratio;
3752
3753			n--;
3754		}
3755
3756		// generate output based on new pulled input
3757
3758		readIndex -= 2.0;
3759
3760		sourceL = pullL;
3761		sourceR = pullR;
3762
3763		while (n--)
3764		{
3765			int iReadIndex = (int)readIndex;
3766			int iReadIndex2 = iReadIndex + 1;
3767
3768			float frac = readIndex - float(iReadIndex);
3769
3770			float s1 = sourceL[iReadIndex];
3771			float s2 = sourceL[iReadIndex2];
3772			float left  = s1 + frac * (s2-s1);
3773
3774			float s3 = sourceR[iReadIndex];
3775			float s4 = sourceR[iReadIndex2];
3776			float right  = s3 + frac * (s4-s3);
3777
3778			*destL++ = left;
3779			*destR++ = right;
3780
3781			readIndex += ratio;
3782		}
3783
3784		readIndex += 2.0;
3785
3786	}
3787
3788	// normalize read index back to start of buffer for next time around...
3789
3790	readIndex -= float(framesToPull);
3791
3792	mReadIndex = readIndex;
3793
3794	return noErr;
3795}
3796
3797// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3798// CalculateDistanceAndAzimuth() support
3799// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3800
3801Float32 MAG(ALfloat *inVector)
3802{
3803	return sqrt(inVector[0] * inVector[0] + inVector[1] * inVector[1] + inVector[2] * inVector[2]);
3804}
3805
3806// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3807void aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector)
3808{
3809	outVector[0]=(inVector1[1]*inVector2[2]-inVector1[2]*inVector2[1]);
3810	outVector[1]=(inVector1[2]*inVector2[0]-inVector1[0]*inVector2[2]);
3811	outVector[2]=(inVector1[0]*inVector2[1]-inVector1[1]*inVector2[0]);
3812}
3813
3814// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3815Float32 aluDotproduct(ALfloat *inVector1,ALfloat *inVector2)
3816{
3817	return (inVector1[0]*inVector2[0]+inVector1[1]*inVector2[1]+inVector1[2]*inVector2[2]);
3818}
3819
3820// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3821void aluNormalize(ALfloat *inVector)
3822{
3823	ALfloat length,inverse_length;
3824
3825	length=(ALfloat)sqrt(aluDotproduct(inVector,inVector));
3826	if (length != 0)
3827	{
3828		inverse_length=(1.0f/length);
3829		inVector[0]*=inverse_length;
3830		inVector[1]*=inverse_length;
3831		inVector[2]*=inverse_length;
3832	}
3833}
3834
3835// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3836void aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3])
3837{
3838	ALfloat result[3];
3839
3840	result[0]=vector[0]*matrix[0][0]+vector[1]*matrix[1][0]+vector[2]*matrix[2][0];
3841	result[1]=vector[0]*matrix[0][1]+vector[1]*matrix[1][1]+vector[2]*matrix[2][1];
3842	result[2]=vector[0]*matrix[0][2]+vector[1]*matrix[1][2]+vector[2]*matrix[2][2];
3843	memcpy(vector,result,sizeof(result));
3844}
3845
3846// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3847inline bool	IsZeroVector(Float32* inVector)
3848{
3849	if ((inVector[0] == 0.0) && (inVector[1] == 0.0) && (inVector[2] == 0.0))
3850		return true;
3851	else
3852		return false;
3853}
3854
3855// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3856#define	LOG_SOURCE_CONES	0
3857bool OALSource::ConeAttenuation()
3858{
3859#if LOG_VERBOSE
3860    DebugMessageN1("OALSource::ConeAttenuation - OALSource = %ld\n", (long int) mSelfToken);
3861#endif
3862	// determine if attenuation  is needed at all
3863	if (	IsZeroVector(mConeDirection)		||
3864			((mConeInnerAngle == 360.0) && (mConeOuterAngle == 360.0))	)
3865	{
3866		// Not Needed if: AL_Direction is 0,0,0, OR if (Inner and Outer Angle are both 360.0)
3867		if (mConeGainScaler != 1.0)
3868		{
3869			// make sure to reset the bus gain if the current cone scaler is not 1.0 and source cone scaling is no longer required
3870			mConeGainScaler = 1.0;
3871			return true;	// let the caller know the bus gain needs resetting
3872		}
3873		return false;	// no change has occurred to require a bus gain reset
3874	}
3875
3876	// Calculate the Source Cone Attenuation scaler
3877
3878	Float32		vsl[3];		// source to listener vector
3879	Float32		coneDirection[3];
3880	Float32		angle;
3881
3882	mOwningContext->GetListenerPosition(&vsl[0], &vsl[1], &vsl[2]);
3883
3884	// calculate the source to listener vector
3885	vsl[0] -= mPosition[0];
3886	vsl[1] -= mPosition[1];
3887	vsl[2] -= mPosition[2];
3888	aluNormalize(vsl);				// Normalized source to listener vector
3889
3890    coneDirection[0] = mConeDirection[0];
3891	coneDirection[1] = mConeDirection[1];
3892	coneDirection[2] = mConeDirection[2];
3893	aluNormalize(coneDirection);	// Normalized cone direction vector
3894
3895	// calculate the angle between the cone direction vector and the source to listener vector
3896	angle = 180.0 * acos (aluDotproduct(vsl, coneDirection))/M_PI; // convert from radians to degrees
3897
3898	Float32		absAngle = fabs(angle);
3899	Float32		absInnerAngle = fabs(mConeInnerAngle)/2.0;	// app provides the size of the entire inner angle
3900	Float32		absOuterAngle = fabs(mConeOuterAngle)/2.0;	// app provides the size of the entire outer angle
3901	Float32		newScaler;
3902
3903	if (absAngle <= absInnerAngle)
3904	{
3905		 // listener is within the inner cone angle, no attenuation required
3906		 newScaler = 1.0;
3907#if LOG_SOURCE_CONES
3908		DebugMessage("ConeAttenuation - Listener is within the inner angle, no Attenuation required");
3909#endif
3910	}
3911	else if (absAngle >= absOuterAngle)
3912	{
3913		 // listener is outside the outer cone angle, sett attenuation to outer cone gain
3914#if LOG_SOURCE_CONES
3915		DebugMessageN1("ConeAttenuation - Listener is outside the outer angle, scaler equals the Outer Cone Gain = %f", mConeOuterGain);
3916#endif
3917		newScaler = mConeOuterGain;
3918	}
3919	else
3920	{
3921		// this source to listener vector is between the inner and outer cone angles so apply some gain scaling
3922		// db or linear?
3923
3924		// as you move from inner to outer, x goes from 0->1
3925		Float32 x =  (absAngle - absInnerAngle ) / (absOuterAngle - absInnerAngle );
3926
3927		newScaler = 1.0/* cone inner gain */ * (1.0 - x)   +    mConeOuterGain * x;
3928#if LOG_SOURCE_CONES
3929		DebugMessageN1("ConeAttenuation - Listener is between inner and outer angles, scaler equals = %f", newScaler);
3930#endif
3931	}
3932
3933	// there is no need to reset the bus gain if the scaler has not changed (a common scenario)
3934	// change is only necessaery when moving around within the transition zone or crossing between inner, transition and outer zones
3935	if (newScaler != mConeGainScaler)
3936	{
3937		mConeGainScaler = newScaler;
3938		return true;	// let the caller know the bus gain needs resetting
3939	}
3940
3941	return false;	// no change has occurred to require a bus gain reset
3942}
3943
3944// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3945void OALSource::CalculateDistanceAndAzimuth(Float32 *outDistance, Float32 *outAzimuth, Float32 *outElevation, Float32	*outDopplerShift)
3946{
3947#if LOG_VERBOSE
3948    DebugMessageN1("OALSource::CalculateDistanceAndAzimuth - OALSource = %ld\n", (long int) mSelfToken);
3949#endif
3950
3951    Float32 	ListenerOrientation[6],
3952                ListenerPosition[3],
3953                ListenerVelocity[3],
3954                Angle = 0.0,
3955                Distance = 2.0,
3956				Elevation = 0.0,
3957                Distance_squared = 4.0,
3958                front_back,
3959                SourceToListener[3],
3960				ProjectedSource[3],
3961				UpProjection,
3962                Look_Norm[3],
3963                RightEarVector[3],  // previously named U
3964				Up[3],
3965                tPosition[3],
3966                dopplerShift = 1.0;     // default at No shift
3967
3968    *outDopplerShift = dopplerShift;    // initialize
3969
3970	SourceToListener[0]=0;		// initialize
3971	SourceToListener[1]=0;		// initialize
3972	SourceToListener[2]=0;		// initialize
3973	Up[0]=0;					// initialize
3974	Up[1]=0;					// initialize
3975	Up[2]=0;					// initialize
3976
3977    tPosition[0] = mPosition[0];
3978	tPosition[1] = mPosition[1];
3979	tPosition[2] = mPosition[2];
3980
3981    //Get listener properties
3982	mOwningContext->GetListenerPosition(&ListenerPosition[0], &ListenerPosition[1], &ListenerPosition[2]);
3983	mOwningContext->GetListenerVelocity(&ListenerVelocity[0], &ListenerVelocity[1], &ListenerVelocity[2]);
3984	mOwningContext->GetListenerOrientation(&ListenerOrientation[0], &ListenerOrientation[1], &ListenerOrientation[2],
3985											&ListenerOrientation[3], &ListenerOrientation[4], &ListenerOrientation[5]);
3986
3987    // Get buffer properties
3988	BufferInfo	*bufferInfo = mBufferQueueActive->Get(mCurrentBufferIndex);
3989	if (bufferInfo == NULL)
3990	{
3991        // Not sure if this should be the error case
3992        *outDistance = 0.0;
3993        *outAzimuth = 0.0;
3994        *outElevation = 0.0;
3995        return;	// there are no buffers
3996	}
3997
3998	// Only apply 3D calculations for mono buffers
3999	if (bufferInfo->mBuffer->GetNumberChannels() == 1)
4000	{
4001		//1. Translate Listener to origin (convert to head relative)
4002		if (mSourceRelative == AL_FALSE)
4003		{
4004			tPosition[0] -= ListenerPosition[0];
4005			tPosition[1] -= ListenerPosition[1];
4006			tPosition[2] -= ListenerPosition[2];
4007		}
4008        //2. Align coordinate system axes
4009        aluCrossproduct(&ListenerOrientation[0],&ListenerOrientation[3],RightEarVector); // Right-ear-vector
4010        aluNormalize(RightEarVector); // Normalized Right-ear-vector
4011        Look_Norm[0] = ListenerOrientation[0];
4012        Look_Norm[1] = ListenerOrientation[1];
4013        Look_Norm[2] = ListenerOrientation[2];
4014        aluNormalize(Look_Norm);
4015
4016       //3. Calculate distance attenuation
4017        Distance_squared = aluDotproduct(tPosition,tPosition);
4018		Distance = sqrt(Distance_squared);
4019
4020        Angle = 0.0f;
4021
4022	  //4. Determine Angle of source relative to listener
4023	  if(Distance>0.0f){
4024		SourceToListener[0]=tPosition[0];
4025		SourceToListener[1]=tPosition[1];
4026		SourceToListener[2]=tPosition[2];
4027		// Note: SourceToListener doesn't need to be normalized here.
4028		// Probably better to move this next line into the Doppler
4029		// calculation code so that it can be optimized away if
4030		// DopplerFactor is 0.
4031		aluNormalize(SourceToListener);
4032
4033		aluCrossproduct(RightEarVector, Look_Norm, Up);
4034		UpProjection = aluDotproduct(SourceToListener,Up);
4035		ProjectedSource[0] = SourceToListener[0] - UpProjection*Up[0];
4036		ProjectedSource[1] = SourceToListener[1] - UpProjection*Up[1];
4037		ProjectedSource[2] = SourceToListener[2] - UpProjection*Up[2];
4038		aluNormalize(ProjectedSource);
4039
4040		Angle = 180.0 * acos (aluDotproduct(ProjectedSource, RightEarVector))/M_PI;
4041		zapBadness(Angle); // remove potential NANs
4042
4043		//is the source infront of the listener or behind?
4044		front_back = aluDotproduct(ProjectedSource,Look_Norm);
4045		if(front_back<0.0f)
4046		  Angle = 360.0f - Angle;
4047
4048		//translate from cartesian angle to 3d mixer angle
4049		if((Angle>=0.0f)&&(Angle<=270.0f))
4050			Angle = 90.0f - Angle;
4051		else
4052			Angle = 450.0f - Angle;
4053	  }
4054
4055        //5. Calculate elevation
4056		Elevation = 90.0 - 180.0 * acos(    aluDotproduct(SourceToListener, Up)   )/ 3.141592654f;
4057		zapBadness(Elevation); // remove potential NANs
4058
4059		if(SourceToListener[0]==0.0 && SourceToListener[1]==0.0 && SourceToListener[2]==0.0 )
4060		   Elevation = 0.0;
4061
4062		if (Elevation > 90.0)
4063			Elevation = 180.0 - Elevation;
4064		if (Elevation < -90.0)
4065			Elevation = -180.0 - Elevation;
4066
4067		//6. Calculate doppler
4068		Float32		dopplerFactor = mOwningContext->GetDopplerFactor();
4069        if (dopplerFactor > 0.0)
4070        {
4071			Float32		speedOfSound = mOwningContext->GetSpeedOfSound();
4072
4073			Float32     SourceVelocity[3];
4074            GetVelocity (SourceVelocity[0], SourceVelocity[1], SourceVelocity[2]);
4075
4076			// don't do all these calculations if the sourec and listener have zero velocity
4077			bool	SourceHasVelocity = !IsZeroVector(SourceVelocity);
4078			bool	ListenerHasVelocity = !IsZeroVector(ListenerVelocity);
4079			if (SourceHasVelocity || ListenerHasVelocity)
4080			{
4081				Float32	NUvls = (aluDotproduct(SourceToListener, ListenerVelocity))/MAG(SourceToListener);
4082				Float32	NUvss = (aluDotproduct(SourceToListener, SourceVelocity))/MAG(SourceToListener);
4083
4084				NUvls = -NUvls; // COMMENT HERE PLEASE
4085				NUvss = -NUvss; // COMMENT HERE PLEASE
4086
4087				NUvls = fmin(NUvls, speedOfSound/dopplerFactor);
4088				NUvss = fmin(NUvss, speedOfSound/dopplerFactor);
4089
4090				dopplerShift = ( (speedOfSound - dopplerFactor * NUvls) / (speedOfSound - dopplerFactor * NUvss)   );
4091				zapBadnessForDopplerShift(dopplerShift); // remove potential NANs
4092
4093				// limit the pitch shifting to 4 octaves up and 3 octaves down
4094				if (dopplerShift > 16.0)
4095					dopplerShift = 16.0;
4096				else if(dopplerShift < 0.125)
4097					dopplerShift = 0.125;
4098
4099				#if LOG_DOPPLER
4100					DebugMessageN1("CalculateDistanceAndAzimuth: dopplerShift after scaling =  %f\n", dopplerShift);
4101				#endif
4102
4103				*outDopplerShift = dopplerShift;
4104			}
4105        }
4106    }
4107    else
4108    {
4109        Angle=0.0;
4110        Distance=0.0;
4111    }
4112
4113	if ((Get3DMixerVersion() < k3DMixerVersion_2_0) && (mReferenceDistance > 1.0))
4114	{
4115        // the pre 2.0 mixer does not have the DistanceParam property so to compensate,
4116        // set the DistanceAtten property correctly for refDist, maxDist, and rolloff,
4117        // and then scale our calculated distance to a reference distance of 1.0 before passing to the mixer
4118        Distance = Distance/mReferenceDistance;
4119        if (Distance > mMaxDistance/mReferenceDistance)
4120            Distance = mMaxDistance/mReferenceDistance; // clamp the distance to the max distance
4121	}
4122
4123    *outDistance = Distance;
4124    *outAzimuth = Angle;
4125    *outElevation = Elevation;
4126}
4127
4128// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4129// Apple Environmental Audio (ASA) Extension
4130// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4131#pragma mark ***** ASA Extension Methods *****
4132void OALSource::SetReverbSendLevel(Float32 inReverbLevel)
4133{
4134#if LOG_VERBOSE
4135    DebugMessageN2("OALSource::SetReverbSendLevel - OALSource:inReverbLevel = %ld:%f\n", (long int) mSelfToken, inReverbLevel);
4136#endif
4137#if LOG_GRAPH_AND_MIXER_CHANGES
4138    DebugMessageN2("OALSource::SetReverbSendLevel - OALSource:inReverbLevel = %ld:%f\n", (long int) mSelfToken, inReverbLevel);
4139#endif
4140
4141	if (inReverbLevel < 0.0f || inReverbLevel > 1.0f)
4142		throw (OSStatus)AL_INVALID_VALUE; // must be within 0.0-1.0 range
4143
4144	// don't allow synchronous source manipulation
4145	CAGuard::Locker sourceLock(mSourceLock);
4146
4147    if (inReverbLevel == mASAReverbSendLevel)
4148		return;			// nothing to do
4149
4150
4151	mASAReverbSendLevel = inReverbLevel;
4152	UpdateBusReverb();
4153}
4154
4155// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4156void	OALSource::SetOcclusion(Float32 inOcclusion)
4157{
4158#if LOG_VERBOSE
4159    DebugMessageN2("OALSource::SetOcclusion - OALSource:inOcclusion = %ld:%f\n", (long int) mSelfToken, inOcclusion);
4160#endif
4161#if LOG_GRAPH_AND_MIXER_CHANGES
4162    DebugMessageN2("OALSource::SetOcclusion - OALSource:inOcclusion = %ld:%f\n", (long int) mSelfToken, inOcclusion);
4163#endif
4164	if (inOcclusion < -100.0f || inOcclusion > 0.0f)
4165		throw (OSStatus)AL_INVALID_VALUE; // must be within -100.0 - 0.0 range
4166
4167    if (inOcclusion == mASAOcclusion)
4168		return;			// nothing to do
4169
4170
4171	mASAOcclusion = inOcclusion;
4172
4173	UpdateBusOcclusion();
4174}
4175
4176// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4177void	OALSource::SetObstruction(Float32 inObstruction)
4178{
4179#if LOG_VERBOSE
4180    DebugMessageN2("OALSource::SetObstruction - OALSource:inObstruction = %ld:%f\n", (long int) mSelfToken, inObstruction);
4181#endif
4182#if LOG_GRAPH_AND_MIXER_CHANGES
4183    DebugMessageN2("OALSource::SetObstruction - OALSource:inObstruction = %ld:%f\n", (long int) mSelfToken, inObstruction);
4184#endif
4185	if (inObstruction < -100.0f || inObstruction > 0.0f)
4186		throw (OSStatus)AL_INVALID_VALUE; // must be within -100.0 - 0.0 range
4187
4188	// don't allow synchronous source manipulation
4189	CAGuard::Locker sourceLock(mSourceLock);
4190
4191    if (inObstruction == mASAObstruction)
4192		return;			// nothing to do
4193
4194	mASAObstruction = inObstruction;
4195
4196	UpdateBusObstruction();
4197}
4198
4199// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4200void	OALSource::SetRogerBeepEnable(Boolean inEnable)
4201{
4202#if LOG_VERBOSE
4203    DebugMessageN2("OALSource::SetRogerBeepEnable - OALSource:inEnable = %ld:%d\n", (long int) mSelfToken, inEnable);
4204#endif
4205#if LOG_GRAPH_AND_MIXER_CHANGES
4206    DebugMessageN2("OALSource::SetRogerBeepEnable - OALSource:inEnable = %ld:%d\n", (long int) mSelfToken, inEnable);
4207#endif
4208
4209	// don't allow synchronous source manipulation
4210	CAGuard::Locker sourceLock(mSourceLock);
4211
4212	// Enable cannot be set during playback
4213	if ((mState == AL_PLAYING) || (mState == AL_PAUSED))
4214		throw (OSStatus) AL_INVALID_OPERATION;
4215
4216    if (inEnable == mASARogerBeepEnable)
4217		return;			// nothing to do
4218
4219	mASARogerBeepEnable = inEnable;
4220
4221	if (mASARogerBeepEnable)
4222	{
4223		SetupRogerBeepAU();
4224
4225		// first get the initial values
4226		UInt32 propSize = sizeof(UInt32);
4227		UInt32 bypassValue;
4228		if(AudioUnitGetProperty(mRogerBeepAU, kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0, &bypassValue, &propSize) == noErr)
4229			mASARogerBeepOn = bypassValue ? 0 : 1;
4230
4231		Float32 paramValue;
4232		if(AudioUnitGetParameter(mRogerBeepAU, 6/*kRogerBeepParam_RogerGain*/, kAudioUnitScope_Global, 0, &paramValue) == noErr)
4233			mASARogerBeepGain = paramValue;
4234
4235		if(AudioUnitGetParameter(mRogerBeepAU, 4/*kRogerBeepParam_Sensitivity*/, kAudioUnitScope_Global, 0, &paramValue) == noErr)
4236			mASARogerBeepSensitivity = (UInt32)paramValue;
4237
4238		if(AudioUnitGetParameter(mRogerBeepAU, 5 /*kRogerBeepParam_RogerType*/, kAudioUnitScope_Global, 0, &paramValue) == noErr)
4239			mASARogerBeepType = (UInt32)paramValue;
4240
4241		//now default the unit off
4242		SetRogerBeepOn(false);
4243	}
4244
4245	else
4246	{
4247		if(mRogerBeepNode)
4248			AUGraphRemoveNode(mOwningContext->GetGraph(), mRogerBeepNode);
4249		mRogerBeepNode = 0;
4250		mRogerBeepAU = 0;
4251	}
4252}
4253
4254// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4255void	OALSource::SetRogerBeepOn(Boolean inOn)
4256{
4257#if LOG_VERBOSE
4258    DebugMessageN2("OALSource::SetRogerBeepOn - OALSource:inOn = %ld:%d\n", (long int) mSelfToken, inOn);
4259#endif
4260#if LOG_GRAPH_AND_MIXER_CHANGES
4261    DebugMessageN2("OALSource::SetRogerBeepOn - OALSource:inOn = %ld:%d\n", (long int) mSelfToken, inOn);
4262#endif
4263
4264	// don't allow synchronous source manipulation
4265	CAGuard::Locker sourceLock(mSourceLock);
4266
4267    if (inOn == mASARogerBeepOn)
4268		return;			// nothing to do
4269
4270	mASARogerBeepOn = inOn;
4271
4272	UInt32 bypassValue = mASARogerBeepOn ? 0 : 1;
4273	AudioUnitSetProperty(mRogerBeepAU, kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0, &bypassValue, sizeof(UInt32));
4274}
4275
4276// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4277void	OALSource::SetRogerBeepGain(Float32 inGain)
4278{
4279#if LOG_VERBOSE
4280    DebugMessageN2("OALSource::SetRogerBeepGain - OALSource:inGain = %ld:%f\n", (long int) mSelfToken, inGain);
4281#endif
4282#if LOG_GRAPH_AND_MIXER_CHANGES
4283    DebugMessageN2("OALSource::SetRogerBeepGain - OALSource:inGain = %ld:%f\n", (long int) mSelfToken, inGain);
4284#endif
4285
4286	if (inGain < -100.0f || inGain > 20.0f)
4287		throw (OSStatus)AL_INVALID_VALUE; // must be within -100.0 - 20.0 range
4288
4289	if(!mASARogerBeepEnable)
4290		throw (OSStatus) AL_INVALID_OPERATION;
4291
4292    if (inGain == mASARogerBeepGain)
4293		return;			// nothing to do
4294
4295	mASARogerBeepGain = inGain;
4296
4297	AudioUnitSetParameter(mRogerBeepAU, 6/*kRogerBeepParam_RogerGain*/, kAudioUnitScope_Global, 0, inGain, 0 );
4298}
4299
4300// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4301void	OALSource::SetRogerBeepSensitivity(SInt32 inSensitivity)
4302{
4303#if LOG_VERBOSE
4304    DebugMessageN2("OALSource::SetRogerBeepSensitivity - OALSource:inSensitivity = %ld:%d\n", (long int) mSelfToken, inSensitivity);
4305#endif
4306#if LOG_GRAPH_AND_MIXER_CHANGES
4307    DebugMessageN2("OALSource::SetRogerBeepSensitivity - OALSource:inSensitivity = %ld:%d\n", (long int) mSelfToken, inSensitivity);
4308#endif
4309	if (inSensitivity < 0 || inSensitivity > 2)
4310		throw (OSStatus)AL_INVALID_VALUE; // must be within 0 - 2 range
4311
4312	// don't allow synchronous source manipulation
4313	CAGuard::Locker sourceLock(mSourceLock);
4314
4315	if(!mASARogerBeepEnable)
4316		throw (OSStatus)AL_INVALID_OPERATION;
4317
4318    if (inSensitivity == mASARogerBeepSensitivity)
4319		return;			// nothing to do
4320
4321	mASARogerBeepSensitivity = inSensitivity;
4322
4323	AudioUnitSetParameter(mRogerBeepAU, 4/*kRogerBeepParam_Sensitivity*/, kAudioUnitScope_Global, 0, inSensitivity, 0 );
4324}
4325
4326// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4327void	OALSource::SetRogerBeepType(SInt32 inType)
4328{
4329#if LOG_VERBOSE
4330    DebugMessageN2("OALSource::SetRogerBeepType - OALSource:inType = %ld:%d\n", (long int) mSelfToken, inType);
4331#endif
4332#if LOG_GRAPH_AND_MIXER_CHANGES
4333    DebugMessageN2("OALSource::SetRogerBeepType - OALSource:inType = %ld:%d\n", (long int) mSelfToken, inType);
4334#endif
4335
4336	if (inType < 0 || inType > 3)
4337		throw (OSStatus)AL_INVALID_VALUE; // must be within 0 - 3 range
4338
4339	// don't allow synchronous source manipulation
4340	CAGuard::Locker sourceLock(mSourceLock);
4341
4342	if(!mASARogerBeepEnable)
4343		throw (OSStatus)AL_INVALID_OPERATION;
4344
4345    if (inType == mASARogerBeepType)
4346		return;			// nothing to do
4347
4348	mASARogerBeepType = inType;
4349
4350	AudioUnitSetParameter(mRogerBeepAU, 5 /*kRogerBeepParam_RogerType*/, kAudioUnitScope_Global, 0, inType, 0 );
4351}
4352
4353// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4354void	OALSource::SetRogerBeepPreset(FSRef* inRef)
4355{
4356#if LOG_VERBOSE
4357    DebugMessageN2("OALSource::SetRogerBeepPreset - OALSource:inRef = %ld:%p\n", (long int) mSelfToken, inRef);
4358#endif
4359	// don't allow synchronous source manipulation
4360	CAGuard::Locker sourceLock(mSourceLock);
4361
4362	try {
4363			Boolean				status;
4364			SInt32				result = 0;
4365			CFURLRef			fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, inRef);
4366			if (fileURL)
4367			{
4368				// Read the XML file.
4369				CFDataRef		resourceData = NULL;
4370
4371				status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, fileURL, &resourceData,	NULL, NULL, &result);
4372				CFRelease (fileURL);	// no longer needed
4373
4374				if (status == false || result)
4375					throw (OSStatus) -1;
4376				else
4377				{
4378					CFStringRef			errString = NULL;
4379					CFPropertyListRef   theData = NULL;
4380					theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errString);
4381					CFRelease (resourceData);
4382					if (errString)
4383						CFRelease (errString);
4384
4385					if (theData == NULL || errString)
4386					{
4387						if (theData)
4388							CFRelease (theData);
4389						throw (OSStatus) -1;
4390					}
4391					else
4392					{
4393						result = AudioUnitSetProperty(mRogerBeepAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &theData, sizeof(theData) );
4394						CFRelease (theData);
4395						THROW_RESULT
4396					}
4397				}
4398			}
4399			else
4400				throw (OSStatus) -1;
4401	}
4402	catch (OSStatus result) {
4403		throw result;
4404	}
4405	catch (...) {
4406		throw (OSStatus) -1;
4407	}
4408
4409	return;
4410
4411}
4412
4413// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4414void	OALSource::SetDistortionEnable(Boolean inEnable)
4415{
4416#if LOG_VERBOSE
4417    DebugMessageN2("OALSource::SetDistortionEnable - OALSource:inEnable = %ld:%d\n", (long int) mSelfToken, inEnable);
4418#endif
4419#if LOG_GRAPH_AND_MIXER_CHANGES
4420    DebugMessageN2("OALSource::SetDistortionEnable - OALSource:inEnable = %ld:%d\n", (long int) mSelfToken, inEnable);
4421#endif
4422
4423	// don't allow synchronous source manipulation
4424	CAGuard::Locker sourceLock(mSourceLock);
4425
4426    if (inEnable == mASADistortionEnable)
4427		return;			// nothing to do
4428
4429	mASADistortionEnable = inEnable;
4430	if (mASADistortionEnable)
4431	{
4432		SetupDistortionAU();
4433		// first get the default values
4434		UInt32 propSize = sizeof(UInt32);
4435
4436		UInt32 bypassValue;
4437		if(AudioUnitGetProperty(mDistortionAU, kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0, &bypassValue, &propSize) == noErr)
4438			mASADistortionOn = bypassValue ? 0 : 1;
4439
4440		Float32 paramValue;
4441		if(AudioUnitGetParameter(mDistortionAU, 15/*kDistortionParam_FinalMix*/, kAudioUnitScope_Global, 0, &paramValue) == noErr)
4442			mASADistortionMix = paramValue;
4443
4444		AUPreset distortionType;
4445		propSize = sizeof(distortionType);
4446		if(AudioUnitGetProperty(mDistortionAU, kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0, &distortionType, &propSize) == noErr)
4447		{
4448			if(distortionType.presetName) CFRelease(distortionType.presetName);
4449			mASADistortionType = distortionType.presetNumber;
4450		}
4451
4452		// now default the unit off
4453		SetDistortionOn(false);
4454	}
4455
4456	else
4457	{
4458		if(mDistortionNode)
4459			AUGraphRemoveNode(mOwningContext->GetGraph(), mDistortionNode);
4460		mDistortionNode = 0;
4461		mDistortionAU = 0;
4462	}
4463}
4464
4465// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4466void	OALSource::SetDistortionOn(Boolean inOn)
4467{
4468#if LOG_VERBOSE
4469    DebugMessageN2("OALSource::SetDistortionOn - OALSource:inOn = %ld:%d\n", (long int) mSelfToken, inOn);
4470#endif
4471#if LOG_GRAPH_AND_MIXER_CHANGES
4472    DebugMessageN2("OALSource::SetDistortionOn - OALSource:inOn = %ld:%d\n", (long int) mSelfToken, inOn);
4473#endif
4474
4475	// don't allow synchronous source manipulation
4476	CAGuard::Locker sourceLock(mSourceLock);
4477
4478    if (inOn == mASADistortionOn)
4479		return;			// nothing to do
4480
4481	mASADistortionOn = inOn;
4482
4483	UInt32 bypassValue = mASADistortionOn ? 0 : 1;
4484
4485	AudioUnitSetProperty(mDistortionAU, kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0, &bypassValue, sizeof(UInt32));
4486}
4487
4488// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4489void	OALSource::SetDistortionMix(Float32 inMix)
4490{
4491#if LOG_VERBOSE
4492    DebugMessageN2("OALSource::SetDistortionMix - OALSource:inMix = %ld:%f\n", (long int) mSelfToken, inMix);
4493#endif
4494#if LOG_GRAPH_AND_MIXER_CHANGES
4495    DebugMessageN2("OALSource::SetDistortionMix - OALSource:inMix = %ld:%f\n", (long int) mSelfToken, inMix);
4496#endif
4497
4498	if (inMix < 0.0f || inMix > 100.0f)
4499		throw (OSStatus)AL_INVALID_VALUE; // must be within 0.0 - 100.0 range
4500
4501	// don't allow synchronous source manipulation
4502	CAGuard::Locker sourceLock(mSourceLock);
4503
4504	if(!mASADistortionEnable)
4505		throw (OSStatus)AL_INVALID_OPERATION;
4506
4507    if (inMix == mASADistortionMix)
4508		return;			// nothing to do
4509
4510	mASADistortionMix = inMix;
4511	AudioUnitSetParameter(mDistortionAU, 15/*kDistortionParam_FinalMix*/, kAudioUnitScope_Global, 0, inMix, 0 );
4512}
4513
4514// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4515void	OALSource::SetDistortionType(SInt32 inType)
4516{
4517#if LOG_VERBOSE
4518    DebugMessageN2("OALSource::SetDistortionMix - OALSource:inType = %ld:%df\n", (long int) mSelfToken, inType);
4519#endif
4520#if LOG_GRAPH_AND_MIXER_CHANGES
4521    DebugMessageN2("OALSource::SetDistortionType:  OALSource: = %u : inType %d\n", mSelfToken, inType );
4522#endif
4523
4524	// don't allow synchronous source manipulation
4525	CAGuard::Locker sourceLock(mSourceLock);
4526
4527	if(!mASADistortionEnable)
4528		throw (OSStatus)AL_INVALID_OPERATION;
4529
4530    if (inType == mASADistortionType)
4531		return;			// nothing to do
4532
4533	mASADistortionType = inType;
4534	AUPreset distortionType;
4535	distortionType.presetNumber = mASADistortionType;
4536	distortionType.presetName = NULL;
4537
4538	AudioUnitSetProperty(mDistortionAU, kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0, &distortionType, sizeof(AUPreset));
4539}
4540
4541// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4542void	OALSource::SetDistortionPreset(FSRef* inRef)
4543{
4544#if LOG_VERBOSE
4545    DebugMessageN2("OALSource::SetDistortionPreset - OALSource:inRef = %ld:%p\n", (long int) mSelfToken, inRef);
4546#endif
4547	// don't allow synchronous source manipulation
4548	CAGuard::Locker sourceLock(mSourceLock);
4549
4550	try {
4551			Boolean				status;
4552			SInt32				result = 0;
4553			CFURLRef			fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, inRef);
4554			if (fileURL)
4555			{
4556				// Read the XML file.
4557				CFDataRef		resourceData = NULL;
4558
4559				status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, fileURL, &resourceData,	NULL, NULL, &result);
4560				CFRelease (fileURL);	// no longer needed
4561
4562				if (status == false || result)
4563					throw (OSStatus) -1;
4564				else
4565				{
4566					CFStringRef			errString = NULL;
4567					CFPropertyListRef   theData = NULL;
4568					theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errString);
4569					CFRelease (resourceData);
4570					if (errString)
4571						CFRelease (errString);
4572
4573					if (theData == NULL || errString)
4574					{
4575						if (theData)
4576							CFRelease (theData);
4577						throw (OSStatus) -1;
4578					}
4579					else
4580					{
4581						result = AudioUnitSetProperty(mDistortionAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &theData, sizeof(theData) );
4582						CFRelease (theData);
4583						THROW_RESULT
4584					}
4585				}
4586			}
4587			else
4588				throw (OSStatus) -1;
4589	}
4590	catch (OSStatus result) {
4591		throw result;
4592	}
4593	catch (...) {
4594		throw (OSStatus) -1;
4595	}
4596
4597	return;
4598
4599}
4600
4601// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4602// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4603#pragma mark _____BufferQueue_____
4604// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4605// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4606UInt32     BufferQueue::GetCurrentFrame(UInt32	inBufferIndex)
4607{
4608#if LOG_VERBOSE
4609    DebugMessageN1("BufferQueue::GetCurrentFrame - inBufferIndex = %d", inBufferIndex);
4610#endif
4611	iterator	it = begin();
4612	std::advance(it, inBufferIndex);
4613	if (it != end())
4614		return (it->mBuffer->GetBytesPerPacket() == 0) ? 0 : it->mOffset/it->mBuffer->GetBytesPerPacket();
4615
4616	return 0;
4617}
4618
4619// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4620void 	BufferQueue::AppendBuffer(OALSource*	thisSource, ALuint	inBufferToken, OALBuffer	*inBuffer, ALuint	inACToken)
4621{
4622#if LOG_VERBOSE
4623    DebugMessageN4("BufferQueue::AppendBuffer - thisSource:inBufferToken:inBuffer:inACToken = %d:%d:%p:%d", thisSource->GetToken(), inBufferToken, inBuffer, inACToken);
4624#endif
4625	BufferInfo	newBuffer;
4626
4627	newBuffer.mBufferToken = inBufferToken;
4628	newBuffer.mBuffer = inBuffer;
4629	newBuffer.mOffset = 0;
4630	newBuffer.mProcessedState = kPendingProcessing;
4631	newBuffer.mACToken = inACToken;
4632
4633	push_back(value_type (newBuffer));
4634    SetQueueSize();
4635}
4636
4637// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4638ALuint 	BufferQueue::RemoveQueueEntryByIndex(OALSource*	thisSource, UInt32	inIndex, bool	inReleaseIt)
4639{
4640#if LOG_VERBOSE
4641    DebugMessageN3("BufferQueue::RemoveQueueEntryByIndex - thisSource:inIndex:inReleaseIt:inACToken = %d:%d:%d", thisSource->GetToken(), inIndex, inReleaseIt);
4642#endif
4643	iterator	it = begin();
4644	ALuint		outBufferToken = 0;
4645
4646	std::advance(it, inIndex);
4647	if (it != end())
4648	{
4649		outBufferToken = it->mBufferToken;
4650		if (inReleaseIt)
4651			it->mBuffer->ReleaseBuffer(thisSource); // if this release decrements the attchment count of this source to zero, it
4652													// will be deleted from the buffers list of attached sources
4653		erase(it);
4654	}
4655    SetQueueSize();
4656
4657	return (outBufferToken);
4658}
4659
4660// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4661UInt32 	BufferQueue::GetQueueSizeInFrames()
4662{
4663#if LOG_VERBOSE
4664    DebugMessage("BufferQueue::GetQueueSizeInFrames");
4665#endif
4666	iterator	it = begin();
4667	UInt32		totalFrames = 0;
4668
4669	while (it != end())
4670	{
4671		totalFrames += it->mBuffer->GetFrameCount();
4672		++it;
4673	}
4674
4675	return (totalFrames);
4676}
4677
4678// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4679UInt32 	BufferQueue::GetBufferFrameCount(UInt32	inBufferIndex)
4680{
4681#if LOG_VERBOSE
4682   DebugMessageN1("BufferQueue::GetBufferFrameCount - inBufferIndex = %d",inBufferIndex);
4683#endif
4684	iterator	it = begin();
4685	std::advance(it, inBufferIndex);
4686	if (it != end())
4687		return (it->mBuffer->GetFrameCount());
4688
4689	return 0;
4690}
4691
4692// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4693ALuint 	BufferQueue::GetBufferTokenByIndex(UInt32	inBufferIndex)
4694{
4695#if LOG_VERBOSE
4696    DebugMessageN1("BufferQueue::GetBufferTokenByIndex - inBufferIndex = %d",inBufferIndex);
4697#endif
4698	iterator	it = begin();
4699	std::advance(it, inBufferIndex);
4700	if (it != end())
4701		return (it->mBuffer->GetToken());
4702
4703	return 0;
4704}
4705
4706// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4707void 	BufferQueue::SetFirstBufferOffset(UInt32	inFrameOffset)
4708{
4709#if LOG_VERBOSE
4710    DebugMessageN1("BufferQueue::SetFirstBufferOffset - inFrameOffset = %d",inFrameOffset);
4711#endif
4712	iterator	it = begin();
4713	if (it == end())
4714		return;
4715
4716	UInt32		packetOffset = FrameOffsetToPacketOffset(inFrameOffset);
4717	UInt32		packetSize = GetPacketSize();
4718
4719	it->mOffset = packetOffset * packetSize;
4720}
4721
4722// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4723UInt32     BufferQueue::GetPacketSize()
4724{
4725#if LOG_VERBOSE
4726    DebugMessage("BufferQueue::GetPacketSize");
4727#endif
4728	iterator	it = begin();
4729	if (it != end())
4730		return(it->mBuffer->GetBytesPerPacket());
4731	return (0);
4732}
4733
4734// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4735UInt32 	BufferQueue::FrameOffsetToPacketOffset(UInt32	inFrameOffset)
4736{
4737#if LOG_VERBOSE
4738    DebugMessageN1("BufferQueue::FrameOffsetToPacketOffset - inFrameOffset = %d",inFrameOffset);
4739#endif
4740	return inFrameOffset; // this is correct for pcm which is all we're doing right now
4741
4742	// if non pcm formats are used return the packet that contains inFrameOffset, which may back up the
4743	// requested frame - round backward not forward
4744}