aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2008-08-14 05:43:52 -0700
committerChris Robinson <[email protected]>2008-08-14 05:43:52 -0700
commit22557070ec4852d64ad153f5cac907f84119702c (patch)
tree5ef3211350145257afdd1642699a206da89d8bfe
parentf8ef66954c4cd95a8c91a458b33a8e8318a72d5b (diff)
Ramp channel gains to remove pops and clicks from abrupt changes
Thanks to Christopher Fitzgerald for helping me work on it
-rw-r--r--Alc/ALu.c72
-rw-r--r--OpenAL32/Include/alSource.h7
-rw-r--r--OpenAL32/Include/alu.h13
3 files changed, 72 insertions, 20 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 4454b8d4..39f01f2f 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -31,6 +31,7 @@
#include "alThunk.h"
#include "alListener.h"
#include "alAuxEffectSlot.h"
+#include "alu.h"
#include "bs2b.h"
#if defined(HAVE_STDINT_H)
@@ -69,18 +70,9 @@ typedef long long ALint64;
#define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
#define MAX_PITCH 4
-enum {
- FRONT_LEFT = 0,
- FRONT_RIGHT,
- SIDE_LEFT,
- SIDE_RIGHT,
- BACK_LEFT,
- BACK_RIGHT,
- CENTER,
- LFE,
-
- OUTPUTCHANNELS
-};
+/* Minimum ramp length in milliseconds. The value below was chosen to
+ * adequately reduce clicks and pops from harsh gain changes. */
+#define MIN_RAMP_LENGTH 16
ALboolean DuplicateStereo = AL_FALSE;
@@ -628,10 +620,17 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS];
static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS];
- ALfloat DrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
- ALfloat WetSend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ ALfloat newDrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ ALfloat newWetSend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
ALfloat DryGainHF = 0.0f;
ALfloat WetGainHF = 0.0f;
+ ALfloat *DrySend;
+ ALfloat *WetSend;
+ ALuint rampLength;
+ ALfloat dryGainStep[OUTPUTCHANNELS];
+ ALfloat wetGainStep[OUTPUTCHANNELS];
+ ALfloat dryGainHFStep;
+ ALfloat wetGainHFStep;
ALuint BlockAlign,BufferSize;
ALuint DataSize=0,DataPosInt=0,DataPosFrac=0;
ALuint Channels,Frequency,ulExtraSamples;
@@ -672,9 +671,20 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
while(size > 0)
{
//Setup variables
- ALEffectSlot = (ALContext ? ALContext->AuxiliaryEffectSlot : NULL);
- ALSource = (ALContext ? ALContext->Source : NULL);
SamplesToDo = min(size, BUFFERSIZE);
+ if(ALContext)
+ {
+ ALEffectSlot = ALContext->AuxiliaryEffectSlot;
+ ALSource = ALContext->Source;
+ rampLength = ALContext->Frequency * MIN_RAMP_LENGTH / 1000;
+ }
+ else
+ {
+ ALEffectSlot = NULL;
+ ALSource = NULL;
+ rampLength = 0;
+ }
+ rampLength = max(rampLength, SamplesToDo);
//Clear mixing buffer
memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
@@ -703,10 +713,9 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
Frequency = ALBuffer->frequency;
CalcSourceParams(ALContext, ALSource,
- (Channels==1) ? AL_TRUE : AL_FALSE,
- format, DrySend, WetSend, &Pitch,
- &DryGainHF, &WetGainHF);
-
+ (Channels==1) ? AL_TRUE : AL_FALSE,
+ format, newDrySend, newWetSend, &Pitch,
+ &DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
DataSize /= Channels * aluBytesFromFormat(ALBuffer->format);
@@ -715,6 +724,19 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
DataPosInt = ALSource->position;
DataPosFrac = ALSource->position_fraction;
Filter = &ALSource->iirFilter;
+ DrySend = ALSource->DryGains;
+ WetSend = ALSource->WetGains;
+
+ //Compute the gain steps for each output channel
+ for(i = 0;i < OUTPUTCHANNELS;i++)
+ {
+ dryGainStep[i] = (newDrySend[i]-DrySend[i]) / rampLength;
+ wetGainStep[i] = (newWetSend[i]-WetSend[i]) / rampLength;
+ }
+ dryGainHFStep = (DryGainHF-ALSource->DryGainHF) / rampLength;
+ wetGainHFStep = (WetGainHF-ALSource->WetGainHF) / rampLength;
+ DryGainHF = ALSource->DryGainHF;
+ WetGainHF = ALSource->WetGainHF;
//Compute 18.14 fixed point step
increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
@@ -767,6 +789,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
k = DataPosFrac>>FRACTIONBITS;
fraction = DataPosFrac&FRACTIONMASK;
+ for(i = 0;i < OUTPUTCHANNELS;i++)
+ {
+ DrySend[i] += dryGainStep[i];
+ WetSend[i] += wetGainStep[i];
+ }
+ DryGainHF += dryGainHFStep;
+ WetGainHF += wetGainHFStep;
+
if(Channels==1)
{
ALfloat sample, lowsamp, outsamp;
@@ -872,6 +902,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
//Update source info
ALSource->position = DataPosInt;
ALSource->position_fraction = DataPosFrac;
+ ALSource->DryGainHF = DryGainHF;
+ ALSource->WetGainHF = WetGainHF;
}
//Handle looping sources
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
index 73b02609..42a1b915 100644
--- a/OpenAL32/Include/alSource.h
+++ b/OpenAL32/Include/alSource.h
@@ -7,6 +7,7 @@
#define MAX_SENDS 1
#include "alFilter.h"
+#include "alu.h"
#include "AL/al.h"
#define AL_DIRECT_FILTER 0x20005
@@ -94,6 +95,12 @@ typedef struct ALsource
// Source Type (Static, Streaming, or Undetermined)
ALint lSourceType;
+ // Current gains, which are ramped while mixed
+ ALfloat DryGains[OUTPUTCHANNELS];
+ ALfloat WetGains[OUTPUTCHANNELS];
+ ALfloat DryGainHF;
+ ALfloat WetGainHF;
+
struct ALsource *next;
} ALsource;
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index 6fab1fae..b14180b2 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -8,6 +8,19 @@
extern "C" {
#endif
+enum {
+ FRONT_LEFT = 0,
+ FRONT_RIGHT,
+ SIDE_LEFT,
+ SIDE_RIGHT,
+ BACK_LEFT,
+ BACK_RIGHT,
+ CENTER,
+ LFE,
+
+ OUTPUTCHANNELS
+};
+
extern ALboolean DuplicateStereo;
__inline ALuint aluBytesFromFormat(ALenum format);