/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of HPL1 Engine. */ #include "hpl1/engine/sound/SoundHandler.h" #include "hpl1/engine/math/Math.h" #include "hpl1/engine/resources/Resources.h" #include "hpl1/engine/resources/SoundManager.h" #include "hpl1/engine/sound/LowLevelSound.h" #include "hpl1/engine/sound/SoundChannel.h" #include "hpl1/engine/sound/SoundData.h" #include "hpl1/engine/system/String.h" #include "hpl1/engine/system/low_level_system.h" #include "hpl1/engine/physics/PhysicsBody.h" #include "hpl1/engine/physics/PhysicsWorld.h" #include "hpl1/engine/scene/World3D.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cSoundHandler::cSoundHandler(iLowLevelSound *apLowLevelSound, cResources *apResources) { mpLowLevelSound = apLowLevelSound; mpResources = apResources; mfSpeed = 1; mfNewSpeed = 1; mfSpeedRate = 0; mfVolume = 1; mfNewVolume = 1; mfVolumeRate = 0; mpWorld3D = NULL; mlCount = 0; mlIdCount = 0; mbSilent = false; mAffectedBySpeed = eSoundDest_World; mAffectedByVolume = eSoundDest_World; } //----------------------------------------------------------------------- cSoundHandler::~cSoundHandler() { tSoundEntryListIt it; it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { it->mpSound->Stop(); hplDelete(it->mpSound); it = mlstGuiSounds.erase(it); } it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { it->mpSound->Stop(); hplDelete(it->mpSound); it = mlstWorldSounds.erase(it); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// void cSoundRayCallback::Reset() { mbHasCollided = false; } bool cSoundRayCallback::BeforeIntersect(iPhysicsBody *pBody) { if (pBody->GetBlocksSound()) return true; return false; } bool cSoundRayCallback::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { mbHasCollided = true; return false; } //----------------------------------------------------------------------- void cSoundEntry::Update(float afTimeStep) { if (mfNormalVolumeMul != mfNormalVolumeFadeDest) { // Log("speed %s: %f\n", msName.c_str(),mfNormalVolumeFadeSpeed); mfNormalVolumeMul += mfNormalVolumeFadeSpeed * afTimeStep; if (mfNormalVolumeMul < 0) mfNormalVolumeMul = 0; if (mfNormalVolumeMul > 1) mfNormalVolumeMul = 1; if (mfNormalVolumeFadeSpeed < 0) { if (mfNormalVolumeMul <= mfNormalVolumeFadeDest) { mfNormalVolumeMul = mfNormalVolumeFadeDest; } } else { if (mfNormalVolumeMul >= mfNormalVolumeFadeDest) { mfNormalVolumeMul = mfNormalVolumeFadeDest; } } } if (ABS(mfNormalVolumeFadeDest) < 0.001f && ABS(mfNormalVolumeMul) < 0.001f && mfNormalVolumeFadeSpeed <= 0) { mpSound->Stop(); } } //----------------------------------------------------------------------- iSoundChannel *cSoundHandler::Play(const tString &asName, bool abLoop, float afVolume, const cVector3f &avPos, float afMinDist, float afMaxDist, eSoundDest mType, bool abRelative, bool ab3D, int alPriorityModifier, eSoundDest aEffectType) { if (asName == "") return NULL; // Calculate priority int lPrio = 255; if (mType == eSoundDest_World && !abRelative) { lPrio = alPriorityModifier; float fDist = cMath::Vector3Dist(avPos, mpLowLevelSound->GetListenerPosition()); if (fDist >= afMaxDist) lPrio += 0; else if (fDist >= afMinDist) lPrio += 10; else lPrio += 100; } // Create sound channel iSoundChannel *pSound = CreateChannel(asName, lPrio); if (pSound == NULL) { Warning("Can't find sound '%s' (may also be due too many sounds playing).\n", asName.c_str()); return NULL; } // Set up channel pSound->SetLooping(abLoop); pSound->SetMinDistance(afMinDist); pSound->SetMaxDistance(afMaxDist); pSound->Set3D(ab3D); pSound->SetPriority(lPrio); /////// NEW -- Set sound to use Environment if its a world sound if (aEffectType == eSoundDest_World) pSound->SetAffectedByEnv(true); ////////////////////////////////////////////////////////////////// if (mType == eSoundDest_Gui) { pSound->SetPositionRelative(true); // pSound->SetPosition(avPos); pSound->SetRelPosition(avPos); cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), avPos); pSound->SetPosition(vPos); // Needed? // pSound->SetPosition(mpLowLevelSound->GetListenerPosition() + // pSound->GetRelPosition()); } else { pSound->SetPositionRelative(abRelative); if (abRelative) { pSound->SetRelPosition(avPos); cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), avPos); pSound->SetPosition(vPos); } else { pSound->SetPosition(avPos); } } pSound->SetId(mlIdCount); cSoundEntry Entry; Entry.mpSound = pSound; Entry.mfNormalVolume = afVolume; Entry.msName = asName; Entry.mfNormalSpeed = 1.0f; Entry.mfBlockFadeDest = 1; Entry.mfBlockFadeSpeed = 1; Entry.mfBlockMul = 1; Entry.mbFirstTime = true; Entry.mEffectType = aEffectType; //////////////////////// // Set start volume // GUI if (mType == eSoundDest_Gui) { pSound->SetVolume(afVolume); } // World else { pSound->SetVolume(0); // UpdateDistanceVolume3D(&Entry,1.0f/60.0f,false,mType); } // If it is silent do everything as normal except stop the sound at start. if (mbSilent) { pSound->SetLooping(false); pSound->Stop(); } else { pSound->Play(); } if (mType == eSoundDest_Gui) { mlstGuiSounds.push_back(Entry); } else { mlstWorldSounds.push_back(Entry); } // Log("Starting sound '%s' prio: %d\n", pSound->GetData()->GetName().c_str(), // pSound->GetPriority()); mlIdCount++; return pSound; } //----------------------------------------------------------------------- iSoundChannel *cSoundHandler::PlayGui(const tString &asName, bool abLoop, float afVolume, const cVector3f &avPos, eSoundDest aEffectType) { return Play(asName, abLoop, afVolume, avPos, 1.0f, 1000.0f, eSoundDest_Gui, true, false, 0, aEffectType); } //----------------------------------------------------------------------- iSoundChannel *cSoundHandler::PlayStream(const tString &asFileName, bool abLoop, float afVolume, bool ab3D, eSoundDest aEffectType) { if (asFileName == "") return NULL; iSoundData *pData = mpResources->GetSoundManager()->CreateSoundData(asFileName, true, abLoop); if (pData == NULL) { Error("Couldn't load stream '%s'\n", asFileName.c_str()); return nullptr; } iSoundChannel *pSound = pData->CreateChannel(256); if (!pSound) { Error("Can't create sound channel for '%s'\n", asFileName.c_str()); return NULL; } // If it is silent do everything as normal except stop the sound at start. if (mbSilent) { // pSound->SetLooping(false); pSound->Stop(); } else { pSound->Play(); } pSound->SetId(mlIdCount); pSound->Set3D(ab3D); cSoundEntry Entry; Entry.mpSound = pSound; Entry.mfNormalVolume = afVolume; Entry.msName = asFileName; Entry.mfNormalSpeed = 1.0f; Entry.mfBlockFadeDest = 1; Entry.mfBlockFadeSpeed = 1; Entry.mfBlockMul = 1; Entry.mbFirstTime = true; Entry.mbStream = true; Entry.mEffectType = aEffectType; ///////////////////////// // Setup position pSound->SetPositionRelative(true); pSound->SetRelPosition(cVector3f(0, 0, 1)); cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), pSound->GetRelPosition()); pSound->SetPosition(vPos); mlstGuiSounds.push_back(Entry); mlIdCount++; return pSound; } //----------------------------------------------------------------------- bool cSoundHandler::Stop(const tString &asName) { cSoundEntry *pEntry = GetEntry(asName); if (pEntry) { pEntry->mpSound->Stop(); } else { return false; } return true; } //----------------------------------------------------------------------- bool cSoundHandler::StopAllExcept(const tString &asName) { return false; } //----------------------------------------------------------------------- void cSoundHandler::StopAll(tFlag mTypes) { tSoundEntryListIt it; if (mTypes & eSoundDest_Gui) { it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { it->mpSound->SetPaused(false); it->mpSound->Stop(); it++; } } if (mTypes & eSoundDest_World) { it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { // Log("Stopping: %s\n",it->mpSound->GetData()->GetName().c_str()); it->mpSound->SetPaused(false); it->mpSound->Stop(); it++; } } } //----------------------------------------------------------------------- void cSoundHandler::PauseAll(tFlag mTypes) { tSoundEntryListIt it; if (mTypes & eSoundDest_Gui) { it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { it->mpSound->SetPaused(true); it++; } } if (mTypes & eSoundDest_World) { it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { it->mpSound->SetPaused(true); it++; } } } //----------------------------------------------------------------------- void cSoundHandler::ResumeAll(tFlag mTypes) { tSoundEntryListIt it; if (mTypes & eSoundDest_Gui) { it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { it->mpSound->SetPaused(false); it++; } } if (mTypes & eSoundDest_World) { it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { it->mpSound->SetPaused(false); it++; } } } //----------------------------------------------------------------------- bool cSoundHandler::IsPlaying(const tString &asName) { cSoundEntry *pEntry = GetEntry(asName); if (pEntry) return pEntry->mpSound->IsPlaying(); return false; } //----------------------------------------------------------------------- bool cSoundHandler::IsValid(iSoundChannel *apChannel) { tSoundEntryListIt it; it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { if (it->mpSound == apChannel) return true; it++; } it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { if (it->mpSound == apChannel) return true; it++; } return false; } //----------------------------------------------------------------------- bool cSoundHandler::IsValidId(iSoundChannel *apChannel, int alId) { if (apChannel == NULL) return false; tSoundEntryListIt it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { if (it->mpSound == apChannel && it->mpSound->GetId() == alId) return true; it++; } it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { if (it->mpSound == apChannel && it->mpSound->GetId() == alId) return true; it++; } return false; } //----------------------------------------------------------------------- void cSoundHandler::Update(float afTimeStep) { if (mfNewSpeed != mfSpeed) { mfSpeed += mfSpeedRate; if (mfSpeedRate < 0 && mfSpeed < mfNewSpeed) mfSpeed = mfNewSpeed; if (mfSpeedRate > 0 && mfSpeed > mfNewSpeed) mfSpeed = mfNewSpeed; } if (mfNewVolume != mfVolume) { mfVolume += mfVolumeRate * afTimeStep; if (mfVolumeRate < 0 && mfVolume < mfNewVolume) mfVolume = mfNewVolume; if (mfVolumeRate > 0 && mfVolume > mfNewVolume) mfVolume = mfNewVolume; } tSoundEntryListIt it; it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { if (UpdateEntry(&(*it), afTimeStep, eSoundDest_Gui) == false) { it = mlstGuiSounds.erase(it); } else { ++it; } } it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { if (UpdateEntry(&(*it), afTimeStep, eSoundDest_World) == false) { it = mlstWorldSounds.erase(it); } else { ++it; } } mlCount++; } //----------------------------------------------------------------------- /** * * \todo support types. * \param afSpeed New speed to run sounds at * \param afRate Rate by which the current speed transform to the new * \param mTypes Types affected, not working yet :S */ void cSoundHandler::SetSpeed(float afSpeed, float afRate, tFlag aTypes) { mfNewSpeed = afSpeed; if (mfNewSpeed > mfSpeed && afRate < 0) afRate = -afRate; if (mfNewSpeed < mfSpeed && afRate > 0) afRate = -afRate; mfSpeedRate = afRate; mAffectedBySpeed = aTypes; if (afRate == 0) mfSpeed = mfNewSpeed; } //----------------------------------------------------------------------- void cSoundHandler::SetVolume(float afVolume, float afRate, tFlag aTypes) { mfNewVolume = afVolume; if (mfNewVolume > mfVolume && afRate < 0) afRate = -afRate; if (mfNewVolume < mfVolume && afRate > 0) afRate = -afRate; mfVolumeRate = afRate; mAffectedByVolume = aTypes; if (afRate == 0) mfVolume = mfNewVolume; } //----------------------------------------------------------------------- void cSoundHandler::SetWorld3D(cWorld3D *apWorld3D) { mpWorld3D = apWorld3D; } //----------------------------------------------------------------------- cSoundEntry *cSoundHandler::GetEntryFromSound(iSoundChannel *apSound) { tSoundEntryListIt it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { if (it->mpSound == apSound) { // Log("returning from GUI %d\n",&(*it)); return &(*it); } ++it; } it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { if (it->mpSound == apSound) { // Log("returning from World %d\n",&(*it)); return &(*it); } ++it; } return NULL; } //----------------------------------------------------------------------- tSoundEntryList *cSoundHandler::GetWorldEntryList() { return &mlstWorldSounds; } tSoundEntryList *cSoundHandler::GetGuiEntryList() { return &mlstGuiSounds; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- bool cSoundHandler::UpdateEntry(cSoundEntry *apEntry, float afTimeStep, tFlag aTypes) { // if(apEntry->mbStream) return; apEntry->Update(afTimeStep); /*Log("Updating entry: '%s' vol: %f playing: %d\n",apEntry->msName.c_str(), apEntry->mpSound->GetVolume(), apEntry->mpSound->IsPlaying()?1:0);*/ // Log("Pos: %s\n",apEntry->mpSound->GetPosition().ToString().c_str()); if (!apEntry->mpSound->IsPlaying() && !apEntry->mpSound->GetPaused()) { iSoundChannel *pSound = apEntry->mpSound; if (pSound->GetStopUsed() == false && pSound->GetCallBack() && pSound->GetLooping() && apEntry->mfNormalVolumeFadeDest != 0) { pSound->GetCallBack()->OnPriorityRelease(); // Log("On prio release!\n"); } // Log("Stopping: %s Time: %f / %f\n",pSound->GetData()->GetName().c_str(), // pSound->GetElapsedTime(), // pSound->GetTotalTime()); pSound->Stop(); hplDelete(pSound); return false; } else { if (mAffectedBySpeed & apEntry->mEffectType) { float fSpeed = mfSpeed * apEntry->mfNormalSpeed; if (apEntry->mpSound->GetSpeed() != fSpeed) { apEntry->mpSound->SetSpeed(fSpeed); } } else { if (apEntry->mpSound->GetSpeed() != apEntry->mfNormalSpeed) { apEntry->mpSound->SetSpeed(apEntry->mfNormalSpeed); } } ////////////////////////////// // Update block fade: if (apEntry->mfBlockMul != apEntry->mfBlockFadeDest) { apEntry->mfBlockMul += apEntry->mfBlockFadeSpeed * afTimeStep; if (apEntry->mfBlockFadeSpeed < 0) { if (apEntry->mfBlockMul < apEntry->mfBlockFadeDest) apEntry->mfBlockMul = apEntry->mfBlockFadeDest; } else { if (apEntry->mfBlockMul > apEntry->mfBlockFadeDest) apEntry->mfBlockMul = apEntry->mfBlockFadeDest; } } // Update the sound position // 3D Position! if (apEntry->mbStream) { apEntry->mpSound->SetVolume(apEntry->mfNormalVolume * apEntry->mfNormalVolumeMul * mfVolume); } // else if(apEntry->mpSound->Get3D()) if (apEntry->mpSound->Get3D()) { UpdateDistanceVolume3D(apEntry, afTimeStep, apEntry->mbFirstTime ? false : true, aTypes); } // 2D Position else { if (apEntry->mpSound->GetPositionRelative()) { iSoundChannel *pSound = apEntry->mpSound; cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), pSound->GetRelPosition()); pSound->SetPosition(vPos); if (apEntry->mEffectType & mAffectedByVolume) { pSound->SetVolume(apEntry->mfNormalVolume * apEntry->mfNormalVolumeMul * mfVolume); } else { pSound->SetVolume(apEntry->mfNormalVolume * apEntry->mfNormalVolumeMul); } } else { iSoundChannel *pSound = apEntry->mpSound; float fDX = pSound->GetPosition().x - mpLowLevelSound->GetListenerPosition().x; float fDY = pSound->GetPosition().y - mpLowLevelSound->GetListenerPosition().y; float fDist = sqrt(fDX * fDX + fDY * fDY); if (fDist >= pSound->GetMaxDistance()) { pSound->SetVolume(0); } else { if (fDist < pSound->GetMinDistance()) { pSound->SetVolume(apEntry->mfNormalVolume); // some other stuff to support volume effects } else { float fVolume = 1 - ((fDist - pSound->GetMinDistance()) / (pSound->GetMaxDistance() - pSound->GetMinDistance())); fVolume *= apEntry->mfNormalVolume; pSound->SetVolume(fVolume); } float fPan = 1 - (0.5f - 0.4f * (fDX / pSound->GetMaxDistance())); pSound->SetPan(fPan); } } } } apEntry->mbFirstTime = false; return true; } //----------------------------------------------------------------------- void cSoundHandler::UpdateDistanceVolume3D(cSoundEntry *apEntry, float afTimeStep, bool abFade, tFlag aTypes) { if (mpWorld3D == NULL) { return; } if (apEntry->mpSound->GetPositionRelative()) { iSoundChannel *pSound = apEntry->mpSound; cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), pSound->GetRelPosition()); pSound->SetPosition(vPos); // cVector3f vPos = cMath::MatrixMul(mpLowLevelSound->GetListenerMatrix(), // pSound->GetRelPosition()); // pSound->SetPosition(pSound->GetRelPosition()); if (aTypes & mAffectedByVolume) { pSound->SetVolume(apEntry->mfNormalVolume * apEntry->mfNormalVolumeMul * mfVolume); } else { pSound->SetVolume(apEntry->mfNormalVolume * apEntry->mfNormalVolumeMul); } } else { // Log("%s ",apEntry->msName.c_str()); iSoundChannel *pSound = apEntry->mpSound; float fDist = cMath::Vector3Dist(pSound->GetPosition(), mpLowLevelSound->GetListenerPosition()); if (fDist >= pSound->GetMaxDistance()) { pSound->SetVolume(0); // Set very low priority pSound->SetPriority(0); // Log(" max distance "); } else { float fVolume = 0; // bool bBlocked = false; //////////////////////////////////////// // Check if sound is blocked. if (pSound->GetBlockable() && mpWorld3D && mpWorld3D->GetPhysicsWorld() && (apEntry->mlCount % 30) == 0) { iPhysicsWorld *pPhysicsWorld = mpWorld3D->GetPhysicsWorld(); mSoundRayCallback.Reset(); pPhysicsWorld->CastRay(&mSoundRayCallback, pSound->GetPosition(), mpLowLevelSound->GetListenerPosition(), false, false, false, true); // Log(" from (%s) to (%s) ",pSound->GetPosition().ToString().c_str(), // mpLowLevelSound->GetListenerPosition().ToString().c_str()); // Log(" callback: %d ",mSoundRayCallback.HasCollided()?1:0); if (mSoundRayCallback.HasCollided()) { apEntry->mfBlockFadeDest = 0.0f; apEntry->mfBlockFadeSpeed = -1.0f / 0.55f; if (abFade == false) { apEntry->mfBlockMul = 0.0f; } pSound->SetFiltering(true, 0xF); // bBlocked = true; } else { // pSound->SetFiltering(false, 0xF); apEntry->mfBlockFadeDest = 1; apEntry->mfBlockFadeSpeed = 1.0f / 0.2f; if (abFade == false) { apEntry->mfBlockMul = 1.0f; } } // Log("Blocked: %d ",bBlocked ? 1 : 0); } ++apEntry->mlCount; ///////////////////////////////////// // Lower volume according to distance if (fDist < pSound->GetMinDistance()) { // Set high priority pSound->SetPriority(100); fVolume = apEntry->mfNormalVolume; // some other stuff to support volume effects } else { // Set medium priority pSound->SetPriority(10); float fDelta = fDist - pSound->GetMinDistance(); float fMaxDelta = pSound->GetMaxDistance() - pSound->GetMinDistance(); fVolume = 1 - (fDelta / fMaxDelta); float fSqr = fVolume * fVolume; // Log("Lin: %f Sqr: %f ",fVolume,fSqr); // fade between normal and square fVolume = fVolume * apEntry->mfBlockMul + (1.0f - apEntry->mfBlockMul) * fSqr; // Log("Mix: %f ",fVolume); fVolume *= apEntry->mfNormalVolume; } float fBlock = pSound->GetBlockVolumeMul() + apEntry->mfBlockMul * (1 - pSound->GetBlockVolumeMul()); if (aTypes & apEntry->mEffectType) { pSound->SetVolume(fBlock * fVolume * apEntry->mfNormalVolumeMul * mfVolume); // pSound->SetFilterGainHF(fBlock * fVolume * apEntry->mfNormalVolumeMul * mfVolume); } else { pSound->SetVolume(fBlock * fVolume * apEntry->mfNormalVolumeMul); } // pSound->SetFilterGainHF(0.1f); // Log("Vol: %f\n",fBlock * fVolume * apEntry->mfNormalVolumeMul); // Log("%s Block: %f\n",apEntry->msName.c_str(),apEntry->mfBlockMul); } } } //----------------------------------------------------------------------- cSoundEntry *cSoundHandler::GetEntry(const tString &asName) { tSoundEntryListIt it = mlstGuiSounds.begin(); while (it != mlstGuiSounds.end()) { if (cString::ToLowerCase(it->msName) == cString::ToLowerCase(asName)) { return &(*it); } it++; } it = mlstWorldSounds.begin(); while (it != mlstWorldSounds.end()) { // Log("'%s' vs '%s'\n", it->msName.c_str(), asName.c_str()); if (cString::ToLowerCase(it->msName) == cString::ToLowerCase(asName)) { return &(*it); } it++; } return NULL; } //----------------------------------------------------------------------- iSoundChannel *cSoundHandler::CreateChannel(const tString &asName, int alPriority) { int lNum = cString::ToInt(cString::GetLastChar(asName).c_str(), 0); iSoundChannel *pSound = NULL; iSoundData *pData = NULL; tString sName; tString sBaseName = asName; // Try loading it from the buffer if (lNum >= 1 && lNum <= 9) { pData = mpResources->GetSoundManager()->CreateSoundData(asName, false); } else { int lCount = 0; int lLastNum = -1; // Check what the last sound played was. tPlayedSoundNumMapIt SoundIt = m_mapPlayedSound.find(sBaseName); if (SoundIt == m_mapPlayedSound.end()) { m_mapPlayedSound.insert(tPlayedSoundNumMap::value_type(sBaseName, 0)); SoundIt = m_mapPlayedSound.find(sBaseName); } else { lLastNum = SoundIt->second; } sName = sBaseName + cString::ToString(lCount + 1); pData = mpResources->GetSoundManager()->CreateSoundData(sName, false); while (pData) { lCount++; sName = sBaseName + cString::ToString(lCount + 1); pData = mpResources->GetSoundManager()->CreateSoundData(sName, false); } if (lCount > 0) { int lNum2 = cMath::RandRectl(1, lCount); if (lCount > 2) { while (lLastNum == lNum2) lNum2 = cMath::RandRectl(1, lCount); } SoundIt->second = lNum2; sName = sBaseName + cString::ToString(lNum2); pData = mpResources->GetSoundManager()->CreateSoundData(sName, false); } else { pData = NULL; } } // Try to stream it if (pData == NULL) { sName = "stream_" + sBaseName; pData = mpResources->GetSoundManager()->CreateSoundData(sName, true); if (pData == NULL) { Error("Couldn't stream sound '%s'\n", asName.c_str()); return NULL; } } // Create sound channel pSound = pData->CreateChannel(alPriority); if (pSound == NULL) { // Warning("Couldn't play sound '%s'\n",asName.c_str()); } return pSound; } //----------------------------------------------------------------------- } // namespace hpl