#include "StdAfx.h" #include "ALAudioSource.h" #include "audio/ALAudio.h" #include "audio/ALAudioSystem.h" #include #include "ALListener.h" #include "../Map/Task.h" #include "../Map/TaskManager.h" #include "ClientApp.h" volatile boost::uint32_t ALAudioSource::s_maxthreadtask = 0; //#define UNUSE_TASK class audio_load_task : public CTask { public: virtual void Begin() { } virtual void Run() { s->ThreadLoad(); } virtual bool NeedDelete(){ return true;} ALAudioSource* s; }; ALAudioSource::ALAudioSource(unsigned int uiType /*= TYPE_DEFAULT*/) : AudioSource(uiType), m_wantplay( 0 ) { m_Handle = NULL_AUDIOHANDLE; m_eDoneStatus = NOT_SET; m_ePrevStatus = NOT_SET; SetAllowSharing(true); } ALAudioSource::~ALAudioSource() { while( interlocked_read( &m_wantplay ) == 3 ) Sleep( 1 ); Unload(); m_eDoneStatus = AudioSource::FREE; } void ALAudioSource::Release() { if( interlocked_read( &m_wantplay ) == 3 ) return; if (m_Handle == NULL_AUDIOHANDLE) return; AudioSource::Status eStatus = GetStatus(); if (eStatus == PLAYING) { Stop(); //return; } ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); pkAS->ReleaseALSourceHandle(this); m_ePrevStatus = GetStatus(); m_Handle = NULL_AUDIOHANDLE; interlocked_write( &m_wantplay, 0 ); } bool ALAudioSource::SetConeData(float fAngle1Deg, float fAngle2Deg, float fGain) { SetConeData(fAngle1Deg, fAngle2Deg, fGain); if (m_Handle == NULL_AUDIOHANDLE || GetType() != TYPE_3D) return false; ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); pkAS->ALSourcef(m_Handle, AL_CONE_INNER_ANGLE, fAngle1Deg); pkAS->ALSourcef(m_Handle, AL_CONE_OUTER_ANGLE, fAngle2Deg); pkAS->ALSourcef(m_Handle, AL_CONE_OUTER_GAIN, fGain); return true; } void ALAudioSource::GetConeData(float& fAngle1Deg, float& fAngle2Deg, float& fGain) { if (m_Handle == NULL_AUDIOHANDLE || GetType() != TYPE_3D) { fAngle1Deg = 0.f; fAngle2Deg = 0.f; fGain = 1.f; return; } ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); pkAS->ALGetSourcef(m_Handle, AL_CONE_INNER_ANGLE, &fAngle1Deg); pkAS->ALGetSourcef(m_Handle, AL_CONE_OUTER_ANGLE, &fAngle2Deg); pkAS->ALGetSourcef(m_Handle, AL_CONE_OUTER_GAIN, &fGain); } bool ALAudioSource::SetMinMaxDistance(float fMin, float fMax) { AudioSource::SetMinMaxDistance(fMin, fMax); if (m_Handle == NULL_AUDIOHANDLE) return false; ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); if (GetType() != AudioSource::TYPE_3D) { pkAS->ALSourcei(m_Handle, AL_SOURCE_RELATIVE, AL_TRUE); pkAS->ALSource3f(m_Handle, AL_POSITION, 0.0f, 0.0f, 1.0f); pkAS->ALSourcei(m_Handle, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); } else { pkAS->ALSourcei(m_Handle, AL_SOURCE_RELATIVE, AL_FALSE); } pkAS->ALSourcef(m_Handle, AL_REFERENCE_DISTANCE, fMin); pkAS->ALSourcef(m_Handle, AL_MAX_DISTANCE, fMax); return true; } void ALAudioSource::GetMinMaxDistance(float& fMin, float& fMax) { if (m_Handle == NULL_AUDIOHANDLE || GetType() != AudioSource::TYPE_3D) { AudioSource::GetMinMaxDistance(fMin, fMax); return; } ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); pkAS->ALGetSourcef(m_Handle, AL_REFERENCE_DISTANCE, &fMin); pkAS->ALGetSourcef(m_Handle, AL_MAX_DISTANCE, &fMax); } bool ALAudioSource::SetGain(float fGain) { AudioSource::SetGain(fGain); if (m_Handle == NULL_AUDIOHANDLE) return false; ALAudioSystem* pkAS = (ALAudioSystem*)(AudioSystem::GetAudioSystem()); float fGainScale = 1.f; if( GetStreamed() ) fGainScale = pkAS->GetMusicGainScale(); else if( GetType() == TYPE_3D ) fGainScale = pkAS->Get3DSoundGainScale(); else fGainScale = pkAS->GetSoundGainScale(); float volume = NiClamp(fGain*fGainScale, 0.f, 1.f); pkAS->ALSetSourceVolume(m_Handle, volume); return true; } float ALAudioSource::GetGain() { if (m_Handle == NULL_AUDIOHANDLE) return AudioSource::GetGain(); return AudioSource::GetGain(); } bool ALAudioSource::SetPlaybackRate(long lRate) { return false; } long ALAudioSource::GetPlaybackRate() { return 0L; } void ALAudioSource::SetFilename(const char* pFilename) { NIASSERT(pFilename); // First check to see if incoming filename is the same as the // existing one. If they are identical then, assuming the Source // exists, the function can return. if (m_pcFilename) { if (!strcmp(m_pcFilename, pFilename)) { if (m_Handle != NULL_AUDIOHANDLE) return; } else { Unload(); } } // New filename will require loading SetLoaded(false); NiFree(m_pcFilename); NiFree(m_pcLocalName); m_pcFilename = 0; m_pcLocalName = 0; unsigned int uiLen = strlen(pFilename) + 1; m_pcFilename = NiAlloc(char, uiLen); NIASSERT(m_pcFilename); NiStrcpy(m_pcFilename, uiLen, pFilename); // Now set filename only that can be used as a second check // for creating Sharing sources. char acSearchPath[NI_MAX_PATH]; NiFilename kFilename(m_pcFilename); kFilename.SetDir(""); kFilename.SetDrive(""); kFilename.SetPlatformSubDir(""); kFilename.GetFullPath(acSearchPath, NI_MAX_PATH); uiLen = strlen(acSearchPath) + 1; m_pcLocalName = NiAlloc(char, uiLen); NIASSERT(m_pcLocalName); NiStrcpy(m_pcLocalName, uiLen, acSearchPath); // Reset the Done Status m_eDoneStatus = NOT_SET; } bool ALAudioSource::Load() { if (GetLoaded()) { NiOutputDebugString("Data already loaded\n"); return true; } if (!m_pcFilename) { NiOutputDebugString("Invalid filename\n"); return false; } m_eDoneStatus = NOT_SET; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); m_spBuffer = pkAS->LoadALSource(this); if (m_spBuffer) { SetLoaded(true); return true; } return false; } bool ALAudioSource::Unload() { if (!GetLoaded()) return false; Release(); AudioSource::Status eStatus = GetStatus(); _asm nop m_spBuffer = 0; SetLoaded(false); return true; } void ALAudioSource::PlayAtOnce() { if (!GetLoaded()) return; RealPlay(); } bool ALAudioSource::Play() { #ifdef UNUSE_TASK PlayAtOnce(); return true; #endif if (!GetLoaded()) return false; if( interlocked_read( &s_maxthreadtask ) >= MAX_AUDIOSOURCES ) return false; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); m_fStartTime = SYState()->ClientApp->GetAccumTime(); m_fPlayTime = 2.f; boost::uint32_t flag = interlocked_read( &m_wantplay ); if( flag == 0 ) { interlocked_write( &m_wantplay, 3 ); interlocked_increment( &s_maxthreadtask ); audio_load_task* pLoadTrd = NiNew audio_load_task; pLoadTrd->s = this; g_pkTaskManager->PushAudioTask( pLoadTrd ); //pkAS->m_ttp.push_task( t ); return true; } else if( flag == 3 ) { return false; } else { if( !RealPlay() ) { interlocked_write( &m_wantplay, 0 ); //Play(); } } return true; } void ALAudioSource::ThreadLoad() { ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); if (m_Handle == NULL_AUDIOHANDLE) { AUDIOHANDLE nh = pkAS->CreateALSourceHandle(this); if (nh == NULL_AUDIOHANDLE) { interlocked_write( &m_wantplay, 0 ); interlocked_decrement( &s_maxthreadtask ); return; } m_Handle = nh; } interlocked_write( &m_wantplay, 1 ); interlocked_decrement( &s_maxthreadtask ); } bool ALAudioSource::RealPlay() { ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); if (m_Handle == NULL_AUDIOHANDLE) { /* AUDIOHANDLE nh = pkAS->CreateALSourceHandle(this); if (nh == NULL_AUDIOHANDLE) return; m_Handle = nh; */ return false; } if (GetCone()) SetConeData(m_fConeAngle1Deg, m_fConeAngle2Deg, m_fConeGain); SetMinMaxDistance(m_fMinDistance, m_fMaxDistance); SetGain(m_fGain); if (m_lPlaybackRate > 0) SetPlaybackRate(m_lPlaybackRate); if (m_fPlayTime > 0.0001f) SetPlayTime(m_fPlayTime); if (m_uiPlayPosition > 0) SetPlayPosition(m_uiPlayPosition); if (m_fRoomEffectLevel > 0.0001f) SetRoomEffectLevel(m_fRoomEffectLevel); if (m_fOcclusionFactor > 0.0001f) SetOcclusionFactor(m_fOcclusionFactor); if (m_fObstructionFactor > 0.0001f) SetObstructionFactor(m_fObstructionFactor); if (GetType() == TYPE_3D) UpdateWorldTransfrom(); int loopcount = GetLoopCount(); pkAS->SetSourceLoopCount(m_Handle, loopcount); m_Handle = pkAS->ALPlay(m_Handle); return true; } bool ALAudioSource::Stop() { if ( GetPlayState() == 1 ) { return false; } if (!GetLoaded() || m_Handle == NULL_AUDIOHANDLE) return false; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); bool succ = pkAS->ALStop(m_Handle); //Release(); return (succ); } void ALAudioSource::Rewind() { } AudioSource::Status ALAudioSource::GetStatus() { if (!GetLoaded()) return AudioSource::NOT_SET; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); if ((m_Handle==NULL_AUDIOHANDLE) && (m_eDoneStatus==AudioSource::DONE)) return AudioSource::DONE; AudioSource::Status state; if (!pkAS->GetSourceStatus(m_Handle, state)) return AudioSource::NOT_SET; return state; } bool ALAudioSource::SetPlayTime(float fTime) { return AudioSource::SetPlayTime( fTime ); } float ALAudioSource::GetPlayTime() { return 0.0f; } bool ALAudioSource::GetPlayLength(float& fTime) { return false; } bool ALAudioSource::SetPlayPosition(unsigned int uiPos) { return false; } unsigned int ALAudioSource::GetPlayPosition() { return 0; } bool ALAudioSource::SetRoomEffectLevel(float fLevel) { return false; } float ALAudioSource::GetRoomEffectLevel() { return 0.0f; } bool ALAudioSource::SetOcclusionFactor(float fLevel) { return false; } float ALAudioSource::GetOcclusionFactor() { return 0.0f; } bool ALAudioSource::SetObstructionFactor(float fLevel) { return false; } float ALAudioSource::GetObstructionFactor() { return 0.0f; } NiPoint3 ALAudioSource::GetPosition() { NiPoint3 pos; if ( m_Handle == NULL_AUDIOHANDLE || m_uiInitialType != AudioSource::TYPE_3D ) return NiPoint3::ZERO; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); pkAS->ALGetSourcefv(m_Handle, AL_POSITION, (float*)&pos[0]); return pos; } void ALAudioSource::GetOrientation(NiPoint3& kDir, NiPoint3& kUp) { if ( m_Handle == NULL_AUDIOHANDLE || m_uiInitialType != AudioSource::TYPE_3D ) return; ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); float val[6]; pkAS->ALGetSourcefv(m_Handle, AL_ORIENTATION, val); kDir.x = val[0]; kDir.y = val[1]; kDir.z = val[2]; kUp.x = val[3]; kUp.y = val[4]; kUp.z = val[5]; } void ALAudioSource::DelayStop( uint32 seconds ) { m_delay_stop = seconds + (uint32)time( NULL ); } void ALAudioSource::Update(float fTime) { if( interlocked_read( &m_wantplay ) == 1 ) { if( RealPlay() ) interlocked_write( &m_wantplay, 2 ); else interlocked_write( &m_wantplay, 0 ); } AudioSource::Update(fTime); AudioSource::Status eCurStatus = GetStatus(); if (m_ePrevStatus != eCurStatus) { if (m_fnStateChangedCallBack && (m_eCallBackStatus == NOT_SET || (m_eCallBackStatus != NOT_SET && m_eCallBackStatus == eCurStatus))) m_fnStateChangedCallBack(this, eCurStatus); m_ePrevStatus = eCurStatus; } if (((GetStatus() == AudioSource::DONE) || (GetStatus() == AudioSource::FREE) || (GetStatus() == AudioSource::PLAYING && GetGain() < 0.0001f))&& GetPlayState() == 2 ) { m_eDoneStatus = AudioSource::DONE; Release(); } if (m_Handle == NULL_AUDIOHANDLE || GetType() != TYPE_3D) return; UpdateWorldTransfrom(); if( this->m_ePrevStatus == AudioSource::PLAYING && m_delay_stop && (uint32)time(NULL) >= m_delay_stop ) { Release(); m_delay_stop = 0; } } void ALAudioSource::UpdateWorldTransfrom() { NiPoint3 worldLoc = GetWorldTranslate(); NiPoint3 worldVel = GetWorldVelocity(); ALAudioSystem* pkAS = (ALAudioSystem*)AudioSystem::GetAudioSystem(); pkAS->ALSource3f(m_Handle, AL_POSITION, worldLoc.x, worldLoc.y, worldLoc.z); pkAS->ALSource3f(m_Handle, AL_VELOCITY, worldVel.x, worldVel.y, worldVel.z); }