From 705849ca7371176d4e645b92898cb9a235602f9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Jan 2010 05:37:20 -0800 Subject: [PATCH] Add an option for point resampling --- Alc/ALc.c | 7 +++ Alc/ALu.c | 138 ++++++++++++++++++++++++++++++++------------ OpenAL32/Include/alSource.h | 10 ++++ OpenAL32/alSource.c | 2 + alsoftrc.sample | 7 +++ 5 files changed, 126 insertions(+), 38 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 05da7130..15bb01be 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -218,6 +218,9 @@ static const ALchar alExtList[] = // Mixing Priority Level ALint RTPrioLevel; +// Resampler Quality +resampler_t DefaultResampler; + /////////////////////////////////////////////////////// @@ -265,6 +268,10 @@ static void alc_init(void) RTPrioLevel = GetConfigValueInt(NULL, "rt-prio", 0); + DefaultResampler = GetConfigValueInt(NULL, "resampler", LINEAR); + if(DefaultResampler >= RESAMPLER_MAX || DefaultResampler < POINT) + DefaultResampler = LINEAR; + devs = GetConfigValue(NULL, "drivers", ""); if(devs[0]) { diff --git a/Alc/ALu.c b/Alc/ALu.c index 4a53c6ec..f9a9ff2e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -860,6 +860,12 @@ static ALvoid CalcSourceParams(const ALCcontext *ALContext, ALsource *ALSource) } } +static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac) +{ + return val1; + (void)val2; + (void)frac; +} static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac) { return val1 + ((val2-val1)*(frac * (1.0f/(1<Resampler; State = ALSource->state; BuffersPlayed = ALSource->BuffersPlayed; DataPosInt = ALSource->position; @@ -1056,39 +1064,52 @@ another_source: if(Channels == 1) /* Mono */ { - while(BufferSize--) - { - for(i = 0;i < OUTPUTCHANNELS;i++) - DrySend[i] += dryGainStep[i]; - for(i = 0;i < MAX_SENDS;i++) - WetSend[i] += wetGainStep[i]; - - /* First order interpolator */ - value = lerp(Data[k], Data[k+1], DataPosFrac); - - /* Direct path final mix buffer and panning */ - outsamp = lpFilter4P(DryFilter, 0, value); - DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; - DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; - DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; - DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; - DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; - DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; - DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; - DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; - - /* Room path final mix buffer and panning */ - for(i = 0;i < MAX_SENDS;i++) - { - outsamp = lpFilter2P(WetFilter[i], 0, value); - WetBuffer[i][j] += outsamp*WetSend[i]; - } +#define DO_MIX(resampler) do { \ + while(BufferSize--) \ + { \ + for(i = 0;i < OUTPUTCHANNELS;i++) \ + DrySend[i] += dryGainStep[i]; \ + for(i = 0;i < MAX_SENDS;i++) \ + WetSend[i] += wetGainStep[i]; \ + \ + /* First order interpolator */ \ + value = (resampler)(Data[k], Data[k+1], DataPosFrac); \ + \ + /* Direct path final mix buffer and panning */ \ + outsamp = lpFilter4P(DryFilter, 0, value); \ + DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \ + DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \ + DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \ + DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \ + DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \ + DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \ + DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \ + DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \ + \ + /* Room path final mix buffer and panning */ \ + for(i = 0;i < MAX_SENDS;i++) \ + { \ + outsamp = lpFilter2P(WetFilter[i], 0, value); \ + WetBuffer[i][j] += outsamp*WetSend[i]; \ + } \ + \ + DataPosFrac += increment; \ + k += DataPosFrac>>FRACTIONBITS; \ + DataPosFrac &= FRACTIONMASK; \ + j++; \ + } \ +} while(0) - DataPosFrac += increment; - k += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - j++; + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; } +#undef DO_MIX } else if(Channels == 2) /* Stereo */ { @@ -1097,7 +1118,7 @@ another_source: }; const ALfloat scaler = aluSqrt(1.0f/Channels); -#define DO_MIX() do { \ +#define DO_MIX(resampler) do { \ while(BufferSize--) \ { \ for(i = 0;i < OUTPUTCHANNELS;i++) \ @@ -1107,7 +1128,8 @@ another_source: \ for(i = 0;i < Channels;i++) \ { \ - value = lerp(Data[k*Channels + i], Data[(k+1)*Channels + i], DataPosFrac); \ + value = (resampler)(Data[k*Channels + i], Data[(k+1)*Channels + i], \ + DataPosFrac); \ outsamp = lpFilter2P(DryFilter, chans[i]*2, value)*DrySend[chans[i]]; \ for(out = 0;out < OUTPUTCHANNELS;out++) \ DryBuffer[j][out] += outsamp*Matrix[chans[i]][out]; \ @@ -1125,7 +1147,15 @@ another_source: } \ } while(0) - DO_MIX(); + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; + } } else if(Channels == 4) /* Quad */ { @@ -1135,7 +1165,15 @@ another_source: }; const ALfloat scaler = aluSqrt(1.0f/Channels); - DO_MIX(); + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; + } } else if(Channels == 6) /* 5.1 */ { @@ -1146,7 +1184,15 @@ another_source: }; const ALfloat scaler = aluSqrt(1.0f/Channels); - DO_MIX(); + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; + } } else if(Channels == 7) /* 6.1 */ { @@ -1158,7 +1204,15 @@ another_source: }; const ALfloat scaler = aluSqrt(1.0f/Channels); - DO_MIX(); + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; + } } else if(Channels == 8) /* 7.1 */ { @@ -1170,7 +1224,15 @@ another_source: }; const ALfloat scaler = aluSqrt(1.0f/Channels); - DO_MIX(); + switch(Resampler) + { + case POINT: DO_MIX(point); + break; + case LINEAR: DO_MIX(lerp); + break; + case RESAMPLER_MAX: + break; + } #undef DO_MIX } else /* Unknown? */ diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 3889c85c..de746c61 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -22,6 +22,14 @@ extern "C" { #endif +typedef enum { + POINT = 0, + LINEAR, + + RESAMPLER_MAX +} resampler_t; +extern resampler_t DefaultResampler; + typedef struct ALbufferlistitem { struct ALbuffer *buffer; @@ -47,6 +55,8 @@ typedef struct ALsource ALboolean bLooping; ALenum DistanceModel; + resampler_t Resampler; + ALenum state; ALuint position; ALuint position_fraction; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 5ffc503c..5ad255d6 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1818,6 +1818,8 @@ static ALvoid InitSourceParams(ALsource *pSource) pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; + pSource->Resampler = DefaultResampler; + pSource->state = AL_INITIAL; pSource->lSourceType = AL_UNDETERMINED; diff --git a/alsoftrc.sample b/alsoftrc.sample index 22c60a3c..bda8dd45 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -60,6 +60,13 @@ # Sets the output frequency. #frequency = 44100 +## resampler: +# Selects the resampler used when mixing sources. Valid values are: +# 0 - None (nearest sample, no interpolation) +# 1 - Linear (extrapolates samples using a linear slope between samples) +# Specifying other values will result in using the default (linear). +#resampler = 1 + ## rt-prio: # Sets real-time priority for the mixing thread. Not all drivers may use this # (eg. PulseAudio) as they already control the priority of the mixing thread. -- 2.11.4.GIT