Ingame sound pos envelope support

This commit is contained in:
BeaR 2014-10-12 16:12:13 +02:00
parent 920ac531aa
commit e211c7a2b2
8 changed files with 146 additions and 50 deletions

View file

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

View file

@ -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();
};

View file

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

View file

@ -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

View file

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

View file

@ -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();

View file

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

View file

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