/* * SND_Scene.cpp * * The scene for sounds. * * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * 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 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * 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, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #ifdef WIN32 #pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning #endif //WIN32 #include "SND_Scene.h" #include "SND_DependKludge.h" #include "SYS_System.h" #include "SND_IAudioDevice.h" #include #include //static unsigned int tijd = 0; SND_Scene::SND_Scene(SND_IAudioDevice* audiodevice) : m_audiodevice(audiodevice) { if (m_audiodevice) m_wavecache = m_audiodevice->GetWaveCache(); if (!m_wavecache || !audiodevice) { m_audio = false; } else { //if so, go ahead! m_audio = true; #ifdef ONTKEVER printf("SND_Scene::SND_Scene() m_audio == true\n"); #endif m_audiodevice->InitListener(); } IsPlaybackWanted(); } SND_Scene::~SND_Scene() { StopAllObjects(); } // check if audioplayback is wanted bool SND_Scene::IsPlaybackWanted() { SYS_SystemHandle syshandle = SYS_GetSystem(); int audio = SYS_GetCommandLineInt(syshandle,"noaudio",0); if ((audio == 0) && m_audiodevice && m_wavecache) { m_audioplayback = true; } else { StopAllObjects(); m_audioplayback = false; } return m_audioplayback; } int SND_Scene::LoadSample(const STR_String& samplename, void* memlocation, int size) { int result = -1; if (m_audiodevice) { SND_WaveSlot* waveslot = m_audiodevice->LoadSample(samplename, memlocation, size); if (waveslot) result = waveslot->GetBuffer(); } return result; } void SND_Scene::RemoveAllSamples() { if (m_audio && m_audiodevice) m_audiodevice->RemoveAllSamples(); } bool SND_Scene::CheckBuffer(SND_SoundObject* pObject) { bool result = false; if (pObject && m_wavecache) { SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(pObject->GetSampleName()); if (waveslot) { pObject->SetBuffer(waveslot->GetBuffer()); result = true; } } return result; } bool SND_Scene::IsSampleLoaded(STR_String& samplename) { bool result = false; if (samplename && m_wavecache) { SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(samplename); if (waveslot && waveslot->IsLoaded()) result = true; } return result; } void SND_Scene::AddObject(SND_SoundObject* pObject) { if (m_audio) { STR_String samplename = pObject->GetSampleName(); SND_WaveSlot* slot = NULL; // don't add the object if no valid sample is referenced if (samplename != "") { // check if the sample is already loaded slot = m_wavecache->GetWaveSlot(samplename); } if (slot) { pObject->SetBuffer(slot->GetBuffer()); // needed for expected lifespan of the sample, but ain't necesary anymore i think MT_Scalar samplelength = slot->GetNumberOfSamples(); MT_Scalar samplerate = slot->GetSampleRate(); MT_Scalar soundlength = samplelength/samplerate; pObject->SetLength(soundlength); // add the object to the list m_soundobjects.insert((SND_SoundObject*)pObject); } } } void SND_Scene::SetListenerTransform(const MT_Vector3& pos, const MT_Vector3& vel, const MT_Matrix3x3& ori) { if (m_audio) { GetListener()->SetPosition(pos); GetListener()->SetVelocity(vel); GetListener()->SetOrientation(ori); } } void SND_Scene::UpdateListener() { // process the listener if modified if (m_listener.IsModified()) { m_audiodevice->SetListenerGain(m_listener.GetGain()); // fmod doesn't support dopplervelocity, so just use the dopplerfactor instead #ifdef USE_FMOD m_audiodevice->SetDopplerFactor(m_listener.GetDopplerVelocity()); #else m_audiodevice->SetDopplerVelocity(m_listener.GetDopplerVelocity()); m_audiodevice->SetDopplerFactor(m_listener.GetDopplerFactor()); #endif m_listener.SetModified(false); } } void SND_Scene::AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime) { if (m_audio) { if (pObject) { #ifdef ONTKEVER printf("SND_Scene::AddActiveObject\n"); #endif // first check if the object is already on the list if (pObject->IsActive()) { pObject->SetTimeStamp(curtime); pObject->StartSound(); } else { pObject->SetTimeStamp(curtime); // compute the expected lifespan pObject->SetLifeSpan(); // lets give the new active-to-be object an id if (m_audiodevice->GetNewId(pObject)) { // and add the object m_activeobjects.addTail(pObject); pObject->StartSound(); pObject->SetActive(true); } } } } } void SND_Scene::RemoveActiveObject(SND_SoundObject* pObject) { if (m_audio) { if (pObject) { #ifdef ONTKEVER printf("SND_Scene::RemoveActiveObject\n"); #endif // if inactive, remove it from the list if (pObject->IsActive()) { // first make sure it is stopped m_audiodevice->ClearId(pObject); } } } } void SND_Scene::UpdateActiveObects() { // ++tijd; SND_SoundObject* pObject; // update only the objects that need to be updated for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); !pObject->isTail(); pObject = (SND_SoundObject*)pObject->getNext()) { int id = pObject->GetId(); if (id >= 0) { bool juststartedplaying = false; #ifdef USE_FMOD // fmod wants these set before playing the sample if (pObject->IsModified()) { m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); } // ok, properties Set. now see if it must play if (pObject->GetPlaystate() == SND_MUST_PLAY) { m_audiodevice->PlayObject(id); pObject->SetPlaystate(SND_PLAYING); pObject->InitRunning(); // printf("start play: %d\n", tijd); juststartedplaying = true; } #endif if (pObject->Is3D()) { // Get the global positions and velocity vectors // of the listener and soundobject MT_Vector3 op = pObject->GetPosition(); MT_Vector3 lp = m_listener.GetPosition(); MT_Vector3 position = op - lp; // Calculate relative velocity in global coordinates // of the sound with respect to the listener. MT_Vector3 ov = pObject->GetVelocity(); MT_Vector3 lv = m_listener.GetVelocity(); MT_Vector3 velocity = ov - lv; // Now map the object position and velocity into // the local coordinates of the listener. MT_Matrix3x3 lo = m_listener.GetOrientation(); MT_Vector3 local_sound_pos = position * lo; MT_Vector3 local_sound_vel = velocity * lo; m_audiodevice->SetObjectTransform( id, local_sound_pos, local_sound_vel, pObject->GetOrientation(), // make relative to listener! lp, pObject->GetRollOffFactor()); } else { m_audiodevice->ObjectIs2D(id); } // update the situation if (pObject->IsModified()) { m_audiodevice->SetObjectPitch(id, pObject->GetPitch()); m_audiodevice->SetObjectGain(id, pObject->GetGain()); m_audiodevice->SetObjectMinGain(id, pObject->GetMinGain()); m_audiodevice->SetObjectMaxGain(id, pObject->GetMaxGain()); m_audiodevice->SetObjectReferenceDistance(id, pObject->GetReferenceDistance()); m_audiodevice->SetObjectRollOffFactor(id, pObject->GetRollOffFactor()); m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); pObject->SetModified(false); } pObject->AddRunning(); #ifdef ONTKEVER STR_String naam = pObject->GetObjectName(); STR_String sample = pObject->GetSampleName(); int id = pObject->GetId(); int buffer = pObject->GetBuffer(); float gain = pObject->GetGain(); float pitch = pObject->GetPitch(); float timestamp = pObject->GetTimestamp(); printf("naam: %s, sample: %s \n", naam.Ptr(), sample.Ptr()); printf("id: %d, buffer: %d \n", id, buffer); printf("gain: %f, pitch: %f, ts: %f \n\n", gain, pitch, timestamp); #endif #ifdef USE_OPENAL // ok, properties Set. now see if it must play if (pObject->GetPlaystate() == SND_MUST_PLAY) { m_audiodevice->PlayObject(id); pObject->SetPlaystate(SND_PLAYING); //break; } #endif // check to see if the sound is still playing // if not: release its id int playstate = m_audiodevice->GetPlayState(id); #ifdef ONTKEVER if (playstate != 2) printf("%d - ",playstate); #endif // if ((playstate == SND_STOPPED && (!juststartedplaying) && !pObject->GetLoopMode() && pObject->IsRunning()) #ifdef WIN32 if ((playstate == SND_STOPPED) && !pObject->GetLoopMode()) #else if (!pObject->GetLoopMode()) #endif { // printf("remove: %d\n", tijd); RemoveActiveObject(pObject); } } } } void SND_Scene::UpdateCD() { if (m_audiodevice) { SND_CDObject* pCD = SND_CDObject::Instance(); if (pCD) { int playstate = pCD->GetPlaystate(); switch (playstate) { case SND_MUST_PLAY: { // initialize the cd only when you need it m_audiodevice->SetCDGain(pCD->GetGain()); m_audiodevice->SetCDPlaymode(pCD->GetPlaymode()); m_audiodevice->PlayCD(pCD->GetTrack()); pCD->SetPlaystate(SND_PLAYING); pCD->SetUsed(); break; } case SND_MUST_PAUSE: { m_audiodevice->PauseCD(true); pCD->SetPlaystate(SND_PAUSED); break; } case SND_MUST_RESUME: { m_audiodevice->PauseCD(false); pCD->SetPlaystate(SND_PLAYING); break; } case SND_MUST_STOP: { m_audiodevice->StopCD(); pCD->SetPlaystate(SND_STOPPED); break; } default: { } } // this one is only for realtime modifying settings if (pCD->IsModified()) { m_audiodevice->SetCDGain(pCD->GetGain()); pCD->SetModified(false); } } } } void SND_Scene::Proceed() { if (m_audio && m_audioplayback) { m_audiodevice->MakeCurrent(); UpdateListener(); UpdateActiveObects(); UpdateCD(); // m_audiodevice->UpdateDevice(); } } void SND_Scene::DeleteObject(SND_SoundObject* pObject) { #ifdef ONTKEVER printf("SND_Scene::DeleteObject\n"); #endif if (pObject) { if (m_audiodevice) m_audiodevice->ClearId(pObject); // must remove object from m_activeList std::set::iterator set_it; set_it = m_soundobjects.find(pObject); if (set_it != m_soundobjects.end()) m_soundobjects.erase(set_it); // release the memory delete pObject; pObject = NULL; } } void SND_Scene::RemoveAllObjects() { #ifdef ONTKEVER printf("SND_Scene::RemoveAllObjects\n"); #endif StopAllObjects(); std::set::iterator it = m_soundobjects.begin(); while (it != m_soundobjects.end()) { delete (*it); it++; } m_soundobjects.clear(); } void SND_Scene::StopAllObjects() { if (m_audio) { #ifdef ONTKEVER printf("SND_Scene::StopAllObjects\n"); #endif SND_SoundObject* pObject; for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); !pObject->isTail(); pObject = (SND_SoundObject*)pObject->getNext()) { m_audiodevice->ClearId(pObject); } } } SND_SoundListener* SND_Scene::GetListener() { return &m_listener; }