irrKlang sound emitter and listener scene nodes
Posted: Fri Nov 24, 2006 8:43 pm
Basically these scene nodes automatically update the irrKlang sound listener and sound emitter positions. All you should need to do to use them...
Here is an example of how to use it...
Travis
- create and initialize irrKlang engine and irrlicht device
- create a sound listener and set it to be the child of the camera
- create a sound emitter.
- create some sounds, bind them to the emitter with emitter->addSound()
Code: Select all
// irrlicht
#include <ISceneManager.h>
#include <ISceneNode.h>
#include <IVideoDriver.h>
#include <irrArray.h>
// irrKlang
#include <ISoundEngine.h>
#include <ISound.h>
namespace irr {
namespace scene {
class CSoundEmitterSceneNode : public ISceneNode
{
public:
//! constructor
CSoundEmitterSceneNode(ISceneNode* parent,
ISceneManager* mgr,
s32 id = -1);
//! destructor
virtual ~CSoundEmitterSceneNode();
//! This method is called just before the rendering process of the whole scene.
virtual void OnPreRender();
//! does nothing.
virtual void render();
//! This method is called just after the rendering process of the whole scene.
virtual void OnPostRender(u32 timeMs);
//! Just get the bounding box
const core::aabbox3d<f32>& getBoundingBox() const;
//! Add a sound to this emitter
virtual void addSound(audio::ISound* sound);
//! Remove a sound from this emitter
virtual void removeSound(audio::ISound* sound);
//! Remove all sounds from this emitter
virtual void removeAllSounds();
//! Get the number of sounds in this emitter
virtual u32 getSoundCount() const;
//! Get a specific sound from this emitter
virtual audio::ISound* getSound(u32 index);
private:
//! non-virtual used to cleanup sound resources
void deleteAllSounds();
private:
core::aabbox3d<f32> Box;
// we manage more than one sound emitter
core::array<audio::ISound*> Sounds;
};
class CSoundListenerSceneNode : public ISceneNode
{
public:
CSoundListenerSceneNode(ISceneNode* parent,
ISceneManager* mgr,
audio::ISoundEngine* eng,
u32 now,
s32 id = -1);
virtual ~CSoundListenerSceneNode();
public:
//! This method is called just before the rendering process of the whole scene.
virtual void OnPreRender();
//! does nothing.
virtual void render();
//! This method is called just after the rendering process of the whole scene.
virtual void OnPostRender(u32 timeMs);
//! Just get the bounding box
const core::aabbox3d<f32>& getBoundingBox() const;
private:
// our bounding box for debug drawing
core::aabbox3d<f32> Box;
// the sound engine
audio::ISoundEngine* SoundEngine;
// doppler support
core::vector3df PreviousPosition;
u32 PreviousTime;
};
CSoundEmitterSceneNode::CSoundEmitterSceneNode(
ISceneNode* parent,
ISceneManager* mgr,
s32 id)
: ISceneNode(parent, mgr, id)
{
#ifdef _DEBUG
setDebugName("CSoundEmitterSceneNode");
#endif
setAutomaticCulling(false);
}
CSoundEmitterSceneNode::~CSoundEmitterSceneNode()
{
deleteAllSounds();
}
void CSoundEmitterSceneNode::OnPreRender()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this, ESNRP_SOLID);
ISceneNode::OnPreRender();
}
void CSoundEmitterSceneNode::render()
{
// for debug purposes only, draw a blue box for audio listeners
if (DebugDataVisible)
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(Box, video::SColor(255, 0, 0, 255));
}
}
void CSoundEmitterSceneNode::OnPostRender(u32 timeMs)
{
ISceneNode::OnPostRender(timeMs);
// would be nice if irrKlang supported velocity/doppler for sounds
// update the sounds source positions
const core::vector3df position = getAbsolutePosition();
u32 s;
for (s = 0; s < Sounds.size(); ++s)
Sounds[s]->setPosition(position);
}
const core::aabbox3d<f32>& CSoundEmitterSceneNode::getBoundingBox() const
{
return Box;
}
void CSoundEmitterSceneNode::addSound(audio::ISound* sound)
{
// you can't insert the same sound multiple times
s32 e = Sounds.binary_search(sound);
if (e != -1)
return;
Sounds.push_back(sound);
sound->grab();
// make sure the sound is at the correct position
const core::vector3df position = getAbsolutePosition();
sound->setPosition(position);
}
void CSoundEmitterSceneNode::removeSound(audio::ISound* sound)
{
s32 s = Sounds.binary_search(sound);
if (s != -1)
{
Sounds.erase(s);
sound->drop();
}
}
void CSoundEmitterSceneNode::removeAllSounds()
{
deleteAllSounds();
}
u32 CSoundEmitterSceneNode::getSoundCount() const
{
return Sounds.size();
}
audio::ISound* CSoundEmitterSceneNode::getSound(u32 index)
{
return Sounds[index];
}
void CSoundEmitterSceneNode::deleteAllSounds()
{
u32 s;
for (s = 0; s < Sounds.size(); ++s)
Sounds[s]->drop();
Sounds.clear();
}
CSoundListenerSceneNode::CSoundListenerSceneNode(ISceneNode* parent,
ISceneManager* mgr,
audio::ISoundEngine* eng,
u32 now,
s32 id)
: ISceneNode(parent, mgr, id)
, SoundEngine(eng)
, PreviousTime(now)
{
#ifdef _DEBUG
setDebugName("CSoundListenerSceneNode");
#endif
if (SoundEngine)
SoundEngine->grab();
setAutomaticCulling(false);
}
CSoundListenerSceneNode::~CSoundListenerSceneNode()
{
if (SoundEngine)
SoundEngine->drop();
}
void CSoundListenerSceneNode::OnPreRender()
{
// listener is always rendered!
if (SoundEngine)
SceneManager->registerNodeForRendering(this, ESNRP_SOLID);
ISceneNode::OnPreRender();
}
void CSoundListenerSceneNode::render()
{
// for debug purposes only, draw a red box for audio listener
if (DebugDataVisible)
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(Box, video::SColor(255, 255, 0, 0));
}
}
void CSoundListenerSceneNode::OnPostRender(u32 timeMs)
{
// update our transformation matrix
ISceneNode::OnPostRender(timeMs);
// get the up vector
core::vector3df upwards(0.f, 1.f, 0.f);
getAbsoluteTransformation().rotateVect(upwards);
// and forward vector
core::vector3df forwards(0.f, 0.f, 1.f);
getAbsoluteTransformation().rotateVect(forwards);
// do doppler
const f32 elapsed = (timeMs - PreviousTime) / 1000.f;
PreviousTime = timeMs;
// do position/velocity
const core::vector3df position = getAbsolutePosition();
const core::vector3df velocity = (position - PreviousPosition) / elapsed;
PreviousPosition = position;
// feed position, velocity and orientation information to sound engine
SoundEngine->setListenerPosition(position, forwards, velocity, upwards);
}
const core::aabbox3d<f32>& CSoundListenerSceneNode::getBoundingBox() const
{
return Box;
}
} // namespace scene
} // namespace irr
Code: Select all
#include <irrlicht.h>
#pragma comment(lib, "irrlicht.lib")
#include <irrklang.h>
#pragma comment(lib, "irrklang.lib")
using namespace irr;
int main()
{
IrrlichtDevice *device =
createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480), 16);
if (!device)
return 0;
audio::ISoundEngine* engine = audio::createIrrKlangDevice();
if (!engine)
return 0;
device->setWindowCaption(L"Irrlicht/IrrKlang demo");
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
// note!!!
//
// modified version of example.irr has a node with name 'sphere'
//
smgr->loadScene("../../media/example.irr");
scene::ISceneNode* camera = smgr->addCameraSceneNodeFPS();
scene::CSoundListenerSceneNode* listener =
new scene::CSoundListenerSceneNode(camera, smgr, engine, device->getTimer()->getRealTime());
listener->setDebugDataVisible(true);
scene::ISceneNode* node = smgr->getSceneNodeFromName("sphere");
if (node)
{
scene::CSoundEmitterSceneNode* emitter =
new scene::CSoundEmitterSceneNode(node, smgr);
emitter->setDebugDataVisible(true);
audio::ISound* sound =
engine->play3D("../../media/irrlichttheme.ogg", node->getAbsolutePosition(), true, false, true);
sound->setMinDistance(10.f);
sound->setMaxDistance(100.f);
emitter->addSound(sound);
}
while(device->run())
{
if (driver->beginScene(true, true, video::SColor(255,100,101,140)))
{
smgr->drawAll();
driver->endScene();
}
}
device->drop();
return 0;
}