mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Ingame sound pos envelope support
This commit is contained in:
parent
920ac531aa
commit
e211c7a2b2
|
@ -45,6 +45,7 @@ struct CVoice
|
|||
{
|
||||
CSample *m_pSample;
|
||||
CChannel *m_pChannel;
|
||||
int m_Age; // increases when reused
|
||||
int m_Tick;
|
||||
int m_Vol; // 0 - 255
|
||||
int m_FalloffDistance; // 0 - inifintee (well int)
|
||||
|
@ -171,7 +172,10 @@ static void Mix(short *pFinalOut, unsigned Frames)
|
|||
if(v->m_Flags&ISound::FLAG_LOOP)
|
||||
v->m_Tick = 0;
|
||||
else
|
||||
{
|
||||
v->m_pSample = 0;
|
||||
v->m_Age++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,18 +501,28 @@ void CSound::SetListenerPos(float x, float y)
|
|||
m_CenterY = (int)y;
|
||||
}
|
||||
|
||||
void CSound::SetVoiceVolume(int VoiceID, float Volume)
|
||||
void CSound::SetVoiceVolume(CVoiceHandle Voice, float Volume)
|
||||
{
|
||||
if(VoiceID < 0 || VoiceID >= NUM_VOICES)
|
||||
if(!Voice.IsValid())
|
||||
return;
|
||||
|
||||
int VoiceID = Voice.Id();
|
||||
|
||||
if(m_aVoices[VoiceID].m_Age != Voice.Age())
|
||||
return;
|
||||
|
||||
Volume = clamp(Volume, 0.0f, 1.0f);
|
||||
m_aVoices[VoiceID].m_Vol = (int)(Volume*255.0f);
|
||||
}
|
||||
|
||||
void CSound::SetVoiceMaxDistance(int VoiceID, int Distance)
|
||||
void CSound::SetVoiceMaxDistance(CVoiceHandle Voice, int Distance)
|
||||
{
|
||||
if(VoiceID < 0 || VoiceID >= NUM_VOICES)
|
||||
if(!Voice.IsValid())
|
||||
return;
|
||||
|
||||
int VoiceID = Voice.Id();
|
||||
|
||||
if(m_aVoices[VoiceID].m_Age != Voice.Age())
|
||||
return;
|
||||
|
||||
if(Distance < 0)
|
||||
|
@ -517,31 +531,46 @@ void CSound::SetVoiceMaxDistance(int VoiceID, int Distance)
|
|||
m_aVoices[VoiceID].m_FalloffDistance = Distance;
|
||||
}
|
||||
|
||||
void CSound::SetVoiceLocation(CVoiceHandle Voice, float x, float y)
|
||||
{
|
||||
if(!Voice.IsValid())
|
||||
return;
|
||||
|
||||
int VoiceID = Voice.Id();
|
||||
|
||||
if(m_aVoices[VoiceID].m_Age != Voice.Age())
|
||||
return;
|
||||
|
||||
m_aVoices[VoiceID].m_X = x;
|
||||
m_aVoices[VoiceID].m_Y = y;
|
||||
}
|
||||
|
||||
void CSound::SetChannel(int ChannelID, float Vol, float Pan)
|
||||
{
|
||||
m_aChannels[ChannelID].m_Vol = (int)(Vol*255.0f);
|
||||
m_aChannels[ChannelID].m_Pan = (int)(Pan*255.0f); // TODO: this is only on and off right now
|
||||
}
|
||||
|
||||
int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
|
||||
ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
|
||||
{
|
||||
int VoiceID = -1;
|
||||
int Age = -1;
|
||||
int i;
|
||||
|
||||
if(SampleID == 107) // GetSampleID(SOUND_CHAT_SERVER)
|
||||
{
|
||||
if(!g_Config.m_SndServerMessage)
|
||||
return VoiceID;
|
||||
return CVoiceHandle();
|
||||
}
|
||||
else if(SampleID == 108) // GetSampleID(SOUND_CHAT_CLIENT)
|
||||
{}
|
||||
else if(SampleID == 109) // GetSampleID(SOUND_CHAT_HIGHLIGHT)
|
||||
{
|
||||
if(!g_Config.m_SndHighlight)
|
||||
return VoiceID;
|
||||
return CVoiceHandle();
|
||||
}
|
||||
else if(!g_Config.m_SndGame)
|
||||
return VoiceID;
|
||||
return CVoiceHandle();
|
||||
|
||||
|
||||
lock_wait(m_SoundLock);
|
||||
|
@ -572,18 +601,19 @@ int CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
|
|||
m_aVoices[VoiceID].m_X = (int)x;
|
||||
m_aVoices[VoiceID].m_Y = (int)y;
|
||||
m_aVoices[VoiceID].m_FalloffDistance = DefaultDistance;
|
||||
Age = m_aVoices[VoiceID].m_Age;
|
||||
}
|
||||
|
||||
lock_release(m_SoundLock);
|
||||
return VoiceID;
|
||||
return CreateVoiceHandle(VoiceID, Age);
|
||||
}
|
||||
|
||||
int CSound::PlayAt(int ChannelID, int SampleID, int Flags, float x, float y)
|
||||
ISound::CVoiceHandle CSound::PlayAt(int ChannelID, int SampleID, int Flags, float x, float y)
|
||||
{
|
||||
return Play(ChannelID, SampleID, Flags|ISound::FLAG_POS, x, y);
|
||||
}
|
||||
|
||||
int CSound::Play(int ChannelID, int SampleID, int Flags)
|
||||
ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags)
|
||||
{
|
||||
return Play(ChannelID, SampleID, Flags, 0, 0);
|
||||
}
|
||||
|
|
|
@ -37,12 +37,13 @@ public:
|
|||
virtual void SetListenerPos(float x, float y);
|
||||
virtual void SetChannel(int ChannelID, float Vol, float Pan);
|
||||
|
||||
virtual void SetVoiceVolume(int VoiceId, float Volume);
|
||||
virtual void SetVoiceMaxDistance(int VoiceId, int Distance);
|
||||
virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume);
|
||||
virtual void SetVoiceMaxDistance(CVoiceHandle Voice, int Distance);
|
||||
virtual void SetVoiceLocation(CVoiceHandle Voice, float x, float y);
|
||||
|
||||
int Play(int ChannelID, int SampleID, int Flags, float x, float y);
|
||||
virtual int PlayAt(int ChannelID, int SampleID, int Flags, float x, float y);
|
||||
virtual int Play(int ChannelID, int SampleID, int Flags);
|
||||
CVoiceHandle Play(int ChannelID, int SampleID, int Flags, float x, float y);
|
||||
virtual CVoiceHandle PlayAt(int ChannelID, int SampleID, int Flags, float x, float y);
|
||||
virtual CVoiceHandle Play(int ChannelID, int SampleID, int Flags);
|
||||
virtual void Stop(int SampleID);
|
||||
virtual void StopAll();
|
||||
};
|
||||
|
|
|
@ -16,6 +16,24 @@ public:
|
|||
FLAG_ALL=3
|
||||
};
|
||||
|
||||
class CVoiceHandle
|
||||
{
|
||||
friend class ISound;
|
||||
int m_Id;
|
||||
int m_Age;
|
||||
public:
|
||||
CVoiceHandle()
|
||||
: m_Id(-1), m_Age(-1)
|
||||
{}
|
||||
|
||||
bool IsValid() const { return (Id() >= 0) && (Age() >= 0); }
|
||||
int Id() const { return m_Id; }
|
||||
int Age() const { return m_Age; }
|
||||
|
||||
bool operator ==(const CVoiceHandle &Other) const { return m_Id == Other.m_Id && m_Age == Other.m_Age; }
|
||||
};
|
||||
|
||||
|
||||
virtual bool IsSoundEnabled() = 0;
|
||||
|
||||
virtual int LoadWV(const char *pFilename) = 0;
|
||||
|
@ -27,13 +45,23 @@ public:
|
|||
virtual void SetChannel(int ChannelID, float Volume, float Panning) = 0;
|
||||
virtual void SetListenerPos(float x, float y) = 0;
|
||||
|
||||
virtual void SetVoiceVolume(int VoiceId, float Volume) = 0;
|
||||
virtual void SetVoiceMaxDistance(int VoiceId, int Distance) = 0;
|
||||
virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume) = 0;
|
||||
virtual void SetVoiceMaxDistance(CVoiceHandle Voice, int Distance) = 0;
|
||||
virtual void SetVoiceLocation(CVoiceHandle Voice, float x, float y) = 0;
|
||||
|
||||
virtual int PlayAt(int ChannelID, int SampleID, int Flags, float x, float y) = 0;
|
||||
virtual int Play(int ChannelID, int SampleID, int Flags) = 0;
|
||||
virtual CVoiceHandle PlayAt(int ChannelID, int SampleID, int Flags, float x, float y) = 0;
|
||||
virtual CVoiceHandle Play(int ChannelID, int SampleID, int Flags) = 0;
|
||||
virtual void Stop(int SampleID) = 0;
|
||||
virtual void StopAll() = 0;
|
||||
|
||||
protected:
|
||||
inline CVoiceHandle CreateVoiceHandle(int Index, int Age)
|
||||
{
|
||||
CVoiceHandle Voice;
|
||||
Voice.m_Id = Index;
|
||||
Voice.m_Age = Age;
|
||||
return Voice;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ class CMapLayers : public CComponent
|
|||
bool m_EnvelopeUpdate;
|
||||
|
||||
void MapScreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup, float Zoom = 1.0f);
|
||||
static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser);
|
||||
public:
|
||||
enum
|
||||
{
|
||||
|
@ -26,6 +25,8 @@ public:
|
|||
virtual void OnRender();
|
||||
|
||||
void EnvelopeUpdate();
|
||||
|
||||
static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <engine/engine.h>
|
||||
#include <engine/sound.h>
|
||||
|
||||
#include <game/client/components/maplayers.h> // envelope
|
||||
#include <game/client/components/sounds.h>
|
||||
|
||||
#include "mapsounds.h"
|
||||
|
@ -49,7 +50,7 @@ void CMapSounds::OnMapLoad()
|
|||
}
|
||||
|
||||
// enqueue sound sources
|
||||
m_SourceQueue.clear();
|
||||
m_lSourceQueue.clear();
|
||||
for(int g = 0; g < Layers()->NumGroups(); g++)
|
||||
{
|
||||
CMapItemGroup *pGroup = Layers()->GetGroup(g);
|
||||
|
@ -80,10 +81,10 @@ void CMapSounds::OnMapLoad()
|
|||
// dont add sources which are too much delayed
|
||||
if(pSources[i].m_Loop || (Client()->LocalTime() >= pSources[i].m_TimeDelay + Sound()->GetSampleDuration(pSoundLayer->m_Sound)))
|
||||
{
|
||||
CSource source;
|
||||
CSourceQueueEntry source;
|
||||
source.m_Sound = pSoundLayer->m_Sound;
|
||||
source.m_pSource = &pSources[i];
|
||||
m_SourceQueue.add(source);
|
||||
m_lSourceQueue.add(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -91,6 +92,8 @@ void CMapSounds::OnMapLoad()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lVoices.clear();
|
||||
}
|
||||
|
||||
void CMapSounds::OnRender()
|
||||
|
@ -99,29 +102,52 @@ void CMapSounds::OnRender()
|
|||
return;
|
||||
|
||||
// enqueue sounds
|
||||
for(int i = 0; i < m_SourceQueue.size(); i++)
|
||||
for(int i = 0; i < m_lSourceQueue.size(); i++)
|
||||
{
|
||||
CSource Source = m_SourceQueue[i];
|
||||
CSourceQueueEntry *pSource = &m_lSourceQueue[i];
|
||||
|
||||
if(!Source.m_pSource || Source.m_Sound == -1)
|
||||
if(!pSource->m_pSource || pSource->m_Sound == -1)
|
||||
{
|
||||
m_SourceQueue.remove(Source);
|
||||
m_lSourceQueue.remove_index(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Source.m_pSource->m_TimeDelay <= Client()->LocalTime())
|
||||
if(pSource->m_pSource->m_TimeDelay <= Client()->LocalTime())
|
||||
{
|
||||
{
|
||||
int Flags = 0;
|
||||
if(Source.m_pSource->m_Loop) Flags |= ISound::FLAG_LOOP;
|
||||
int Flags = 0;
|
||||
if(pSource->m_pSource->m_Loop) Flags |= ISound::FLAG_LOOP;
|
||||
|
||||
if(Source.m_pSource->m_Global)
|
||||
m_pClient->m_pSounds->PlaySample(CSounds::CHN_AMBIENT, m_aSounds[Source.m_Sound], 1.0f, Flags);
|
||||
else
|
||||
m_pClient->m_pSounds->PlaySampleAt(CSounds::CHN_AMBIENT, m_aSounds[Source.m_Sound], 1.0f, vec2(fx2f(Source.m_pSource->m_Position.x), fx2f(Source.m_pSource->m_Position.y)), Flags);
|
||||
}
|
||||
CSourceVoice Voice;
|
||||
Voice.m_pSource = pSource->m_pSource;
|
||||
|
||||
m_SourceQueue.remove(Source);
|
||||
}
|
||||
if(pSource->m_pSource->m_Global)
|
||||
Voice.m_Voice = m_pClient->m_pSounds->PlaySample(CSounds::CHN_AMBIENT, m_aSounds[pSource->m_Sound], 1.0f, Flags);
|
||||
else
|
||||
Voice.m_Voice = m_pClient->m_pSounds->PlaySampleAt(CSounds::CHN_AMBIENT, m_aSounds[pSource->m_Sound], 1.0f, vec2(fx2f(pSource->m_pSource->m_Position.x), fx2f(pSource->m_pSource->m_Position.y)), Flags);
|
||||
|
||||
Sound()->SetVoiceMaxDistance(Voice.m_Voice, pSource->m_pSource->m_FalloffDistance);
|
||||
|
||||
m_lVoices.add(Voice);
|
||||
m_lSourceQueue.remove_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
// update voices
|
||||
for(int i = 0; i < m_lVoices.size(); i++)
|
||||
{
|
||||
CSourceVoice *pVoice = &m_lVoices[i];;
|
||||
|
||||
if(!pVoice->m_Voice.IsValid())
|
||||
continue;
|
||||
|
||||
if(pVoice->m_pSource->m_PosEnv >= 0)
|
||||
{
|
||||
float aChannels[4];
|
||||
CMapLayers::EnvelopeEval(pVoice->m_pSource->m_PosEnvOffset/1000.0f, pVoice->m_pSource->m_PosEnv, aChannels, m_pClient->m_pMapLayersBackGround);
|
||||
float OffsetX = aChannels[0];
|
||||
float OffsetY = aChannels[1];
|
||||
|
||||
Sound()->SetVoiceLocation(pVoice->m_Voice, fx2f(pVoice->m_pSource->m_Position.x)+OffsetX, fx2f(pVoice->m_pSource->m_Position.y)+OffsetY);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <base/tl/array.h>
|
||||
|
||||
#include <engine/sound.h>
|
||||
|
||||
#include <game/client/component.h>
|
||||
|
||||
class CMapSounds : public CComponent
|
||||
|
@ -10,15 +12,22 @@ class CMapSounds : public CComponent
|
|||
int m_aSounds[64];
|
||||
int m_Count;
|
||||
|
||||
struct CSource
|
||||
struct CSourceQueueEntry
|
||||
{
|
||||
int m_Sound;
|
||||
CSoundSource *m_pSource;
|
||||
|
||||
bool operator ==(const CSource &Other) const { return (m_Sound == Other.m_Sound) && (m_pSource == Other.m_pSource); }
|
||||
bool operator ==(const CSourceQueueEntry &Other) const { return (m_Sound == Other.m_Sound) && (m_pSource == Other.m_pSource); }
|
||||
};
|
||||
|
||||
array<CSource> m_SourceQueue;
|
||||
array<CSourceQueueEntry> m_lSourceQueue;
|
||||
|
||||
struct CSourceVoice
|
||||
{
|
||||
ISound::CVoiceHandle m_Voice;
|
||||
CSoundSource *m_pSource;
|
||||
};
|
||||
array<CSourceVoice> m_lVoices;
|
||||
|
||||
public:
|
||||
CMapSounds();
|
||||
|
|
|
@ -206,24 +206,24 @@ void CSounds::Stop(int SetId)
|
|||
Sound()->Stop(pSet->m_aSounds[i].m_Id);
|
||||
}
|
||||
|
||||
void CSounds::PlaySample(int Chn, int SampleId, float Vol, int Flags)
|
||||
ISound::CVoiceHandle CSounds::PlaySample(int Chn, int SampleId, float Vol, int Flags)
|
||||
{
|
||||
if((Chn == CHN_MUSIC && !g_Config.m_SndMusic) || SampleId == -1)
|
||||
return;
|
||||
return ISound::CVoiceHandle();
|
||||
|
||||
if(Chn == CHN_MUSIC)
|
||||
Flags |= ISound::FLAG_LOOP;
|
||||
|
||||
Sound()->Play(Chn, SampleId, Flags);
|
||||
return Sound()->Play(Chn, SampleId, Flags);
|
||||
}
|
||||
|
||||
void CSounds::PlaySampleAt(int Chn, int SampleId, float Vol, vec2 Pos, int Flags)
|
||||
ISound::CVoiceHandle CSounds::PlaySampleAt(int Chn, int SampleId, float Vol, vec2 Pos, int Flags)
|
||||
{
|
||||
if((Chn == CHN_MUSIC && !g_Config.m_SndMusic) || SampleId == -1)
|
||||
return;
|
||||
return ISound::CVoiceHandle();
|
||||
|
||||
if(Chn == CHN_MUSIC)
|
||||
Flags |= ISound::FLAG_LOOP;
|
||||
|
||||
Sound()->PlayAt(Chn, SampleId, Flags, Pos.x, Pos.y);
|
||||
return Sound()->PlayAt(Chn, SampleId, Flags, Pos.x, Pos.y);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
#ifndef GAME_CLIENT_COMPONENTS_SOUNDS_H
|
||||
#define GAME_CLIENT_COMPONENTS_SOUNDS_H
|
||||
#include <engine/sound.h>
|
||||
#include <game/client/component.h>
|
||||
|
||||
class CSounds : public CComponent
|
||||
|
@ -45,8 +46,8 @@ public:
|
|||
void PlayAndRecord(int Channel, int SetId, float Vol, vec2 Pos);
|
||||
void Stop(int SetId);
|
||||
|
||||
void PlaySample(int Channel, int SampleId, float Vol, int Flags = 0);
|
||||
void PlaySampleAt(int Channel, int SampleId, float Vol, vec2 Pos, int Flags = 0);
|
||||
ISound::CVoiceHandle PlaySample(int Channel, int SampleId, float Vol, int Flags = 0);
|
||||
ISound::CVoiceHandle PlaySampleAt(int Channel, int SampleId, float Vol, vec2 Pos, int Flags = 0);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue