- 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;
}