#include "pch.hpp"
//===========================================================================//
// File:	 Sound Channel.cpp												 //
// Project:  GameOS					                                         //
// Contents: Direct Sound manager											 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 01/23/98  JTR    Created													 //
//																			 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "Sound Renderer.hpp"
#include "ErrorHandler.hpp"
#include "DirectX.hpp"
#include "Debugger.hpp"

extern CRITICAL_SECTION g_soundCritSec;
extern DWORD gLanguageDLL;
extern DWORD gFreezeLogic;
extern bool DisableSoundSystem;
extern SoundRendererData SoundRenderer;


// UNIMPLEMENTED
//
//	gos_GetChannelPosition(int Channel)
//		return channel <channel>'s position (in bytes)
//
int gos_GetChannelPosition( int Channel )
{
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gos_GetChannelPosition was called with sound uninitialized" ));
		return 0;
	}
	STOP(( "Not implemented" )); 
	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0 );
	return 0;
}

// UNIMPLEMENTED
//
//	gos_SetChannelPosition(int Channel, int off)
//		set channel <channel>'s position to <off> (in bytes)
//
void gos_SetChannelPosition( int Channel, int Offset )
{
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gos_SetChannelPosition was called with sound uninitialized" ));
		return;
	}
	STOP(( "Not implemented" )); 
	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0 );
}

gosAudio_PlayMode __stdcall gosAudio_GetChannelPlayMode(int Channel)
{
	LOG_BLOCK("gosAudio::GetChannelPlayMode");
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelStatus was called with sound uninitialized" ));
		return gosAudio_Stop;
	}


	//
	// You can't get the playmode of the mixer, Channel must correspond to a regular channel.
	//
#ifdef LAB_ONLY
	if (Channel == gosAudio_Mixer)
	{
		STOP(( "You cannot get the playmode of the mixer (channel 0xffffffff)"));
		return gosAudio_Stop;
	}
#endif
	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0);

	SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelStatus(%d)",Channel ));

	if (SoundRenderer.m_Channel[Channel]->m_resourceType == gosAudio_StreamedMusic)
	{
		return (gosAudio_PlayMode) SoundRenderer.m_Channel[Channel]->m_currentSoundResource->m_hMusic->m_musicStatus;
	}
	else
	if  (SoundRenderer.m_Channel[Channel]->m_Buffer == NULL)
		return gosAudio_Stop;

	if (SoundRenderer.m_Channel[Channel]->m_fPaused)
	{
		return gosAudio_Pause;
	}
	else
	{
		if (SoundRenderer.m_Channel[Channel]->m_fPlaying == true && SoundRenderer.m_Channel[Channel]->IsPlaying())
		{
			if (SoundRenderer.m_Channel[Channel]->m_bLoopFlag)
				return gosAudio_Loop;
			else
				return gosAudio_PlayOnce;
		}
		else
		{
			return gosAudio_Stop;
		}
	}
}

void __stdcall gosAudio_SetChannelSlider(int Channel, enum gosAudio_Properties ga_p, float value, float value1, float value2)
{
	LOG_BLOCK("gosAudio::SetChannelSlider");
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider was called with sound uninitialized" ));
		return;
	}
	gosASSERT(Channel == gosAudio_Mixer || (Channel < SoundRenderer.m_numChannels && Channel >= 0) );

	switch(ga_p)
	{
	case gosAudio_Volume:
		{
			if (Channel == gosAudio_Mixer)
			{
				if (value == SoundRenderer.m_Mixer->m_fVolume)
					return;
				SoundRenderer.m_Mixer->SetVolume( value );
			}
			else
			{
				if (value == SoundRenderer.m_Channel[Channel]->m_fVolume)
					return;
				SoundRenderer.m_Channel[Channel]->SetVolume(value);
			}
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Volume, %f)",Channel, value ));
			break;
		};

	case gosAudio_Panning:
		{
			if (Channel == gosAudio_Mixer)
				STOP((GROUP_DIRECTSOUND, "It is illegal to try and set the mixer's panning"));
			else
			{
				if (value == SoundRenderer.m_Channel[Channel]->m_fPanning)
					return;
				SoundRenderer.m_Channel[Channel]->SetPan(value);
			}
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Panning, %f)",Channel, value ));
			break;
		};

	case gosAudio_Frequency:
		{
			if (Channel == gosAudio_Mixer)
				STOP((GROUP_DIRECTSOUND, "It is illegal to try and set the mixer's frequency"));
			else
			{
				if (value == SoundRenderer.m_Channel[Channel]->m_fFrequency)
					return;
				SoundRenderer.m_Channel[Channel]->SetFrequency(value);
			}
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Frequency, %f)",Channel, value ));
			break;
		};

	case gosAudio_SeekTime:
		STOP(( "Not implemented" )); 
		break;

	case gosAudio_Position:
		if (Channel == gosAudio_Mixer)
		{
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.vPosition.x && 
				value1 == SoundRenderer.m_Mixer->m_Attributes3D.vPosition.y &&
				value2 == SoundRenderer.m_Mixer->m_Attributes3D.vPosition.z)
				return;
			SoundRenderer.m_Mixer->SetPosition( value, value1, value2 );
		}
		else
		{
			if (value == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.x && 
				value1 == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.y &&
				value2 == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.z)
				return;
			SoundRenderer.m_Channel[Channel]->SetPosition( value, value1, value2 );
		}
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Position, %f, %f, %f)",Channel, value, value1, value2 ));
		break;

	case gosAudio_Velocity:
		if (Channel == gosAudio_Mixer)
		{
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.x && 
				value1 == SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.y &&
				value2 == SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.z)
				return;
			SoundRenderer.m_Mixer->SetVelocity( value, value1, value2 );
		}
		else
		{
			if (value == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.x  && 
				value1 == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.y &&
				value2 == SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.z)
				return;
			SoundRenderer.m_Channel[Channel]->SetVelocity( value, value1, value2 );
		}
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Velocity, %f, %f, %f)",Channel, value, value1, value2 ));
		break;

	case gosAudio_MinMaxDistance:
		if (Channel == gosAudio_Mixer)
			STOP(( "DistanceMinMax cannot be set on the Mixer" ));
		else
		{
			if (value == SoundRenderer.m_Channel[Channel]->m_Attributes3D.flMinDistance &&
				value1 == SoundRenderer.m_Channel[Channel]->m_Attributes3D.flMaxDistance)
				return;
			SoundRenderer.m_Channel[Channel]->SetDistanceMinMax( value, value1 );
		}
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_MinMaxDistance, %f, %f)",Channel, value, value1 ));
		break;

	case gosAudio_FrontOrientation:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.x && 
				value1 == SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.y &&
				value2 == SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.z)
				return;
			SoundRenderer.m_Mixer->SetFrontOrientation( value, value1, value2 );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_FrontOrientation, %f, %f, %f)",Channel, value, value1, value2 ));
			break;
		};
	case gosAudio_TopOrientation:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.x && 
				value1 == SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.y &&
				value2 == SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.z)
				return;
			SoundRenderer.m_Mixer->SetTopOrientation( value, value1, value2 );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_TopOrientation, %f, %f, %f)",Channel, value, value1, value2 ));
			break;
		};
	case gosAudio_Doppler:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.flDopplerFactor)
				return;
			SoundRenderer.m_Mixer->SetDopplerFactor( value );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Doppler, %f)",Channel, value ));
			break;
		};
	case gosAudio_Rolloff:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.flRolloffFactor)
				return;
			SoundRenderer.m_Mixer->SetRolloffFactor( value );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Rolloff, %f)",Channel, value ));
			break;
		};
	case gosAudio_Distance:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_Attributes3D.flDistanceFactor)
				return;
			SoundRenderer.m_Mixer->SetDistanceFactor( value );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Distance, %f)",Channel, value ));
			break;
		};
	case gosAudio_Reverb:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_reverbFactor)
				return;
			SoundRenderer.m_Mixer->SetReverbFactor( value );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Reverb, %f)",Channel, value ));
			break;
		};
	case gosAudio_Decay:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			if (value == SoundRenderer.m_Mixer->m_decayFactor)
				return;
			SoundRenderer.m_Mixer->SetDecayFactor( value );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_Decay, %f)",Channel, value ));
	   		break;
		};
	case gosAudio_ConeAngles:
		{
			gosASSERT( Channel != gosAudio_Mixer );
			if (SoundRenderer.m_Channel[Channel]->m_Attributes3D.dwInsideConeAngle == value &&
				SoundRenderer.m_Channel[Channel]->m_Attributes3D.dwOutsideConeAngle == value1)
				return;
			SoundRenderer.m_Channel[Channel]->SetConeAngles( (DWORD) value, (DWORD) value1 );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_ConeAngles, %f, %f)",Channel, value, value1 ));
			break;
		};
	case gosAudio_ConeOrientation:
		{
			gosASSERT( Channel != gosAudio_Mixer );
			if (SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.x == value &&
				SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.y == value1 &&
				SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.z == value2)
				return;

			SoundRenderer.m_Channel[Channel]->SetConeOrientation( value, value1, value2 );
			SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetChannelSlider(%d, gosAudio_ConeOrientation, %f, %f)",Channel, value, value1 ));
			break;
		};
	default:
		{
			STOP(( "Bad sound slider index" )); 
			break;
		}
	}
#ifdef LAB_ONLY
#ifndef _DEBUG
	if (DebuggerActive && DebugDisplay == DbgS_PlayHistory && SoundRenderer.m_verboseDebugger)
#else
	if (SoundRenderer.m_verboseDebugger)
#endif
	{
		char action[32];
		switch (ga_p)
		{
		case gosAudio_Volume:
			strcpy(action,"Volume");
			break;		   
		case gosAudio_Panning:
			strcpy(action,"Panning");
			break;
		case gosAudio_Frequency:
			strcpy(action,"Frequency");
			break;
		case gosAudio_SeekTime:
			strcpy(action,"Seek");
			break;
		case gosAudio_Position:
			strcpy(action,"Position");
			break;
		case gosAudio_Velocity:
			strcpy(action,"Velocity");
			break;
		case gosAudio_MinMaxDistance:
			strcpy(action,"MinMax");
			break;
		case gosAudio_FrontOrientation:
			strcpy(action,"Orient Front");
			break;
		case gosAudio_TopOrientation:
			strcpy(action,"Orient Top");
			break;
		case gosAudio_Doppler:
			strcpy(action,"Doppler");
			break;
		case gosAudio_Rolloff:
			strcpy(action,"Rolloff");
			break;
		case gosAudio_Distance:
			strcpy(action,"Distance");
			break;
		case gosAudio_Reverb:
			strcpy(action,"Reverb");
			break;
		case gosAudio_Decay:
			strcpy(action,"Decay");
			break;
		case gosAudio_ConeAngles:
			strcpy(action,"Cone Angle");
			break;
		case gosAudio_ConeOrientation:
			strcpy(action,"Cone Orient");
			break;
		}
	
		char tmp[256];

		if (Channel == gosAudio_Mixer)
		{
			sprintf(tmp, "							           (%5.2f, %5.2f, %5.2f)\n",  value, value1, value2);
		}
		else
		{
			sprintf(tmp, "									   (%5.2f, %5.2f, %5.2f)\n",  value, value1, value2 );
		}
		strncpy( SoundRenderer.m_playHistory[SoundRenderer.m_playHistoryItr], tmp, 127 );
		SoundRenderer.m_playHistoryItr++;
		if (SoundRenderer.m_playHistoryItr == 32)
			SoundRenderer.m_playHistoryItr = 0;

		if (Channel == gosAudio_Mixer)
		{
			sprintf(tmp, "%9.2f    %-12s      Mixer\n",  gos_GetElapsedTime(), action);
			SPEW ((GROUP_DIRECTSOUND,"%s Mixer", action));
		}
		else
		{
			sprintf(tmp, "%9.2f    %-12s         %2d    <%s>\n",  gos_GetElapsedTime(), action, Channel, SoundRenderer.m_Channel[Channel]->m_resourceName[0] ? SoundRenderer.m_Channel[Channel]->m_resourceName : "Unlabeled UserMemory");
			SPEW ((GROUP_DIRECTSOUND,"%s Channel %d: %s", action, Channel, SoundRenderer.m_Channel[Channel]->m_resourceName[0] ? SoundRenderer.m_Channel[Channel]->m_resourceName : "Unlabeled UserMemory"));
		}
		strncpy( SoundRenderer.m_playHistory[SoundRenderer.m_playHistoryItr], tmp, 127 );
		SoundRenderer.m_playHistoryItr++;
		if (SoundRenderer.m_playHistoryItr == 32)
			SoundRenderer.m_playHistoryItr = 0;
	}
#endif
}

void __stdcall gosAudio_AssignResourceToChannel(int Channel, HGOSAUDIO hgosaudio)
{
	LOG_BLOCK("gosAudio::AssignResourceToChannel");
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_AssignResourceToChannel was called with sound uninitialized" ));
		return;
	}

	if (DisableSoundSystem)
		return;

	//
	// You can't assign a resource to the mixer, Channel must correspond to a regular channel.
	//
#ifdef LAB_ONLY
	if (Channel == 0xffffffff)
	{
		STOP(( "You cannot assign a resource to the mixer (channel -1)"));
		return;
	}
#endif

	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0 );

	if (hgosaudio == NULL)
	{
		// clear out sound from ds buffers
		gosAudio_SetChannelPlayMode( Channel, gosAudio_Stop );
		SoundRenderer.m_Channel[Channel]->ClearAndFree();
	}
	else
	{
#ifdef LAB_ONLY
		if (!IsValidSoundResource(hgosaudio))
			STOP(( "0x%x is not a valid resource handle", hgosaudio ));
#endif
		switch (hgosaudio->m_Type)
		{
		case gosAudio_CachedFile:
		case gosAudio_UserMemory:
			if (SoundRenderer.m_reset == false && ((SoundResource *)hgosaudio)->m_FileName && ((SoundResource *)hgosaudio)->m_Type == SoundRenderer.m_Channel[Channel]->m_resourceType &&
				!stricmp(((SoundResource *)hgosaudio)->m_FileName, SoundRenderer.m_Channel[Channel]->m_resourceName))
			{
				// assigning the same resource, don't stop the channel!
				// unless we're resetting!
				SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
			}
			else
			{
				gosAudio_SetChannelPlayMode(Channel, gosAudio_Stop);
				SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
			}
			break;
		case gosAudio_StreamedFile:
			{
				if (SoundRenderer.m_reset == false && ((SoundResource *)hgosaudio)->m_FileName && ((SoundResource *)hgosaudio)->m_Type == SoundRenderer.m_Channel[Channel]->m_resourceType &&
					!stricmp(((SoundResource *)hgosaudio)->m_FileName, SoundRenderer.m_Channel[Channel]->m_resourceName))
				{
					// assigning the same resource, don't stop the channel!
					// unless we're resetting!
					SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
				}
				else
				{
					gosAudio_SetChannelPlayMode(Channel, gosAudio_Stop);
					SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
				}
			}
			break;
		case gosAudio_StreamedFP:
			{
				if (SoundRenderer.m_reset == false && ((SoundResource *)hgosaudio)->m_FileName && ((SoundResource *)hgosaudio)->m_Type == SoundRenderer.m_Channel[Channel]->m_resourceType &&
					!stricmp(((SoundResource *)hgosaudio)->m_FileName, SoundRenderer.m_Channel[Channel]->m_resourceName))
				{
					// assigning the same resource, don't stop the channel!
					// unless we're resetting!
					SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
				}
				else
				{
					gosAudio_SetChannelPlayMode(Channel, gosAudio_Stop);
					SoundRenderer.m_Channel[Channel]->CreateAndLoadBuffer((SoundResource *) hgosaudio);
				}
			}
			break;
		case gosAudio_StreamedMusic:
			if (SoundRenderer.m_reset == false && ((SoundResource *)hgosaudio)->m_FileName && ((SoundResource *)hgosaudio)->m_Type == SoundRenderer.m_Channel[Channel]->m_resourceType &&
				!stricmp(((SoundResource *)hgosaudio)->m_FileName, SoundRenderer.m_Channel[Channel]->m_resourceName))
			{
				// assigning the same resource, don't stop the channel!
				// unless we're resetting!
			}
			else
			{
				SoundRenderer.m_Channel[Channel]->ClearAndFree();
				SoundRenderer.m_Channel[Channel]->m_currentSoundResource = hgosaudio;
				SoundRenderer.m_Channel[Channel]->m_resourceType = gosAudio_StreamedMusic;
				strncpy(SoundRenderer.m_Channel[Channel]->m_resourceName, hgosaudio->m_FileName,127);

			}
			break;
		case gosAudio_UserMemoryPlayList:
			if (SoundRenderer.m_reset == false && ((SoundResource *)hgosaudio)->m_FileName && ((SoundResource *)hgosaudio)->m_Type == SoundRenderer.m_Channel[Channel]->m_resourceType &&
				!stricmp(((SoundResource *)hgosaudio)->m_FileName, SoundRenderer.m_Channel[Channel]->m_resourceName))
			{
				// assigning the same resource, don't stop the channel!
				// unless we're resetting!
			}
			else
			{
				gosAudio_SetChannelPlayMode(Channel, gosAudio_Stop);
				SoundRenderer.m_Channel[Channel]->CreateStreamBuffer((SoundResource *)  hgosaudio);
			}
			break;
		}
	}

#ifdef LAB_ONLY
#ifndef _DEBUG
	if (DebuggerActive && DebugDisplay == DbgS_PlayHistory)
#endif
	{
		char tmp[256];
		sprintf(tmp, "%9.2f    Assign               %2d    <%s>\n",  gos_GetElapsedTime(), Channel, SoundRenderer.m_Channel[Channel]->m_resourceName[0] ? SoundRenderer.m_Channel[Channel]->m_resourceName : "Unlabeled UserMemory");
		strncpy( SoundRenderer.m_playHistory[SoundRenderer.m_playHistoryItr], tmp, 127 );
		SPEW ((GROUP_DIRECTSOUND,"Assign Channel %d with %s: (0x%x)", Channel, SoundRenderer.m_Channel[Channel]->m_resourceName[0] ? SoundRenderer.m_Channel[Channel]->m_resourceName : "Unlabeled UserMemory", hgosaudio));
		SoundRenderer.m_playHistoryItr++;
		if (SoundRenderer.m_playHistoryItr == 32)
			SoundRenderer.m_playHistoryItr = 0;
	}
#endif
}

void __stdcall gosAudio_GetChannelSlider(int Channel, enum gosAudio_Properties ga_p, float * value, float * value1, float * value2)
{
	LOG_BLOCK("gosAudio::GetChannelSlider");
	if (value)
		*value = 0.0f;
	if (value1)
		*value1 = 0.0f;
	if (value2)
		*value2 = 0.0f;
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelValue was called with sound uninitialized" ));
		return;
	}
	gosASSERT(Channel == gosAudio_Mixer || (Channel < SoundRenderer.m_numChannels && Channel >= 0) );
	SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelValue(%d)",Channel ));

	switch(ga_p)
	{
	case gosAudio_Volume:
		{
			if (Channel != gosAudio_Mixer)
				*value = SoundRenderer.m_Channel[Channel]->m_fVolume;
			else
				*value = SoundRenderer.m_Mixer->m_fVolume;
			break;
		};
	case gosAudio_Panning:
		{
			if (Channel == gosAudio_Mixer)
				*value = 0.0f;
			else
				*value = SoundRenderer.m_Channel[Channel]->m_fPanning;
			break;
		};

	case gosAudio_Frequency:
		{
			if (Channel == gosAudio_Mixer)
				*value = 1.0f;
			else
				*value = SoundRenderer.m_Channel[Channel]->m_fFrequency;
			break;
		};
	case gosAudio_SeekTime:
		{
			
			break;
		}
	case gosAudio_Position:
		{
			if (Channel == gosAudio_Mixer)
			{
				*value = SoundRenderer.m_Mixer->m_Attributes3D.vPosition.x;
				*value1 = SoundRenderer.m_Mixer->m_Attributes3D.vPosition.y;
				*value2 = SoundRenderer.m_Mixer->m_Attributes3D.vPosition.z;
			}
			else
			{
				*value = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.x;
				*value1 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.y;
				*value2 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vPosition.z;
			}
			break;
		};
	case gosAudio_Velocity:
		{
			if (Channel == gosAudio_Mixer)
			{
				*value = SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.x;
				*value1 = SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.y;
				*value2 = SoundRenderer.m_Mixer->m_Attributes3D.vVelocity.z;
			}
			else
			{
				*value = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.x;
				*value1 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.y;
				*value2 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vVelocity.z;
			}
			break;
		};
	case gosAudio_MinMaxDistance:
		{
			gosASSERT( Channel != gosAudio_Mixer );
			*value = SoundRenderer.m_Channel[Channel]->m_Attributes3D.flMinDistance;
			*value1 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.flMaxDistance;
			break;
		};
	// the sliders listed below are only for the mixer/listener
	case gosAudio_FrontOrientation:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.x;
			*value1 = SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.y;
			*value2 = SoundRenderer.m_Mixer->m_Attributes3D.vOrientFront.z;
			break;
		};
	case gosAudio_TopOrientation:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.x;
			*value1 = SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.y;
			*value2 = SoundRenderer.m_Mixer->m_Attributes3D.vOrientTop.z;
			break;
		};
	case gosAudio_Doppler:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_Attributes3D.flDopplerFactor;
			break;
		};
	case gosAudio_Rolloff:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_Attributes3D.flRolloffFactor;
			break;
		};
	case gosAudio_Distance:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_Attributes3D.flDistanceFactor;
			break;
		};
	case gosAudio_Reverb:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_reverbFactor;
			break;
		};
	case gosAudio_Decay:
		{
			gosASSERT( Channel == gosAudio_Mixer );
			*value = SoundRenderer.m_Mixer->m_decayFactor;
			break;
		};
	case gosAudio_ConeAngles:
		{
			gosASSERT( Channel != gosAudio_Mixer );
			*value = (float) SoundRenderer.m_Channel[Channel]->m_Attributes3D.dwInsideConeAngle;
			*value1 = (float) SoundRenderer.m_Channel[Channel]->m_Attributes3D.dwOutsideConeAngle;
			break;
		};
	case gosAudio_ConeOrientation:
		{
			gosASSERT( Channel != gosAudio_Mixer );
			*value = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.x;
			*value1 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.y;
			*value2 = SoundRenderer.m_Channel[Channel]->m_Attributes3D.vConeOrientation.z;
			break;
		};
	default:
		{
			STOP(( "Bad sound slider index" )); 
			break;
		}
	}
}

void __stdcall gosAudio_AllocateChannelSliders(int Channel, DWORD properties)
{
	LOG_BLOCK("gosAudio::AllocateChannelSliders");
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_AllocateChannelSliders was called with sound uninitialized" ));
		return;
	}
	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0 );
	SPEW(( GROUP_DIRECTSOUND, "gosAudio_AllocateChannelSliders( %d, %d )",Channel, properties ));

	SoundRenderer.m_Channel[Channel]->m_currentProperties = properties;
}


#ifdef _ARMOR
char* GetPlayMode( enum gosAudio_PlayMode ga_pm )
{
	switch (ga_pm)
	{
		case gosAudio_PlayOnce:
			return "PlayOnce";
		case gosAudio_Loop:
			return "Loop";
		case gosAudio_Stop:
			return "Stop";
		case gosAudio_Pause:
			return "Pause";
		case gosAudio_Continue:
			return "Continue";
	}
	return "Unknown";
}
#endif


void __stdcall gosAudio_SetChannelPlayMode(int Channel, enum gosAudio_PlayMode ga_pm)
{
	LOG_BLOCK("gosAudio::SetChannelPlayMode");
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_ChannelPlayMode was called with sound uninitialized" ));
		return;
	}

#ifdef LAB_ONLY
	if (Channel == 0xffffffff)
	{
		STOP(( "You cannot set the playmode of the mixer (channel -1)"));
		return;
	}
#endif
	gosASSERT( Channel < SoundRenderer.m_numChannels && Channel >= 0 );


	if (SoundRenderer.m_allPaused || DisableSoundSystem)
		return;
	// if the channel has no assigned resources, don't do anything

	DS3DSoundChannel * s = SoundRenderer.m_Channel[Channel];

	if (s->m_resourceType == gosAudio_StreamedMusic)
	{
		if (!s->m_currentSoundResource)
			return;
		if (!s->m_currentSoundResource->m_hMusic)
			return;
	}
	else
	if (!s->m_Buffer)
		return;
	SPEW(( GROUP_DIRECTSOUND, "gosAudio_ChannelPlayMode( %d, %s ) on (0x%x)",Channel, GetPlayMode(ga_pm), SoundRenderer.m_Channel[Channel]->m_Buffer ));

	EnterCriticalSection(&g_soundCritSec);


	switch (ga_pm)
	{
	case gosAudio_PlayOnce:
		{
			s->SetAllParameters();
			s->m_bLoopFlag = false;
			s->m_fPaused = false;
			s->m_fPlaying= true;
			if (s->m_resourceType == gosAudio_UserMemory ||
				s->m_resourceType == gosAudio_UserMemoryDecode ||
				s->m_resourceType == gosAudio_CachedFile)
				s->playPending = true;
			else
			{
				s->PlayStream();
			}
			break;
		};
	case gosAudio_Loop:
		{
			s->SetAllParameters();
			s->m_bLoopFlag = true;
			s->m_fPaused = false;
			s->m_fPlaying= true;
			if (s->m_resourceType == gosAudio_UserMemory || 
				s->m_resourceType == gosAudio_CachedFile)
				s->playPending = true;
			else
				s->PlayStream();
			break;
		};
	case gosAudio_Stop:
		{
			gosASSERT(Channel < SoundRenderer.m_numChannels);
			if (s->m_resourceType == gosAudio_UserMemory || 
				s->m_resourceType == gosAudio_CachedFile)
			{
				s->Stop();
			}
			else
			{
				s->StopStream();
				s->m_currentSoundResource->m_nBytesPlayed = 0;
			}
			break;
		};
	case gosAudio_Pause:
		{
			if (s->IsPlaying() )
			{
				if (s->m_resourceType == gosAudio_UserMemory || 
					s->m_resourceType == gosAudio_CachedFile)
				{
					s->Pause();
				}
				else
				{
					s->PauseStream();
				}
			}
			break;
		};
	case gosAudio_Continue:
		{
			SoundRenderer.m_Mixer->Flush();
			if ( s->m_fPaused)
			{
				if (s->m_resourceType == gosAudio_UserMemory || 
					s->m_resourceType == gosAudio_CachedFile)
				{
					s->Play();
				}
				else
				{		
					s->PlayStream();
				}
			}
			break;
		};
	}

	if (gFreezeLogic && s->m_Buffer)
	{
		wStop(s->m_Buffer);
	}

#ifdef LAB_ONLY
#ifndef _DEBUG
	if (DebuggerActive && DebugDisplay == DbgS_PlayHistory)
#endif
	{
		char action[32];
		switch (ga_pm)
		{
		case gosAudio_PlayOnce:
			strcpy(action, "Play Once");
			break;			
		case gosAudio_Loop:
			strcpy(action, "Loop");
			break;
		case gosAudio_Stop:
			strcpy(action, "Stop");
			break;
		case gosAudio_Pause:
			strcpy(action, "Pause");
			break;
		case gosAudio_Continue:
			strcpy(action, "Continue");
			break;
		}
		char tmp[256];
		sprintf(tmp, "%9.2f    %-12s         %2d    <%s>\n",  gos_GetElapsedTime(), action, Channel, s->m_resourceName[0] ? s->m_resourceName : "Unlabeled UserMemory");
		SPEW ((GROUP_DIRECTSOUND, "%s Channel %d: %s", action, Channel, s->m_resourceName[0] ? s->m_resourceName : "Unlabeled UserMemory"));
		strncpy( SoundRenderer.m_playHistory[SoundRenderer.m_playHistoryItr], tmp, 127 );
		SoundRenderer.m_playHistoryItr++;
		if (SoundRenderer.m_playHistoryItr == 32)
			SoundRenderer.m_playHistoryItr = 0;
	}
#endif
	LeaveCriticalSection(&g_soundCritSec);
}

void __stdcall gosAudio_GetChannelInfo(int Channel, gosAudio_ChannelInfo * ci)
{
	LOG_BLOCK("gosAudio::GetChannelInfo");
	if (!SoundRenderer.m_isInitialized || Environment.soundDisable)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelInfo was called with sound uninitialized" ));

		memset(ci,0,sizeof(gosAudio_ChannelInfo));
		ci->hAudio = NULL;
		ci->dwProperties = 0;
		ci->ePlayMode = gosAudio_Stop;
		return;
	}
	SPEW(( GROUP_DIRECTSOUND, "gosAudio_GetChannelInfo( %d, %x )",Channel, ci ));
	gosASSERT(Channel == gosAudio_Mixer || (Channel < SoundRenderer.m_numChannels && Channel >= 0) );

	memset( ci, 0, sizeof(gosAudio_ChannelInfo) );
	if (Channel == gosAudio_Mixer)
	{
		DS3DSoundMixer * m = SoundRenderer.m_Mixer;
		ci->dwProperties = m->m_properties;
		ci->fVolume = m->m_fVolume;
		ci->fPanning = 0;
		ci->fFrequency = 1.0f;
		ci->ePlayMode = gosAudio_Loop;

		ci->fPosX = m->m_Attributes3D.vPosition.x;
		ci->fPosY = m->m_Attributes3D.vPosition.y;
		ci->fPosZ = m->m_Attributes3D.vPosition.z;
		ci->fVelX = m->m_Attributes3D.vVelocity.x;
		ci->fVelY = m->m_Attributes3D.vVelocity.y;
		ci->fVelZ = m->m_Attributes3D.vVelocity.z;

		m->GetSpeakerConfig(&ci->dwSpeakerConfig);
		ci->fDoppler = m->m_Attributes3D.flDopplerFactor;
		ci->fRolloff = m->m_Attributes3D.flRolloffFactor;
		ci->fDistance = m->m_Attributes3D.flDistanceFactor;
		ci->fDecay = m->m_decayFactor;
		ci->fReverb = m->m_reverbFactor;
		ci->fFrontX = m->m_Attributes3D.vOrientFront.x;
		ci->fFrontY = m->m_Attributes3D.vOrientFront.y;
		ci->fFrontZ = m->m_Attributes3D.vOrientFront.z;
		ci->fTopX = m->m_Attributes3D.vOrientTop.x;
		ci->fTopY = m->m_Attributes3D.vOrientTop.y;
		ci->fTopZ = m->m_Attributes3D.vOrientTop.z;
		return;
	}
	else
	{
		DS3DSoundChannel * s = SoundRenderer.m_Channel[Channel];
		ci->fMinDistance = s->m_Attributes3D.flMinDistance;
		ci->fMaxDistance = s->m_Attributes3D.flMaxDistance;

		ci->hAudio = s->m_currentSoundResource;
		ci->dwProperties = s->m_currentProperties;
		ci->ePlayMode = gosAudio_GetChannelPlayMode( Channel );
		ci->fVolume = s->m_fVolume;
		ci->fPanning = s->m_fPanning;
		ci->fFrequency = s->m_fFrequency;
	
		ci->fPosX = s->m_Attributes3D.vPosition.x;
		ci->fPosY = s->m_Attributes3D.vPosition.y;
		ci->fPosZ = s->m_Attributes3D.vPosition.z;

		ci->fVelX = s->m_Attributes3D.vVelocity.x;
		ci->fVelY = s->m_Attributes3D.vVelocity.y;
		ci->fVelZ = s->m_Attributes3D.vVelocity.z;

		ci->fConeInner = (float) s->m_Attributes3D.dwInsideConeAngle;
		ci->fConeOuter = (float) s->m_Attributes3D.dwOutsideConeAngle;

		ci->fConeX = s->m_Attributes3D.vConeOrientation.x;
		ci->fConeY = s->m_Attributes3D.vConeOrientation.y;
		ci->fConeZ = s->m_Attributes3D.vConeOrientation.z;
	}


	DS3DSoundChannel * s = SoundRenderer.m_Channel[Channel];
	if (s->m_resourceType != -1)
	{
		if (s->m_resourceType == gosAudio_StreamedMusic)
		{
			if (ci->hAudio->m_hMusic->m_fDurationSec != 0.0f)
				ci->fCompletionRatio = ((float) ((double)ci->hAudio->m_hMusic->m_fSoFarSec / (double)ci->hAudio->m_hMusic->m_fDurationSec));
			else
				ci->fCompletionRatio = 0.0f;
			ci->ePlayMode = (gosAudio_PlayMode) ci->hAudio->m_hMusic->m_musicStatus;
		}
		else
		if (s->m_resourceType == gosAudio_StreamedFile || s->m_resourceType == gosAudio_StreamedFP)
		{
			bool isPlaying = s->m_fPlaying && s->IsPlaying();
			if (!isPlaying) 
				ci->ePlayMode = gosAudio_Stop;

			if (!s->m_fPaused && !isPlaying)
			{
				ci->fCompletionRatio = 0.0f;
			}
			else
			{
				DWORD playpos;
				playpos = s->m_currentSoundResource->m_nBytesPlayed;
				ci->fCompletionRatio = (float) playpos / 
					((s->m_currentSoundResource->m_microsoftPCM ? 1 : 4) * (s->m_currentSoundResource->m_DataLength));
			}
		}
		else
		if (s->m_resourceType == gosAudio_UserMemoryPlayList)
		{
			ci->fCompletionRatio = (float) (ci->hAudio->m_nBytesPlayed) / (float) (ci->hAudio->m_playListDataLength);
			if (ci->fCompletionRatio > 1.0f)
				ci->fCompletionRatio = 1.0f;
		}
		else
		{
			bool isPlaying = s->m_fPlaying && s->IsPlaying();
			if (!isPlaying) 
				ci->ePlayMode = gosAudio_Stop;

			if (!s->m_fPaused && !isPlaying)
			{
				ci->fCompletionRatio = 0.0f;
			}
			else
			{
				DWORD playpos;
				playpos = s->GetBytesPlayed();
				if (s->m_dsbCaps.dwBufferBytes)
					ci->fCompletionRatio = (float) playpos / s->m_dsbCaps.dwBufferBytes;
				else
					ci->fCompletionRatio = 0.0f;
			}
		}
	}
	else
	{
	 	ci->fCompletionRatio = 0.0f;
	}

	if( 1==LogMode )	// Log file playing back?
	{
		DWORD temp=ReadBitStream(32,Log_Media);
		ci->fCompletionRatio=*(float*)&temp;
	}
	else				// Log file recording
	{
		WriteBitStream(*(DWORD*)&ci->fCompletionRatio,32,Log_Media);
	}
}

void __stdcall gosAudio_SetSpeakerConfig( DWORD config)
{
	if (!SoundRenderer.m_isInitialized)
	{
		SPEW(( GROUP_DIRECTSOUND, "gosAudio_SetSpeakerConfig was called with sound uninitialized" ));
		return;
	}
	SoundRenderer.m_Mixer->SetSpeakerConfig( config );
}

void gosAudio_SelectSoundSystem()
{
}

