openclonk/src/platform/C4SoundSystem.cpp

315 lines
8.3 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 1998-2000, Matthes Bender
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2013, The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
2009-05-08 13:28:41 +00:00
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
2009-05-08 13:28:41 +00:00
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
2009-05-08 13:28:41 +00:00
*/
/* Handles the sound bank and plays effects using DSoundX */
#include <C4Include.h>
#include <C4SoundSystem.h>
#include <C4SoundInstance.h>
2009-05-08 13:28:41 +00:00
#include <C4Random.h>
#include <C4Object.h>
#include <C4Game.h>
#include <C4Config.h>
#include <C4Application.h>
#include <C4Viewport.h>
#include <C4SoundIncludes.h>
#include <C4SoundLoaders.h>
2009-05-08 13:28:41 +00:00
C4SoundSystem::C4SoundSystem():
2010-03-28 18:58:01 +00:00
FirstSound (NULL)
{
}
2009-05-08 13:28:41 +00:00
C4SoundSystem::~C4SoundSystem()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4SoundSystem::Init()
2010-03-28 18:58:01 +00:00
{
if (!Application.MusicSystem.MODInitialized &&
!Application.MusicSystem.InitializeMOD())
2009-05-08 13:28:41 +00:00
return false;
// Might be reinitialisation
ClearEffects();
// (re)init EFX
Modifiers.Init();
2009-05-08 13:28:41 +00:00
// Open sound file
if (!SoundFile.IsOpen())
if (!Reloc.Open(SoundFile, C4CFN_Sound)) return false;
// Load static sound from Sound.ocg
LoadEffects(SoundFile);
#if AUDIO_TK == AUDIO_TK_SDL_MIXER
2009-05-08 13:28:41 +00:00
Mix_AllocateChannels(C4MaxSoundInstances);
#endif
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4SoundSystem::Clear()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ClearEffects();
Modifiers.Clear();
2009-05-08 13:28:41 +00:00
// Close sound file
SoundFile.Close();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4SoundSystem::ClearEffects()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Clear sound bank
C4SoundEffect *csfx,*next;
for (csfx=FirstSound; csfx; csfx=next)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
next=csfx->Next;
delete csfx;
}
2010-03-28 18:58:01 +00:00
FirstSound=NULL;
}
2009-05-08 13:28:41 +00:00
void C4SoundSystem::Execute()
2010-03-28 18:58:01 +00:00
{
#if AUDIO_TK == AUDIO_TK_OPENAL
Application.MusicSystem.SelectContext();
#endif
C4SoundEffect *csfx;
for (csfx=FirstSound; csfx; csfx=csfx->Next)
2010-03-28 18:58:01 +00:00
{
// Instance removal check
csfx->Execute();
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4SoundEffect* C4SoundSystem::GetEffect(const char *szSndName)
2010-03-28 18:58:01 +00:00
{
2011-10-15 12:43:18 +00:00
// Remember wildcards before adding .* extension - if there are 2 versions with different file extensions, play the last added
bool bRandomSound = SCharCount('?',szSndName) || SCharCount('*',szSndName);
// Evaluate sound name
2011-10-15 12:43:18 +00:00
char szName[C4MaxSoundName+2+1];
SCopy(szSndName,szName,C4MaxSoundName);
// Any extension accepted
DefaultExtension(szName,"*");
2011-10-15 12:43:18 +00:00
// Play nth Sound. Standard: 1
int32_t iNumber = 1;
2009-05-08 13:28:41 +00:00
// Sound with a wildcard: determine number of available matches
if (bRandomSound)
2010-03-28 18:58:01 +00:00
{
2011-10-15 12:43:18 +00:00
iNumber = 0;
// Count matching sounds
2011-10-15 12:43:18 +00:00
for (C4SoundEffect *pSfx=FirstSound; pSfx; pSfx=pSfx->Next)
if (WildcardMatch(szName,pSfx->Name))
++iNumber;
2011-10-15 12:43:18 +00:00
// Nothing found? Abort
if(iNumber == 0)
return NULL;
iNumber=SafeRandom(iNumber)+1;
2010-03-28 18:58:01 +00:00
}
// Find requested sound effect in bank
2011-10-15 12:43:18 +00:00
C4SoundEffect *pSfx;
for (pSfx=FirstSound; pSfx; pSfx=pSfx->Next)
if (WildcardMatch(szName,pSfx->Name))
if(!--iNumber)
break;
return pSfx; // Is still NULL if nothing is found
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4SoundInstance *C4SoundSystem::NewEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Sound not active
if (!Config.Sound.RXSound) return NULL;
2009-05-08 13:28:41 +00:00
// Get sound
C4SoundEffect *csfx;
if (!(csfx=GetEffect(szSndName))) return NULL;
2009-05-08 13:28:41 +00:00
// Play
return csfx->New(fLoop, iVolume, pObj, iCustomFalloffDistance, iPitch, modifier);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4SoundInstance *C4SoundSystem::FindInstance(const char *szSndName, C4Object *pObj)
2010-03-28 18:58:01 +00:00
{
2011-10-15 12:43:18 +00:00
char szName[C4MaxSoundName+2+1];
// Evaluate sound name (see GetEffect)
SCopy(szSndName,szName,C4MaxSoundName);
DefaultExtension(szName,"*");
// Find an effect with a matching instance
2010-03-28 18:58:01 +00:00
for (C4SoundEffect *csfx = FirstSound; csfx; csfx = csfx->Next)
if (WildcardMatch(szName, csfx->Name))
{
C4SoundInstance *pInst = csfx->GetInstance(pObj);
2010-03-28 18:58:01 +00:00
if (pInst) return pInst;
}
return NULL;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// LoadEffects will load all sound effects of all known sound types (i.e. *.wav and *.ogg) as defined in C4CFN_SoundFiles
2009-05-08 13:28:41 +00:00
int32_t C4SoundSystem::LoadEffects(C4Group &hGroup)
2010-03-28 18:58:01 +00:00
{
// if there is a Sound.ocg in the group, load the sound from there
if(hGroup.FindEntry(C4CFN_Sound))
{
C4Group g;
g.OpenAsChild(&hGroup, C4CFN_Sound, false, false);
return LoadEffects(g);
}
2009-05-08 13:28:41 +00:00
int32_t iNum=0;
char szFilename[_MAX_FNAME+1];
char szFileType[_MAX_FNAME+1];
C4SoundEffect *nsfx;
// Process segmented list of file types
for (int32_t i = 0; SCopySegment(C4CFN_SoundFiles, i, szFileType, '|', _MAX_FNAME); i++)
{
// Search all sound files in group
hGroup.ResetSearch();
while (hGroup.FindNextEntry(szFileType, szFilename))
// Create and load effect
2010-01-25 04:00:59 +00:00
if ((nsfx = new C4SoundEffect))
2010-03-28 18:58:01 +00:00
{
if (nsfx->Load(szFilename,hGroup))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Overload same name effects
RemoveEffect(szFilename);
// Add effect
nsfx->Next=FirstSound;
FirstSound=nsfx;
iNum++;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
delete nsfx;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
}
return iNum;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4SoundSystem::RemoveEffect(const char *szFilename)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iResult=0;
C4SoundEffect *pNext,*pPrev=NULL;
for (C4SoundEffect *pSfx=FirstSound; pSfx; pSfx=pNext)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pNext=pSfx->Next;
if (WildcardMatch(szFilename,pSfx->Name))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pSfx;
if (pPrev) pPrev->Next=pNext;
else FirstSound=pNext;
iResult++;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
pPrev=pSfx;
}
2010-03-28 18:58:01 +00:00
return iResult;
}
2009-05-08 13:28:41 +00:00
void C4SoundSystem::ClearPointers(C4Object *pObj)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
for (C4SoundEffect *pEff=FirstSound; pEff; pEff=pEff->Next)
pEff->ClearPointers(pObj);
2010-03-28 18:58:01 +00:00
}
C4SoundInstance *C4SoundSystem::GetFirstInstance() const
{
// Return by searching through effect linked list.
for (C4SoundEffect *pSfx = FirstSound; pSfx; pSfx = pSfx->Next)
if (pSfx->FirstInst) return pSfx->FirstInst;
return NULL;
}
C4SoundInstance *C4SoundSystem::GetNextInstance(C4SoundInstance *prev) const
{
// Return by searching through instance linked list and parent linked list of effects
assert(prev && prev->pEffect);
if (prev->pNext) return prev->pNext;
for (C4SoundEffect *pSfx = prev->pEffect->Next; pSfx; pSfx = pSfx->Next)
if (pSfx->FirstInst) return pSfx->FirstInst;
return NULL;
}
C4SoundInstance *StartSoundEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
2010-03-28 18:58:01 +00:00
{
// Sound check
if (!Config.Sound.RXSound) return NULL;
// Start new
return Application.SoundSystem.NewEffect(szSndName, fLoop, iVolume, pObj, iCustomFalloffDistance, iPitch, modifier);
2010-03-28 18:58:01 +00:00
}
C4SoundInstance *StartSoundEffectAt(const char *szSndName, int32_t iX, int32_t iY, int32_t iVolume, int32_t iCustomFallofDistance, int32_t iPitch, C4SoundModifier *modifier)
2010-03-28 18:58:01 +00:00
{
// Sound check
if (!Config.Sound.RXSound) return NULL;
// Create
C4SoundInstance *pInst = StartSoundEffect(szSndName, false, iVolume, NULL, iCustomFallofDistance, iPitch, modifier);
// Set volume by position
2010-03-28 18:58:01 +00:00
if (pInst) pInst->SetVolumeByPos(iX, iY);
// Return
return pInst;
2010-03-28 18:58:01 +00:00
}
C4SoundInstance *GetSoundInstance(const char *szSndName, C4Object *pObj)
2010-03-28 18:58:01 +00:00
{
return Application.SoundSystem.FindInstance(szSndName, pObj);
2010-03-28 18:58:01 +00:00
}
void StopSoundEffect(const char *szSndName, C4Object *pObj)
2010-03-28 18:58:01 +00:00
{
// Find instance
C4SoundInstance *pInst = Application.SoundSystem.FindInstance(szSndName, pObj);
2010-03-28 18:58:01 +00:00
if (!pInst) return;
// Stop
pInst->Stop();
2010-03-28 18:58:01 +00:00
}
void SoundLevel(const char *szSndName, C4Object *pObj, int32_t iLevel)
2010-03-28 18:58:01 +00:00
{
// Sound level zero? Stop
2010-03-28 18:58:01 +00:00
if (!iLevel) { StopSoundEffect(szSndName, pObj); return; }
// Find or create instance
C4SoundInstance *pInst = Application.SoundSystem.FindInstance(szSndName, pObj);
2010-03-28 18:58:01 +00:00
if (!pInst) pInst = StartSoundEffect(szSndName, true, iLevel, pObj);
if (!pInst) return;
// Set volume
pInst->SetVolume(iLevel);
pInst->Execute();
2010-03-28 18:58:01 +00:00
}
void SoundPan(const char *szSndName, C4Object *pObj, int32_t iPan)
2010-03-28 18:58:01 +00:00
{
// Find instance
C4SoundInstance *pInst = Application.SoundSystem.FindInstance(szSndName, pObj);
2010-03-28 18:58:01 +00:00
if (!pInst) return;
// Set pan
pInst->SetPan(iPan);
pInst->Execute();
2010-03-28 18:58:01 +00:00
}
void SoundPitch(const char *szSndName, C4Object *pObj, int32_t iPitch)
{
// Find instance
C4SoundInstance *pInst = Application.SoundSystem.FindInstance(szSndName, pObj);
if (!pInst) return;
// Set pitch
pInst->SetPitch(iPitch);
pInst->Execute();
}
void SoundUpdate(C4SoundInstance *pInst, int32_t iLevel, int32_t iPitch)
{
// Set sound data
pInst->SetVolume(iLevel);
pInst->SetPitch(iPitch);
// Ensure it's reflected in audio engine
pInst->Execute();
}