#include "stdafx.h" #include "alaudiosystem.h" #include "ALAudio.h" #include "ALAudioSource.h" #include "alListener.h" #include "console.h" #include "NiParallelUpdateTaskManager.h" #include "ALAudioUpdateTask.h" void ALAudioSystem::Initialize() { ms_pAudioSystem = NiNew ALAudioSystem; ms_pAudioSystem->IncRefCount(); } void ALAudioSystem::Release() { if (ms_pAudioSystem) { NiDelete ms_pAudioSystem; ms_pAudioSystem = 0; } } ALAudioSystem::ALAudioSystem() { m_spListener = NiNew ALListener; m_fMasterVolume = 0.0f; m_iNumSources = 0; m_iRequestSources = 0; m_pSoundListPlaying = NULL; for( int i = 0; i < MAX_AUDIOSOURCES; ++i ) m_Sources[i] = INVALID_SOURCE; } ALAudioSystem::~ALAudioSystem() { m_listEffectAudio.clear(); m_pSoundListPlaying = 0; _asm nop } bool ALAudioSystem::Startup(const char* pcDirectoryname) { pcDirectoryname; if (!ALInitOpenAL(ALFunction)) return false; ALenum err = ALFunction.alGetError(); m_iRequestSources = MAX_AUDIOSOURCES; while (true) { ALFunction.alGenSources(m_iRequestSources, m_Sources); err = alGetError(); if (err == AL_NO_ERROR) break; // succ m_iRequestSources--; if (m_iRequestSources == 0) { Shutdown(); return false; } } m_iNumSources = m_iRequestSources; NIASSERT(m_iNumSources > 0); err = ALFunction.alGetError(); if (err != AL_NO_ERROR) { _asm nop } ALFunction.alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); err = ALFunction.alGetError(); if (err != AL_NO_ERROR) { _asm nop } //memset(m_Handle, NULL_AUDIOHANDLE, sizeof(m_Handle)); for ( int i = 0; i < MAX_AUDIOSOURCES; ++i ) { m_Handle[i] = NULL_AUDIOHANDLE; } m_hLastHandle = NULL_AUDIOHANDLE; m_fMasterVolume = 1.0f; err = ALFunction.alGetError(); // AudioSysUpdateTask::_SDMInit(); ALFunction.alEnable(AL_DISTANCE_MODEL); return (err==AL_NO_ERROR); } void ALAudioSystem::Shutdown() { // AudioSysUpdateTask::_SDMShutdown(); ALboolean ret = ALShutdownOpenAL(); // Unload all of the Sources if (m_pSources) { // // Any sources that have already released themselves will have been // removed from this list. // NiTListIterator pos = m_pSources->GetHeadPos(); while (pos) { ALAudioSource* pSource = (ALAudioSource*)m_pSources->GetNext(pos); pSource->Unload(); } m_pSources->RemoveAll(); } // // Release and decrement/destroy the listener // if (m_spListener) NiSmartPointerCast(ALListener,m_spListener)->Release(); ALFunction.alGenSources(m_iRequestSources, m_Sources); CheckError(); } void ALAudioSystem::Update(float fTime, bool bUpdateAll /*= false*/) { //if (1 && NiParallelUpdateTaskManager::IsActive()) //{ // AudioSysUpdateTask* pkTask = AudioSysUpdateTask::GetFreeObject(); // if (pkTask) // { // pkTask->Init(this, fTime); // if (NiParallelUpdateTaskManager::Get()->AddTask(pkTask)) // { // return; // } // // Failed to add task, clean up task and fall through // pkTask->Clear(); // } //} Do_UpdateSystem(fTime, bUpdateAll); } void ALAudioSystem::Do_UpdateSystem(float fTime, bool bUpdateAll) { for ( std::list< AudioSourcePtr >::iterator it = m_listEffectAudio.begin(); it != m_listEffectAudio.end(); ) { AudioSourcePtr pSound = (*it); if ( pSound->NeedRelease() ) { //pSound->Stop(); pSound->DelayStop( 10 ); it = m_listEffectAudio.erase( it ); } else ++it; } std::list< AudioSourcePtr >::iterator itPlay = m_listPlayList.begin(); if ( itPlay != m_listPlayList.end() ) { if ( !( m_pSoundListPlaying && !m_pSoundListPlaying->NeedRelease() ) ) { m_pSoundListPlaying = NULL; m_pSoundListPlaying = *itPlay; m_pSoundListPlaying->Play(); m_listPlayList.erase( itPlay ); } } AudioSystem::Update(fTime, bUpdateAll); } bool ALAudioSystem::IsPlaying(AUDIOHANDLE handle) const { return false; } void ALAudioSystem::UpdateMaxDistance() { if (!m_spListener) return; for(unsigned int i = 0; i < m_iNumSources; i++) { if(m_Handle[i] == NULL_AUDIOHANDLE) continue; ALuint src = m_Sources[i]; ALint val = AL_FALSE; ALFunction.alGetSourcei(src, AL_SOURCE_RELATIVE, &val); if(val == AL_TRUE) continue; NiPoint3 pos; ALFunction.alGetSourcefv(src, AL_POSITION, (float*)&pos[0]); float dist = 0.f; ALFunction.alGetSourcef(src, AL_MAX_DISTANCE, &dist); pos -= m_spListener->GetPosition(); dist -= pos.Length(); float gain = (dist < 0.f) ? 0.f : m_SourceVolume[i] * GetMasterVolume(); ALFunction.alSourcef(src, AL_GAIN, linearToDB(gain)); CheckError(); } } void ALAudioSystem::UpdateScores(bool sourceOnly) { } void ALAudioSystem::LoopingUpdate() { std::map::iterator it = m_LoopingList.begin(); while (it != m_LoopingList.end()) { ALint state = 0; ALGetSourcei(it->second.handle, AL_SOURCE_STATE, &state); if (it->second.state != AL_INITIAL && it->second.state != state) { if (g_pkConsole) g_pkConsole->Printf(121, "handle:%d, state:%d\n", it->second.handle, state); } ++it; } } AudioSource* ALAudioSystem::CreateSource(unsigned int uiType /*= AudioSource::TYPE_DEFAULT*/) { return NiNew ALAudioSource(uiType); } void ALAudioSystem::SetAudioTypeVolume(int type, float volume) { m_AudioTypeVolume[type] = volume; } float ALAudioSystem::GetAudioTypeVolume(int type) const { return m_AudioTypeVolume[type]; } void ALAudioSystem::SetMasterVolume(float volume) { m_fMasterVolume = volume; } float ALAudioSystem::GetMasterVolume() const { return m_fMasterVolume; } AUDIOHANDLE ALAudioSystem::GetNewHandle() { m_hLastHandle = m_hLastHandle++%65536; m_hLastHandle &= HANDLE_MASK; if (m_hLastHandle == NULL_AUDIOHANDLE) m_hLastHandle++; return m_hLastHandle; } AudioBufferPtr ALAudioSystem::LoadALSource(ALAudioSource* src) { const char* szFileName = src->GetFilename(); if (!szFileName || szFileName[0]=='\0') return 0; AudioBufferPtr audioBuff; ALAudioSource* pDup = NULL; if (!src->GetStreamed()) { pDup = (ALAudioSource*)FindDuplicateSource(src); if (pDup && !pDup->GetStreamed()) { audioBuff = pDup->GetBuffer(); } else { audioBuff = AudioBuffer::find(szFileName); } } else { audioBuff = AudioBuffer::find(szFileName); } return audioBuff; } AUDIOHANDLE ALAudioSystem::CreateALSourceHandle(ALAudioSource* src) { AudioBufferPtr spBuff = src->GetBuffer(); if (!spBuff) return NULL_AUDIOHANDLE; unsigned int index = MAX_AUDIOSOURCES; if (!FindFreeSource(index)) { // UpdateScores(true); // if (!CullSource(&index, vol)) // index = MAX_AUDIOSOURCES; } if (index == MAX_AUDIOSOURCES) return NULL_AUDIOHANDLE; ALuint buffID = spBuff->getALBuffer(); if (!buffID) return NULL_AUDIOHANDLE; ALFunction.alSourcei(m_Sources[index], AL_BUFFER, buffID); m_Handle[index] = GetNewHandle() | AUDIOHANDLE_INACTIVE_BIT; return (m_Handle[index] & RETURN_MASK); } void ALAudioSystem::ReleaseALSourceHandle(ALAudioSource* src) { AUDIOHANDLE handle = src->GetHandle(); unsigned int index = FindIndex(handle); if (index != MAX_AUDIOSOURCES) { if (m_Sources[index] != INVALID_SOURCE) ALFunction.alSourcei(m_Sources[index], AL_BUFFER, 0); m_Handle[index] = NULL_AUDIOHANDLE; } } bool ALAudioSystem::GetSourceStatus(AUDIOHANDLE handle, AudioSource::Status& status) const { if (handle == NULL_AUDIOHANDLE) { status = AudioSource::NOT_SET; return false; } ALint state = 0; LoopingImage li(handle); AUDIOHANDLE hkey = handle; hkey &= HANDLE_MASK; { ALGetSourcei(handle, AL_SOURCE_STATE, &state); } switch(state) { case AL_INITIAL: status = AudioSource::NOT_SET; break; case AL_PLAYING: case AL_PAUSED: status = AudioSource::PLAYING; break; case AL_STOPPED: status = AudioSource::DONE; break; default: status = AudioSource::NOT_SET; break; } return true; } AudioSource::Status ALAudioSystem::GetStreamStatus(AUDIOHANDLE handle) const { ALint state = 0; ALGetSourcei(handle, AL_SOURCE_STATE, &state); switch(state) { case AL_INITIAL: return AudioSource::NOT_SET; case AL_PLAYING: case AL_PAUSED: return AudioSource::PLAYING; case AL_STOPPED: return AudioSource::DONE; } return AudioSource::FREE; } void ALAudioSystem::ALSetSourceVolume(AUDIOHANDLE handle, float vol) { if (handle == NULL_AUDIOHANDLE) return; unsigned int idx = FindIndex(handle); if (idx != MAX_AUDIOSOURCES) { float gain = vol * GetMasterVolume(); m_SourceVolume[idx] = gain; ALFunction.alSourcef(m_Sources[idx], AL_GAIN, gain/*linearToDB(gain)*/ ); //ALFunction.alSourcef(m_Sources[idx], AL_PITCH, 1.0f); } } bool ALAudioSystem::FindFreeSource(unsigned int& index) const { for(unsigned int i = 0; i < m_iNumSources; i++) if(m_Handle[i] == NULL_AUDIOHANDLE) { index = i; return(true); } return(false); } void ALAudioSystem::ALSourcef(AUDIOHANDLE handle, ALenum name, ALfloat value) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) { if (name == AL_GAIN) { value = DBToLinear(value); } if (name == AL_GAIN_LINEAR) { unsigned int index = FindIndex(handle); if (index == MAX_AUDIOSOURCES) return; m_SourceVolume[index] = value; float vol = NiClamp(GetMasterVolume() * m_TypeVolume[m_iType[index]] * m_SourceVolume[index], 0.f, 1.f); ALFunction.alSourcef(source, AL_GAIN, linearToDB(vol)); } else ALFunction.alSourcef(source, name, value); CheckError(); } } void ALAudioSystem::ALSourcevf(AUDIOHANDLE handle, ALenum name, ALfloat *values) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) ALFunction.alSourcefv(source, name, values); CheckError(); } void ALAudioSystem::ALSource3f(AUDIOHANDLE handle, ALenum name, ALfloat val1, ALfloat val2, ALfloat val3) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) { ALfloat vals[3]; vals[0] = val1; vals[1] = val2; vals[2] = val3; ALFunction.alSourcefv(source, name, vals); CheckError(); } } void ALAudioSystem::ALSourcei(AUDIOHANDLE handle, ALenum name, ALint value) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) ALFunction.alSourcei(source, name, value); CheckError(); } void ALAudioSystem::ALSourcePD(AUDIOHANDLE handle, const NiPoint3& pos, const NiPoint3& dir) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) { ALFunction.alSource3f(source, AL_POSITION, pos.x, pos.y, pos.z); CheckError(); ALFunction.alSource3f(source, AL_DIRECTION, dir.x, dir.y, dir.z); CheckError(); } } void ALAudioSystem::ALGetSourcef(AUDIOHANDLE handle, ALenum name, ALfloat *value) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) { if ((name == AL_GAIN) || (name == AL_GAIN_LINEAR)) { unsigned int idx = FindIndex(handle); if (idx == MAX_AUDIOSOURCES) { *value = 0.f; return; } if (name == AL_GAIN) *value = linearToDB(m_SourceVolume[idx]); else *value = m_SourceVolume[idx]; } else ALFunction.alGetSourcef(source, name, value); CheckError(); } } void ALAudioSystem::ALGetSourcefv(AUDIOHANDLE handle, ALenum name, ALfloat* values) { if((name == AL_POSITION) || (name == AL_DIRECTION) || (name == AL_VELOCITY)) ALGetSource3f(handle, name, &values[0], &values[1], &values[2]); CheckError(); } void ALAudioSystem::ALGetSource3f(AUDIOHANDLE handle, ALenum name, ALfloat* val1, ALfloat* val2, ALfloat* val3) { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) { ALfloat vals[3]; ALFunction.alGetSourcefv(source, name, vals); *val1 = vals[0]; *val2 = vals[1]; *val3 = vals[2]; CheckError(); } } void ALAudioSystem::ALGetSourcei(AUDIOHANDLE handle, ALenum name, ALint *value) const { ALuint source = FindSource(handle); if (source != INVALID_SOURCE) ALFunction.alGetSourcei(source, name, value); CheckError(); } void ALAudioSystem::ALListener3f(ALenum name, ALfloat val1, ALfloat val2, ALfloat val3) { ALFunction.alListener3f(name, val1, val2, val3); CheckError(); } void ALAudioSystem::ALListenerfv(ALenum name, ALfloat* val) { ALFunction.alListenerfv(name, val); CheckError(); } void ALAudioSystem::ALGetListener3f(ALenum name, ALfloat* val1, ALfloat* val2, ALfloat* val3) { ALFunction.alGetListener3f(name, val1, val2, val3); CheckError(); } void ALAudioSystem::ALGetListenerfv(ALenum name, ALfloat* values) { ALFunction.alGetListenerfv(name, values); CheckError(); } void ALAudioSystem::CheckError() const { ALenum code = ALFunction.alGetError(); #ifdef _DEBUG // NIASSERT(code == AL_NO_ERROR); #endif } AUDIOHANDLE ALAudioSystem::ALPlay(AUDIOHANDLE handle) { unsigned int index = FindIndex(handle); if (index != MAX_AUDIOSOURCES) { float vol = m_SourceVolume[index]; ALuint src = m_Sources[index]; NIASSERT(INVALID_SOURCE != src); NiPoint3 pos; float fMin, fMax; ALGetSourcef(handle, AL_REFERENCE_DISTANCE, &fMin); ALGetSourcef(handle, AL_MAX_DISTANCE, &fMax); ALint val = AL_FALSE; ALGetSourcei(handle, AL_SOURCE_RELATIVE, &val); if (val == AL_FALSE) { ALboolean isEnable = ALFunction.alGetBoolean(AL_DISTANCE_MODEL); NIASSERT(isEnable); ALGetSourcefv(handle, AL_POSITION, (float*)&pos[0]); ALListener* pkListener = GetListener(); NiPoint3 lpos = pkListener->GetPosition(); //vol = approximate3DVolume(fMax, fMin, pos); } vol = NiMin(1.0f, vol); vol = NiMax(0.0f, vol); ALFunction.alSourcef(src, AL_GAIN, vol/*linearToDB(vol)*/ ); CheckError(); m_Handle[index] &= ~(AUDIOHANDLE_INACTIVE_BIT | AUDIOHANDLE_LOADING_BIT); ALFunction.alSourcePlay(m_Sources[index]); CheckError(); float gain = 0.0f; if (val == AL_FALSE) { ALFunction.alGetSourcef(src, AL_GAIN, &gain); _asm nop } return m_Handle[index]; } return handle; } bool ALAudioSystem::ALStop(AUDIOHANDLE handle) { unsigned int index = FindIndex(handle); if (index != MAX_AUDIOSOURCES) { ALFunction.alSourceStop(m_Sources[index]); CheckError(); ALenum err = alGetError(); //m_Handle[index] &= AUDIOHANDLE_INACTIVE_BIT; return (err == AL_NO_ERROR); } return false; } unsigned int ALAudioSystem::FindIndex(AUDIOHANDLE handle) const { unsigned int ui = 0; for (ui = 0; ui < m_iNumSources; ui++) { if (m_Handle[ui] && areEqualHandles(m_Handle[ui], handle)) return ui; } return MAX_AUDIOSOURCES; } ALuint ALAudioSystem::FindSource(AUDIOHANDLE handle) const { unsigned int ui = 0; for (ui = 0; ui < m_iNumSources; ui++) { if (m_Handle[ui] && areEqualHandles(m_Handle[ui], handle)) return m_Sources[ui]; } return (INVALID_SOURCE); } float ALAudioSystem::approximate3DVolume(float maxdist, float refdist, const NiPoint3& p) { ALListener* pkListener = GetListener(); NiPoint3 pos = pkListener->GetPosition(); pos -= p; float dist = pos.Length(); if (dist > maxdist) { return 0.0f; } else if (dist < refdist) { return 1.0f; } return 1.0f - (dist - refdist) / (maxdist - refdist); } ALListener* ALAudioSystem::GetListener() { return (ALListener*)AudioSystem::GetListener(); } void ALAudioSystem::SetSourceLoopCount(AUDIOHANDLE handle, unsigned int loopcount) { const int idx = FindIndex(handle); if (idx == MAX_AUDIOSOURCES) return; ALFunction.alSourcei (m_Sources[idx], AL_LOOPING, loopcount > 1?AL_TRUE:AL_FALSE ); }