#ifdef HAVE_CONFIG_H #include <config.h> #endif added to these files. Kent -- mein@cs.umn.edu
574 lines
12 KiB
C++
574 lines
12 KiB
C++
/*
|
|
* 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 HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#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 <stdlib.h>
|
|
#include <iostream>
|
|
|
|
//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())
|
|
#if defined(WIN32) || defined(__APPLE__)
|
|
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<SND_SoundObject*>::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<SND_SoundObject*>::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;
|
|
}
|