topical media & game development
lib-game-delta3d-sdk-examples-testAudio-testaudio.cpp / cpp
include <cassert>
include <stack>
include <iostream>
include <testaudio.h>
include <dtAudio/audiomanager.h>
include <dtAudio/sound.h>
include <dtAudio/soundeffectbinder.h>
include <dtCore/camera.h>
include <dtCore/effectmanager.h>
include <dtCore/object.h>
include <dtCore/orbitmotionmodel.h>
include <dtCore/particlesystem.h>
include <dtCore/transform.h>
include <osgGA/GUIEventAdapter>
// name spaces
using namespace dtCore;
using namespace dtABC;
using namespace dtAudio;
using namespace dtUtil;
IMPLEMENT_MANAGEMENT_LAYER( TestAudioApp )
// static member variables
unsigned int TestAudioApp::kNumSoundFiles(4L);
const char* TestAudioApp::kSoundFile[] =
{
"sounds/pow.wav",
"sounds/bang.wav",
"sounds/helo.wav",
"sounds/carhorn.wav"
};
const char* TestAudioApp::kGfxFile[kNumGfx] =
{
"models/flatdirt.ive",
"models/brdm.ive",
"models/uh-1n.ive"
};
const char* TestAudioApp::kFxFile[kNumFx] =
{
"effects/explosion.osg",
"effects/smoke.osg"
};
const char* TestAudioApp::kFxDetonationType[kNumFx] =
{
"HighExplosiveDetonation",
"SmokeDetonation"
};
TestAudioApp::TestAudioApp(const std::string& configFilename /*= "config.xml"*/)
: Application(configFilename)
, mSndGain(1.0f)
, mSndPitch(1.0f)
, mLooping(false)
, mMic(NULL)
, mOribitMotionModel(NULL)
, mSmokeCountA(0L)
, mSmokeCountC(0L)
, mRecorder(new SoundRecorder())
{
AddSender(&dtCore::System::GetInstance());
AudioManager::Instantiate();
for (unsigned int ii(0L); ii < kNumSoundFiles; ii++)
{
AudioManager::GetInstance().LoadFile(kSoundFile[ii]);
}
mMic = AudioManager::GetListener();
assert(mMic);
SetUpVisuals();
Camera* cam = GetCamera();
assert(cam);
cam->AddChild(mMic);
Transform transform(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
mMic->SetTransform(transform, Transformable::REL_CS);
mSFXBinder = new dtAudio::SoundEffectBinder;
assert(mSFXBinder.get());
if (mFXMgr.get())
{
mSFXBinder->Initialize(mFXMgr.get());
mSFXBinder->AddEffectTypeMapping(kFxDetonationType[EXPLODE], kSoundFile[1L]);
mSFXBinder->AddEffectTypeRange(kFxDetonationType[EXPLODE], 35.0f);
}
CreateHelpLabel();
}
TestAudioApp::~TestAudioApp()
{
if (mSFXBinder.get())
{
mSFXBinder->RemoveEffectTypeRange(kFxDetonationType[EXPLODE]);
mSFXBinder->RemoveEffectTypeMapping(kFxDetonationType[EXPLODE]);
mSFXBinder->Shutdown();
mSFXBinder = NULL;
}
StopAllSounds();
FreeAllStoppedSounds(true);
for (unsigned int ii(0L); ii < kNumSoundFiles; ii++)
{
AudioManager::GetInstance().UnloadFile(kSoundFile[ii]);
}
AudioManager::Destroy();
RemoveSender(&dtCore::System::GetInstance());
}
void TestAudioApp::PreFrame(const double deltaFrameTime)
{
Application::PreFrame(deltaFrameTime);
FlushQueuedSounds();
}
void
TestAudioApp::Frame(const double deltaFrameTime)
{
Application::Frame(deltaFrameTime);
}
void
TestAudioApp::PostFrame(const double deltaFrameTime)
{
Application::PostFrame(deltaFrameTime);
FreeAllStoppedSounds();
MoveTheObject(TRUCK);
MoveTheObject(HELO);
}
bool TestAudioApp::KeyPressed(const Keyboard* keyboard, int key)
{
bool verdict = dtABC::Application::KeyPressed(keyboard, key);
if (verdict == true)
{
return verdict;
}
osg::Vec3 pos(0.0f, 0.0f, 0.0f);
switch (key)
{
case 'a':
LoadPlaySound(kSoundFile[0L]);
verdict = true;
break;
case 's':
mFXMgr->AddDetonation(pos, kFxDetonationType[EXPLODE]);
verdict = true;
break;
case 'd':
LoadPlaySound(kSoundFile[2L], TRUCK);
verdict = true;
break;
case 'f':
LoadPlaySound(kSoundFile[3L], HELO);
verdict = true;
break;
case '0':
ChangeSoundGain(0.0f / 9.0f);
verdict = true;
break;
case '1':
ChangeSoundGain(1.0f / 9.0f);
verdict = true;
break;
case '2':
ChangeSoundGain(2.0f / 9.0f);
verdict = true;
break;
case '3':
ChangeSoundGain(3.0f / 9.0f);
verdict = true;
break;
case '4':
ChangeSoundGain(4.0f / 9.0f);
verdict = true;
break;
case '5':
ChangeSoundGain(5.0f / 9.0f);
verdict = true;
break;
case '6':
ChangeSoundGain(6.0f / 9.0f);
verdict = true;
break;
case '7':
ChangeSoundGain(7.0f / 9.0f);
verdict = true;
break;
case '8':
ChangeSoundGain(8.0f / 9.0f);
verdict = true;
break;
case '9':
ChangeSoundGain(9.0f / 9.0f);
verdict = true;
break;
case '-':
case osgGA::GUIEventAdapter::KEY_KP_Subtract:
ChangeSoundPitch(0.9f);
verdict = true;
break;
case '=':
case osgGA::GUIEventAdapter::KEY_KP_Add:
ChangeSoundPitch(1.1f);
verdict = true;
break;
case 'l':
ToggleSoundLooping();
verdict = true;
break;
case osgGA::GUIEventAdapter::KEY_Pause:
PauseAllSounds();
verdict = true;
break;
case osgGA::GUIEventAdapter::KEY_Return:
case osgGA::GUIEventAdapter::KEY_KP_Enter:
RewindAllSounds();
verdict = true;
break;
case ' ':
StopAllSounds();
verdict = true;
break;
case 'r':
{
if (mRecorder->GetState() == SoundRecorder::Recording)
{
StopRecording();
}
else
{
StartRecording();
}
verdict = true;
} break;
case 'y':
{
std::string sfile("soundrecord.xml");
LOG_INFO("Saving to file: "+ sfile)
mRecorder->SaveFile(sfile);
LOG_INFO("...Done saving file: " + sfile)
verdict = true;
} break;
case osgGA::GUIEventAdapter::KEY_F1:
{
mLabel->SetActive(!mLabel->GetActive());
break;
}
default:
break;
}
return verdict;
}
void TestAudioApp::LoadPlaySound(const char* fname, unsigned int box /*= 0L*/)
{
assert( fname );
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" LoadPlaySound( \%s )", fname);
Sound* snd = AudioManager::GetInstance().NewSound();
assert(snd);
snd->LoadFile(fname);
snd->SetGain(mSndGain);
snd->SetPitch(mSndPitch);
snd->SetLooping(mLooping);
if (box)
{
snd->SetRolloffFactor(0.2f);
}
snd->Play();
mQueued.push(snd);
if (box)
{
Object* obj = mGfxObj[box].get();
assert(obj);
obj->AddChild(snd);
Transform transform(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
snd->SetTransform(transform, Transformable::REL_CS);
snd->SetPlayCallback(MakeSmoke, this);
snd->SetStopCallback(StopSmoke, this);
}
}
void TestAudioApp::StopAllSounds(void)
{
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
if (snd == NULL)
{
continue;
}
if (!snd->IsStopped())
{
snd->Stop();
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" StopAllSounds( \%s )", snd->GetFilename() );
}
}
}
void
TestAudioApp::FreeAllStoppedSounds(bool forced /*= false*/)
{
SND_ITR iter;
std::stack<SND_ITR> stk;
Sound* snd(NULL);
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
if (snd == NULL)
{
continue;
}
if (snd->IsStopped() || forced)
{
stk.push(iter);
}
}
while (stk.size())
{
iter = stk.top();
stk.pop();
snd = *iter;
if (snd == NULL)
{
continue;
}
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" FreeAllStoppedSounds( \%s )", snd->GetFilename());
AudioManager::GetInstance().FreeSound(snd);
mActive.erase(iter);
}
}
void
TestAudioApp::FlushQueuedSounds()
{
Sound* snd(NULL);
while (mQueued.size())
{
snd = mQueued.front();
if (snd == NULL)
{
mQueued.pop();
continue;
}
if (!snd->IsStopped())
{
mQueued.pop();
mActive.push_back(snd);
continue;
}
break;
}
}
void
TestAudioApp::ChangeSoundGain(float gain)
{
mSndGain = gain;
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" ChangeSoundGain( %1.1f )", mSndGain );
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
assert(snd);
snd->SetGain(mSndGain);
}
}
void
TestAudioApp::ChangeSoundPitch(float pitch)
{
mSndPitch *= pitch;
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" ChangeSoundPitch( %1.4f )", mSndPitch);
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
assert(snd);
snd->SetPitch(mSndPitch);
}
}
void
TestAudioApp::ToggleSoundLooping()
{
mLooping = !mLooping;
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" ToggleSoundLooping( \%d )", (mLooping));
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
assert(snd);
if(! snd->IsStopped())
{
snd->SetLooping(mLooping);
}
}
}
void
TestAudioApp::PauseAllSounds()
{
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
if (snd == NULL)
{
continue;
}
snd->Pause();
if (snd->IsPlaying())
{
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" PauseAllSounds( \%s ) paused", snd->GetFilename());
}
else if (snd->IsPaused())
{
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" PauseAllSounds( \%s ) un-paused", snd->GetFilename());
}
}
}
void
TestAudioApp::RewindAllSounds()
{
Sound* snd(NULL);
SND_ITR iter;
for (iter = mActive.begin(); iter != mActive.end(); iter++)
{
snd = *iter;
if (snd == NULL)
{
continue;
}
snd->Rewind();
Log::GetInstance().LogMessage(Log::LOG_ALWAYS, __FUNCTION__,
" RewindAllSounds( \%s )", snd->GetFilename());
}
}
void
TestAudioApp::SetUpVisuals()
{
for (unsigned int ii(0L); ii < kNumGfx; ii++)
{
mGfxObj[ii] = LoadGfxFile(kGfxFile[ii]).get();
assert(mGfxObj[ii].get());
}
mFXMgr = LoadFxFile( kFxFile[EXPLODE] ).get();
assert(mFXMgr.get());
mPSysA = LoadPSFile( kFxFile[SMOKE] ).get();
assert(mPSysA.get());
mGfxObj[TRUCK]->AddChild(mPSysA.get());
mPSysC = LoadPSFile(kFxFile[SMOKE]).get();
assert(mPSysC.get());
mGfxObj[HELO]->AddChild(mPSysC.get());
InitInputDevices();
SetUpCamera();
}
dtCore::RefPtr<Object>
TestAudioApp::LoadGfxFile(const char* fname)
{
if (fname == NULL)
{
// no file name, bail...
return NULL;
}
std::string filename = dtCore::FindFileInPathList(fname);
if (filename == "")
{
// still no file name, bail...
Log::GetInstance().LogMessage( Log::LOG_WARNING,__FUNCTION__,
"AudioManager: can't load file \%s", fname );
return NULL;
}
dtCore::RefPtr<Object> fileobj = new Object;
assert(fileobj.valid());
if (fileobj->LoadFile(filename) == NULL)
{
Log::GetInstance().LogMessage(Log::LOG_WARNING,__FUNCTION__,
"can't load gfx file '\%s'", filename.c_str());
fileobj = 0;
return 0;
}
if (std::string(fname) == kGfxFile[1])
{
//rotate BRDM 90 degrees
Transform trans = Transform(0.0f, 0.0f, 0.0f, 90.0f, 0.0f, 0.0f);
fileobj->SetTransform(trans);
}
// add the object to the scene
AddDrawable(fileobj.get());
dtCore::RefPtr<osg::Node> filenode = fileobj->GetOSGNode();
assert(filenode.valid());
filenode->setNodeMask(0xFFFFFFFF);
return fileobj;
}
dtCore::RefPtr<EffectManager>
TestAudioApp::LoadFxFile(const char* fname)
{
dtCore::RefPtr<EffectManager> effectManager = new EffectManager;
assert(effectManager.valid());
effectManager->AddDetonationTypeMapping(
kFxDetonationType[EXPLODE],
fname
);
AddDrawable(effectManager.get());
return effectManager;
}
dtCore::RefPtr<ParticleSystem>
TestAudioApp::LoadPSFile(const char* fname)
{
dtCore::RefPtr<ParticleSystem> particlesystem = new ParticleSystem;
assert(particlesystem.valid());
particlesystem->LoadFile(fname, false);
particlesystem->SetEnabled(false);
return particlesystem;
}
void
TestAudioApp::InitInputDevices()
{
mOribitMotionModel = new OrbitMotionModel(GetKeyboard(), GetMouse());
mOribitMotionModel->SetTarget(GetCamera());
mOribitMotionModel->SetEnabled(true);
}
void
TestAudioApp::SetUpCamera()
{
osg::Vec3 pos (0.0f, -150.0f, 30.0f);
osg::Vec3 lookat (0.f, 0.f, 0.f);
osg::Vec3 up (0.f, 0.f, 1.f);
Transform xform;
xform.Set(pos, lookat, up);
float dist((lookat - pos).length());
Camera* cam(GetCamera());
assert(cam);
cam->SetTransform(xform);
mOribitMotionModel->SetDistance(dist);
}
void
TestAudioApp::MoveTheObject(unsigned int obj)
{
// figure out which vehicle gets what velocity
static long X(0L);
static const double A(1.0f/2500.0f);
static const double C(1.0f/2500.0f);
double D((obj==HELO)? C: A);
double P(sin( double(X++) * D ));
double V(cos( double(X++) * D ));
unsigned int I((obj==TRUCK)? 1L: 0L);
Transform xform;
osg::Vec3 pos( 0.0f, 0.0f, 0.0f );
osg::Vec3 vel( 0.0f, 0.0f, 0.0f );
OBJ_PTR gfx(mGfxObj[obj]);
// move the vehicle
assert(gfx.get());
gfx->GetTransform(xform);
xform.GetTranslation(pos);
pos[I] = static_cast<double>(P * 50.0f);
xform.SetTranslation(pos);
gfx->SetTransform(xform);
// don't set velocity for TRUCK
if (obj == TRUCK)
{
return;
}
// set the velocity for all children of the vehicle
vel[I] = static_cast<ALfloat>(V * 50.0f);
Sound* snd(NULL);
for (unsigned int ii(0L); ii < gfx->GetNumChildren(); ii++)
{
snd = dynamic_cast<Sound*>(gfx->GetChild(ii));
if (snd == NULL)
{
continue;
}
snd->SetVelocity(vel);
}
}
void
TestAudioApp::MakeSmoke(dtAudio::Sound* sound, void* param)
{
assert(sound);
assert(param);
sound->SetPlayCallback(NULL, NULL);
std::string fname = sound->GetFilename();
TestAudioApp* app = static_cast<TestAudioApp*>(param);
if (fname == app->kSoundFile[2L])
{
assert(app->mPSysA.get());
app->mSmokeCountA++;
app->mPSysA->SetEnabled(true);
return;
}
if (fname == app->kSoundFile[3L])
{
assert(app->mPSysC.get());
app->mSmokeCountC++;
app->mPSysC->SetEnabled(true);
return;
}
}
void
TestAudioApp::StopSmoke(dtAudio::Sound* sound, void* param)
{
assert(sound);
assert(param);
sound->SetStopCallback(NULL, NULL);
std::string fname = sound->GetFilename();
TestAudioApp* app = static_cast<TestAudioApp*>(param);
if (fname == app->kSoundFile[2L])
{
assert(app->mPSysA.get());
app->mSmokeCountA--;
if (app->mSmokeCountA)
{
return;
}
app->mPSysA->SetEnabled(false);
}
if (fname == app->kSoundFile[3L])
{
assert(app->mPSysC.get());
app->mSmokeCountC--;
if (app->mSmokeCountC)
{
return;
}
app->mPSysC->SetEnabled(false);
}
}
void TestAudioApp::StartRecording()
{
LOG_INFO("Starting Recording.")
mRecorder->Record();
}
void TestAudioApp::StopRecording()
{
LOG_INFO("Stopping Recording.")
mRecorder->Stop();
}
void TestAudioApp::CreateHelpLabel()
{
mLabel = new LabelActor();
osg::Vec2 testSize(21.0f, 11.0f);
mLabel->SetBackSize(testSize);
mLabel->SetFontSize(0.8f);
mLabel->SetTextAlignment(LabelActor::AlignmentEnum::LEFT_CENTER);
mLabel->SetText(CreateHelpLabelText());
mLabel->SetEnableDepthTesting(false);
mLabel->SetEnableLighting(false);
GetCamera()->AddChild(mLabel.get());
Transform labelOffset(-17.0f, 50.0f, 7.5f, 0.0f, 90.0f, 0.0f);
mLabel->SetTransform(labelOffset, Transformable::REL_CS);
AddDrawable(GetCamera());
}
std::string TestAudioApp::CreateHelpLabelText()
{
std::string testString("");
testString += "F1: Toggle Help Screen\n";
testString += "\n";
testString += "0-9: Change volume\n";
testString += "+/-: Increase/Decrease pitch\n";
testString += "a: Play gunfire sound\n";
testString += "s: Play explosion sound\n";
testString += "d: Play helicopter hum sound\n";
testString += "f: Play vehicle horn sound\n";
testString += "l: Set sounds to loop\n";
testString += "r: Record sounds\n";
testString += "y: Save soundrecord.xml\n";
testString += "Space: Stops all sounds\n";
testString += "Pause: Pause all sounds\n";
return testString;
}
int main()
{
std::string dataPath = dtCore::GetDeltaDataPathList();
dtCore::SetDataFilePathList(dataPath + ";" +
dtCore::GetDeltaRootPath() + "/examples/data" + ";");
RefPtr<TestAudioApp> app = new TestAudioApp("config.xml");
std::cout << "Key you can push: \n\n";
std::cout << "0-9 set the gain (volume) of sounds.\n";
std::cout << "+ and - increase/decrease pitch.\n";
std::cout << "A plays a 'pow' sound.\n";
std::cout << "S plays a 'boom' sound.\n";
std::cout << "D plays a helicopter hum that is attached to the helicopter.\n";
std::cout << "F plays a horn sounds that is attached to the vehicle.\n";
std::cout << "L sets sounds to looping.\n";
std::cout << "Spacebar stops all sounds.\n";
std::cout << "Esc exits application.\n";
app->Run();
return 0;
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.