Implement sound logic for shaped sounds, fix rectangle height property in editor and submit voice shape information to audio interface

This commit is contained in:
BeaR 2014-11-29 14:29:40 +01:00
parent 485aa4ce54
commit 98d42adf9d
5 changed files with 164 additions and 11 deletions

View file

@ -40,7 +40,7 @@ struct CChannel
{
int m_Vol;
int m_Pan;
} ;
};
struct CVoice
{
@ -51,7 +51,15 @@ struct CVoice
int m_Vol; // 0 - 255
int m_Flags;
int m_X, m_Y;
} ;
float m_Falloff; // [0.0, 1.0]
int m_Shape;
union
{
ISound::CVoiceShapeCircle m_Circle;
ISound::CVoiceShapeRectangle m_Rectangle;
};
};
static CSample m_aSamples[NUM_SAMPLES] = { {0} };
static CVoice m_aVoices[NUM_VOICES] = { {0} };
@ -134,20 +142,79 @@ static void Mix(short *pFinalOut, unsigned Frames)
// TODO: we should respect the channel panning value
int dx = v->m_X - m_CenterX;
int dy = v->m_Y - m_CenterY;
int Dist = (int)sqrtf((float)dx*dx+dy*dy); // float here. nasty
//
int p = IntAbs(dx);
int Range = DefaultDistance;
if(Dist >= 0 && Dist < Range)
float FalloffX = 0.0f;
float FalloffY = 0.0f;
int RangeX = 0; // for panning
bool InVoiceField = false;
switch(v->m_Shape)
{
case ISound::SHAPE_CIRCLE:
{
float r = v->m_Circle.m_Radius;
RangeX = r;
int Dist = (int)sqrtf((float)dx*dx+dy*dy); // nasty float
if(Dist < r)
{
InVoiceField = true;
// falloff
int FalloffDistance = r*v->m_Falloff;
if(Dist > FalloffDistance)
FalloffX = FalloffY = (r-Dist)/(r-FalloffDistance);
else
FalloffX = FalloffY = 1.0f;
}
else
InVoiceField = false;
break;
}
case ISound::SHAPE_RECTANGLE:
{
RangeX = v->m_Rectangle.m_Width/2.0f;
int abs_dx = abs(dx);
int abs_dy = abs(dy);
int w = v->m_Rectangle.m_Width/2.0f;
int h = v->m_Rectangle.m_Height/2.0f;
if(abs_dx < w && abs_dy < h)
{
InVoiceField = true;
// falloff
int fx = v->m_Falloff * w;
int fy = v->m_Falloff * h;
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;
}
};
if(InVoiceField)
{
// panning
if(dx > 0)
Lvol = ((Range-p)*Lvol)/Range;
Lvol = ((RangeX-p)*Lvol)/RangeX;
else
Rvol = ((Range-p)*Rvol)/Range;
Rvol = ((RangeX-p)*Rvol)/RangeX;
// falloff
Lvol = (Lvol*(Range-Dist))/Range;
Rvol = (Rvol*(Range-Dist))/Range;
{
Lvol *= FalloffX;
Rvol *= FalloffY;
}
}
else
{
@ -645,6 +712,20 @@ void CSound::SetVoiceVolume(CVoiceHandle Voice, float Volume)
m_aVoices[VoiceID].m_Vol = (int)(Volume*255.0f);
}
void CSound::SetVoiceFalloff(CVoiceHandle Voice, float Falloff)
{
if(!Voice.IsValid())
return;
int VoiceID = Voice.Id();
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;
Falloff = clamp(Falloff, 0.0f, 1.0f);
m_aVoices[VoiceID].m_Falloff = Falloff;
}
void CSound::SetVoiceLocation(CVoiceHandle Voice, float x, float y)
{
if(!Voice.IsValid())
@ -696,6 +777,35 @@ void CSound::SetVoiceTimeOffset(CVoiceHandle Voice, float offset)
lock_release(m_SoundLock);
}
void CSound::SetVoiceCircle(CVoiceHandle Voice, float Radius)
{
if(!Voice.IsValid())
return;
int VoiceID = Voice.Id();
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;
m_aVoices[VoiceID].m_Shape = ISound::SHAPE_CIRCLE;
m_aVoices[VoiceID].m_Circle.m_Radius = max(0.0f, Radius);
}
void CSound::SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height)
{
if(!Voice.IsValid())
return;
int VoiceID = Voice.Id();
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;
m_aVoices[VoiceID].m_Shape = ISound::SHAPE_RECTANGLE;
m_aVoices[VoiceID].m_Rectangle.m_Width = max(0.0f, Width);
m_aVoices[VoiceID].m_Rectangle.m_Height = max(0.0f, Height);
}
void CSound::SetChannel(int ChannelID, float Vol, float Pan)
{
m_aChannels[ChannelID].m_Vol = (int)(Vol*255.0f);
@ -735,6 +845,9 @@ ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags, float
m_aVoices[VoiceID].m_Flags = Flags;
m_aVoices[VoiceID].m_X = (int)x;
m_aVoices[VoiceID].m_Y = (int)y;
m_aVoices[VoiceID].m_Falloff = 0.0f;
m_aVoices[VoiceID].m_Shape = ISound::SHAPE_CIRCLE;
m_aVoices[VoiceID].m_Circle.m_Radius = DefaultDistance;
Age = m_aVoices[VoiceID].m_Age;
}

View file

@ -41,9 +41,13 @@ public:
virtual void SetChannel(int ChannelID, float Vol, float Pan);
virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume);
virtual void SetVoiceFalloff(CVoiceHandle Voice, float Falloff);
virtual void SetVoiceLocation(CVoiceHandle Voice, float x, float y);
virtual void SetVoiceTimeOffset(CVoiceHandle Voice, float offset); // in s
virtual void SetVoiceCircle(CVoiceHandle Voice, float Radius);
virtual void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height);
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);

View file

@ -16,6 +16,23 @@ public:
FLAG_ALL=3
};
enum
{
SHAPE_CIRCLE,
SHAPE_RECTANGLE,
};
struct CVoiceShapeCircle
{
float m_Radius;
};
struct CVoiceShapeRectangle
{
float m_Width;
float m_Height;
};
class CVoiceHandle
{
friend class ISound;
@ -48,9 +65,13 @@ public:
virtual void SetListenerPos(float x, float y) = 0;
virtual void SetVoiceVolume(CVoiceHandle Voice, float Volume) = 0;
virtual void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) = 0;
virtual void SetVoiceLocation(CVoiceHandle Voice, float x, float y) = 0;
virtual void SetVoiceTimeOffset(CVoiceHandle Voice, float offset) = 0; // in s
virtual void SetVoiceCircle(CVoiceHandle Voice, float Radius) = 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 Play(int ChannelID, int SampleID, int Flags) = 0;
virtual void Stop(int SampleID) = 0;

View file

@ -123,6 +123,21 @@ void CMapSounds::OnRender()
pSource->m_Voice = m_pClient->m_pSounds->PlaySampleAt(CSounds::CHN_MAPSOUND, m_aSounds[pSource->m_Sound], 1.0f, vec2(fx2f(pSource->m_pSource->m_Position.x), fx2f(pSource->m_pSource->m_Position.y)), Flags);
Sound()->SetVoiceTimeOffset(pSource->m_Voice, offset);
Sound()->SetVoiceFalloff(pSource->m_Voice, pSource->m_pSource->m_Falloff/255.0f);
switch(pSource->m_pSource->m_Shape.m_Type)
{
case CSoundShape::SHAPE_CIRCLE:
{
Sound()->SetVoiceCircle(pSource->m_Voice, pSource->m_pSource->m_Shape.m_Circle.m_Radius);
break;
}
case CSoundShape::SHAPE_RECTANGLE:
{
Sound()->SetVoiceRectangle(pSource->m_Voice, fx2f(pSource->m_pSource->m_Shape.m_Rectangle.m_Width), fx2f(pSource->m_pSource->m_Shape.m_Rectangle.m_Height));
break;
}
};
}
}
else

View file

@ -782,7 +782,7 @@ int CEditor::PopupSource(CEditor *pEditor, CUIRect View)
pEditor->m_Map.m_Modified = true;
if(Prop == PROP_RECTANGLE_WIDTH) pSource->m_Shape.m_Rectangle.m_Width = NewVal*1024;
//if(Prop == PROP_RECTANGLE_HEIGHT) pSource->m_Shape.m_Rectangle.m_Height = NewVal*1024;
if(Prop == PROP_RECTANGLE_HEIGHT) pSource->m_Shape.m_Rectangle.m_Height = NewVal*1024;
break;
}