Use vec2s for sound positions

Simply usage and readability of sound functions by using `vec2`s instead of two separate `float`s for positions.
This commit is contained in:
Robert Müller 2024-05-26 11:18:16 +02:00
parent e0e1ef8001
commit 986916400d
5 changed files with 47 additions and 65 deletions

View file

@ -63,12 +63,10 @@ void CSound::Mix(short *pFinalOut, unsigned Frames)
if(Voice.m_Flags & ISound::FLAG_POS && Voice.m_pChannel->m_Pan) if(Voice.m_Flags & ISound::FLAG_POS && Voice.m_pChannel->m_Pan)
{ {
// TODO: we should respect the channel panning value // TODO: we should respect the channel panning value
const int dx = Voice.m_X - m_CenterX.load(std::memory_order_relaxed); const vec2 Delta = Voice.m_Position - vec2(m_ListenerPositionX.load(std::memory_order_relaxed), m_ListenerPositionY.load(std::memory_order_relaxed));
const int dy = Voice.m_Y - m_CenterY.load(std::memory_order_relaxed); vec2 Falloff = vec2(0.0f, 0.0f);
float FalloffX = 0.0f;
float FalloffY = 0.0f;
int RangeX = 0; // for panning float RangeX = 0.0f; // for panning
bool InVoiceField = false; bool InVoiceField = false;
switch(Voice.m_Shape) switch(Voice.m_Shape)
@ -78,50 +76,34 @@ void CSound::Mix(short *pFinalOut, unsigned Frames)
const float Radius = Voice.m_Circle.m_Radius; const float Radius = Voice.m_Circle.m_Radius;
RangeX = Radius; RangeX = Radius;
// dx and dy can be larger than 46341 and thus the calculation would go beyond the limits of a integer, const float Dist = length(Delta);
// therefore we cast them into float
const int Dist = (int)length(vec2(dx, dy));
if(Dist < Radius) if(Dist < Radius)
{ {
InVoiceField = true; InVoiceField = true;
// falloff // falloff
int FalloffDistance = Radius * Voice.m_Falloff; const float FalloffDistance = Radius * Voice.m_Falloff;
if(Dist > FalloffDistance) Falloff.x = Falloff.y = Dist > FalloffDistance ? (Radius - Dist) / (Radius - FalloffDistance) : 1.0f;
FalloffX = FalloffY = (Radius - Dist) / (Radius - FalloffDistance);
else
FalloffX = FalloffY = 1.0f;
} }
else
InVoiceField = false;
break; break;
} }
case ISound::SHAPE_RECTANGLE: case ISound::SHAPE_RECTANGLE:
{ {
RangeX = Voice.m_Rectangle.m_Width / 2.0f; const vec2 AbsoluteDelta = vec2(absolute(Delta.x), absolute(Delta.y));
const float w = Voice.m_Rectangle.m_Width / 2.0f;
const float h = Voice.m_Rectangle.m_Height / 2.0f;
RangeX = w;
const int abs_dx = absolute(dx); if(AbsoluteDelta.x < w && AbsoluteDelta.y < h)
const int abs_dy = absolute(dy);
const int w = Voice.m_Rectangle.m_Width / 2.0f;
const int h = Voice.m_Rectangle.m_Height / 2.0f;
if(abs_dx < w && abs_dy < h)
{ {
InVoiceField = true; InVoiceField = true;
// falloff // falloff
int fx = Voice.m_Falloff * w; const vec2 FalloffDistance = vec2(w, h) * Voice.m_Falloff;
int fy = Voice.m_Falloff * h; Falloff.x = AbsoluteDelta.x > FalloffDistance.x ? (w - AbsoluteDelta.x) / (w - FalloffDistance.x) : 1.0f;
Falloff.y = AbsoluteDelta.y > FalloffDistance.y ? (h - AbsoluteDelta.y) / (h - FalloffDistance.y) : 1.0f;
FalloffX = abs_dx > fx ? (float)(w - abs_dx) / (w - fx) : 1.0f;
FalloffY = abs_dy > fy ? (float)(h - abs_dy) / (h - fy) : 1.0f;
} }
else
InVoiceField = false;
break; break;
} }
}; };
@ -131,15 +113,15 @@ void CSound::Mix(short *pFinalOut, unsigned Frames)
// panning // panning
if(!(Voice.m_Flags & ISound::FLAG_NO_PANNING)) if(!(Voice.m_Flags & ISound::FLAG_NO_PANNING))
{ {
if(dx > 0) if(Delta.x > 0)
VolumeL = ((RangeX - absolute(dx)) * VolumeL) / RangeX; VolumeL = ((RangeX - absolute(Delta.x)) * VolumeL) / RangeX;
else else
VolumeR = ((RangeX - absolute(dx)) * VolumeR) / RangeX; VolumeR = ((RangeX - absolute(Delta.x)) * VolumeR) / RangeX;
} }
{ {
VolumeL *= FalloffX * FalloffY; VolumeL *= Falloff.x * Falloff.y;
VolumeR *= FalloffX * FalloffY; VolumeR *= Falloff.x * Falloff.y;
} }
} }
else else
@ -723,10 +705,10 @@ void CSound::SetChannel(int ChannelId, float Vol, float Pan)
m_aChannels[ChannelId].m_Pan = (int)(Pan * 255.0f); // TODO: this is only on and off right now m_aChannels[ChannelId].m_Pan = (int)(Pan * 255.0f); // TODO: this is only on and off right now
} }
void CSound::SetListenerPos(float x, float y) void CSound::SetListenerPosition(vec2 Position)
{ {
m_CenterX.store((int)x, std::memory_order_relaxed); m_ListenerPositionX.store(Position.x, std::memory_order_relaxed);
m_CenterY.store((int)y, std::memory_order_relaxed); m_ListenerPositionY.store(Position.y, std::memory_order_relaxed);
} }
void CSound::SetVoiceVolume(CVoiceHandle Voice, float Volume) void CSound::SetVoiceVolume(CVoiceHandle Voice, float Volume)
@ -759,7 +741,7 @@ void CSound::SetVoiceFalloff(CVoiceHandle Voice, float Falloff)
m_aVoices[VoiceId].m_Falloff = Falloff; m_aVoices[VoiceId].m_Falloff = Falloff;
} }
void CSound::SetVoiceLocation(CVoiceHandle Voice, float x, float y) void CSound::SetVoicePosition(CVoiceHandle Voice, vec2 Position)
{ {
if(!Voice.IsValid()) if(!Voice.IsValid())
return; return;
@ -770,8 +752,7 @@ void CSound::SetVoiceLocation(CVoiceHandle Voice, float x, float y)
if(m_aVoices[VoiceId].m_Age != Voice.Age()) if(m_aVoices[VoiceId].m_Age != Voice.Age())
return; return;
m_aVoices[VoiceId].m_X = x; m_aVoices[VoiceId].m_Position = Position;
m_aVoices[VoiceId].m_Y = y;
} }
void CSound::SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) void CSound::SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset)
@ -839,7 +820,7 @@ void CSound::SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height)
m_aVoices[VoiceId].m_Rectangle.m_Height = maximum(0.0f, Height); m_aVoices[VoiceId].m_Rectangle.m_Height = maximum(0.0f, Height);
} }
ISound::CVoiceHandle CSound::Play(int ChannelId, int SampleId, int Flags, float x, float y) ISound::CVoiceHandle CSound::Play(int ChannelId, int SampleId, int Flags, vec2 Position)
{ {
const CLockScope LockScope(m_SoundLock); const CLockScope LockScope(m_SoundLock);
@ -877,8 +858,7 @@ ISound::CVoiceHandle CSound::Play(int ChannelId, int SampleId, int Flags, float
} }
m_aVoices[VoiceId].m_Vol = 255; m_aVoices[VoiceId].m_Vol = 255;
m_aVoices[VoiceId].m_Flags = Flags; m_aVoices[VoiceId].m_Flags = Flags;
m_aVoices[VoiceId].m_X = (int)x; m_aVoices[VoiceId].m_Position = Position;
m_aVoices[VoiceId].m_Y = (int)y;
m_aVoices[VoiceId].m_Falloff = 0.0f; m_aVoices[VoiceId].m_Falloff = 0.0f;
m_aVoices[VoiceId].m_Shape = ISound::SHAPE_CIRCLE; m_aVoices[VoiceId].m_Shape = ISound::SHAPE_CIRCLE;
m_aVoices[VoiceId].m_Circle.m_Radius = 1500; m_aVoices[VoiceId].m_Circle.m_Radius = 1500;
@ -888,14 +868,14 @@ ISound::CVoiceHandle CSound::Play(int ChannelId, int SampleId, int Flags, float
return CreateVoiceHandle(VoiceId, Age); return CreateVoiceHandle(VoiceId, Age);
} }
ISound::CVoiceHandle CSound::PlayAt(int ChannelId, int SampleId, int Flags, float x, float y) ISound::CVoiceHandle CSound::PlayAt(int ChannelId, int SampleId, int Flags, vec2 Position)
{ {
return Play(ChannelId, SampleId, Flags | ISound::FLAG_POS, x, y); return Play(ChannelId, SampleId, Flags | ISound::FLAG_POS, Position);
} }
ISound::CVoiceHandle 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); return Play(ChannelId, SampleId, Flags, vec2(0.0f, 0.0f));
} }
void CSound::Pause(int SampleId) void CSound::Pause(int SampleId)

View file

@ -44,7 +44,7 @@ struct CVoice
int m_Tick; int m_Tick;
int m_Vol; // 0 - 255 int m_Vol; // 0 - 255
int m_Flags; int m_Flags;
int m_X, m_Y; vec2 m_Position;
float m_Falloff; // [0.0, 1.0] float m_Falloff; // [0.0, 1.0]
int m_Shape; int m_Shape;
@ -76,8 +76,10 @@ class CSound : public IEngineSound
int m_NextVoice = 0; int m_NextVoice = 0;
uint32_t m_MaxFrames = 0; uint32_t m_MaxFrames = 0;
std::atomic<int> m_CenterX = 0; // This is not an std::atomic<vec2> as this would require linking with
std::atomic<int> m_CenterY = 0; // libatomic with clang x86 as there is no native support for this.
std::atomic<float> m_ListenerPositionX = 0.0f;
std::atomic<float> m_ListenerPositionY = 0.0f;
std::atomic<int> m_SoundVolume = 100; std::atomic<int> m_SoundVolume = 100;
int m_MixingRate = 48000; int m_MixingRate = 48000;
@ -112,18 +114,18 @@ public:
void SetSampleCurrentTime(int SampleId, float Time) override REQUIRES(!m_SoundLock); void SetSampleCurrentTime(int SampleId, float Time) override REQUIRES(!m_SoundLock);
void SetChannel(int ChannelId, float Vol, float Pan) override; void SetChannel(int ChannelId, float Vol, float Pan) override;
void SetListenerPos(float x, float y) override; void SetListenerPosition(vec2 Position) override;
void SetVoiceVolume(CVoiceHandle Voice, float Volume) override REQUIRES(!m_SoundLock); void SetVoiceVolume(CVoiceHandle Voice, float Volume) override REQUIRES(!m_SoundLock);
void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) override REQUIRES(!m_SoundLock); void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) override REQUIRES(!m_SoundLock);
void SetVoiceLocation(CVoiceHandle Voice, float x, float y) override REQUIRES(!m_SoundLock); void SetVoicePosition(CVoiceHandle Voice, vec2 Position) override REQUIRES(!m_SoundLock);
void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) override REQUIRES(!m_SoundLock); // in s void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) override REQUIRES(!m_SoundLock); // in s
void SetVoiceCircle(CVoiceHandle Voice, float Radius) override REQUIRES(!m_SoundLock); void SetVoiceCircle(CVoiceHandle Voice, float Radius) override REQUIRES(!m_SoundLock);
void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) override REQUIRES(!m_SoundLock); void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) override REQUIRES(!m_SoundLock);
CVoiceHandle Play(int ChannelId, int SampleId, int Flags, float x, float y) REQUIRES(!m_SoundLock); CVoiceHandle Play(int ChannelId, int SampleId, int Flags, vec2 Position) REQUIRES(!m_SoundLock);
CVoiceHandle PlayAt(int ChannelId, int SampleId, int Flags, float x, float y) override REQUIRES(!m_SoundLock); CVoiceHandle PlayAt(int ChannelId, int SampleId, int Flags, vec2 Position) override REQUIRES(!m_SoundLock);
CVoiceHandle Play(int ChannelId, int SampleId, int Flags) override REQUIRES(!m_SoundLock); CVoiceHandle Play(int ChannelId, int SampleId, int Flags) override REQUIRES(!m_SoundLock);
void Pause(int SampleId) override REQUIRES(!m_SoundLock); void Pause(int SampleId) override REQUIRES(!m_SoundLock);
void Stop(int SampleId) override REQUIRES(!m_SoundLock); void Stop(int SampleId) override REQUIRES(!m_SoundLock);

View file

@ -6,6 +6,8 @@
#include <engine/kernel.h> #include <engine/kernel.h>
#include <engine/storage.h> #include <engine/storage.h>
#include <base/vmath.h>
class ISound : public IInterface class ISound : public IInterface
{ {
MACRO_INTERFACE("sound") MACRO_INTERFACE("sound")
@ -74,17 +76,17 @@ public:
virtual void SetSampleCurrentTime(int SampleId, float Time) = 0; virtual void SetSampleCurrentTime(int SampleId, float Time) = 0;
virtual void SetChannel(int ChannelId, float Volume, float Panning) = 0; virtual void SetChannel(int ChannelId, float Volume, float Panning) = 0;
virtual void SetListenerPos(float x, float y) = 0; virtual void SetListenerPosition(vec2 Position) = 0;
virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume) = 0; virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume) = 0;
virtual void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) = 0; virtual void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) = 0;
virtual void SetVoiceLocation(CVoiceHandle Voice, float x, float y) = 0; virtual void SetVoicePosition(CVoiceHandle Voice, vec2 Position) = 0;
virtual void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) = 0; // in s virtual void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) = 0; // in s
virtual void SetVoiceCircle(CVoiceHandle Voice, float Radius) = 0; virtual void SetVoiceCircle(CVoiceHandle Voice, float Radius) = 0;
virtual void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) = 0; virtual void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) = 0;
virtual CVoiceHandle PlayAt(int ChannelId, int SampleId, int Flags, float x, float y) = 0; virtual CVoiceHandle PlayAt(int ChannelId, int SampleId, int Flags, vec2 Position) = 0;
virtual CVoiceHandle Play(int ChannelId, int SampleId, int Flags) = 0; virtual CVoiceHandle Play(int ChannelId, int SampleId, int Flags) = 0;
virtual void Pause(int SampleId) = 0; virtual void Pause(int SampleId) = 0;
virtual void Stop(int SampleId) = 0; virtual void Stop(int SampleId) = 0;

View file

@ -239,7 +239,7 @@ void CMapSounds::OnRender()
x -= pGroup->m_OffsetX; x -= pGroup->m_OffsetX;
y -= pGroup->m_OffsetY; y -= pGroup->m_OffsetY;
Sound()->SetVoiceLocation(Voice.m_Voice, x, y); Sound()->SetVoicePosition(Voice.m_Voice, vec2(x, y));
ColorRGBA Volume = ColorRGBA(1.0f, 0.0f, 0.0f, 0.0f); ColorRGBA Volume = ColorRGBA(1.0f, 0.0f, 0.0f, 0.0f);
CMapLayers::EnvelopeEval(Voice.m_pSource->m_SoundEnvOffset, Voice.m_pSource->m_SoundEnv, Volume, 1, &m_pClient->m_MapLayersBackground); CMapLayers::EnvelopeEval(Voice.m_pSource->m_SoundEnvOffset, Voice.m_pSource->m_SoundEnv, Volume, 1, &m_pClient->m_MapLayersBackground);

View file

@ -143,9 +143,7 @@ void CSounds::OnRender()
return; return;
} }
// set listener pos Sound()->SetListenerPosition(m_pClient->m_Camera.m_Center);
Sound()->SetListenerPos(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
UpdateChannels(); UpdateChannels();
// play sound from queue // play sound from queue
@ -224,7 +222,7 @@ void CSounds::PlayAt(int Channel, int SetId, float Vol, vec2 Pos)
if(Channel == CHN_MUSIC) if(Channel == CHN_MUSIC)
Flags = ISound::FLAG_LOOP; Flags = ISound::FLAG_LOOP;
Sound()->PlayAt(Channel, SampleId, Flags, Pos.x, Pos.y); Sound()->PlayAt(Channel, SampleId, Flags, Pos);
} }
void CSounds::Stop(int SetId) void CSounds::Stop(int SetId)
@ -269,5 +267,5 @@ ISound::CVoiceHandle CSounds::PlaySampleAt(int Channel, int SampleId, float Vol,
if(Channel == CHN_MUSIC) if(Channel == CHN_MUSIC)
Flags |= ISound::FLAG_LOOP; Flags |= ISound::FLAG_LOOP;
return Sound()->PlayAt(Channel, SampleId, Flags, Pos.x, Pos.y); return Sound()->PlayAt(Channel, SampleId, Flags, Pos);
} }