diff options
author | Chris Robinson <[email protected]> | 2010-09-24 18:29:49 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2010-09-24 18:29:49 -0700 |
commit | 2e70b82eaab5e8eef4723ab0d99fa3960e5519d7 (patch) | |
tree | b8e5ded8afaef6f096b34488638f0d084d566e6c | |
parent | 117ed52091a2a24d912c51a8a1c3a97cc5f4d4d5 (diff) |
Use separate mixing loops for the dry path and wet paths
This will increase CPU use a bit for sources that use auxiliary sends
(particularly with the cosine resampler), but it makes it more scalable when
adding more sends per source. Additionally, it will improve performance of
sources that don't use auxiliary sends.
The cosine resampler can probably be improved by using a lookup table instead
of calling cos() as there are 14 bits of fractional precision, so a 16384-
element float array would cover it all. This can also be reduced to a half or
quarter size if the precision loss is found to be acceptable.
-rw-r--r-- | Alc/mixer.c | 326 |
1 files changed, 234 insertions, 92 deletions
diff --git a/Alc/mixer.c b/Alc/mixer.c index ecb60aad..9572f7c3 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -96,10 +96,12 @@ static __inline ALfloat cos_lerp16(ALfloat val1, ALfloat val2, ALint frac) #define DO_MIX_MONO(S,sampler) do { \ + ALuint BufferIdx; \ + ALuint pos = DataPosInt; \ + ALuint frac = DataPosFrac; \ if(j == 0) \ { \ - value = sampler##S(Data.p##S[DataPosInt], Data.p##S[DataPosInt+1], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \ \ outsamp = lpFilter4PC(DryFilter, 0, value); \ ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \ @@ -110,18 +112,11 @@ static __inline ALfloat cos_lerp16(ALfloat val1, ALfloat val2, ALint frac) ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \ ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \ ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \ - \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter2PC(WetFilter[out], 0, value); \ - WetClickRemoval[out][0] -= outsamp*WetSend[out]; \ - } \ } \ - while(BufferSize--) \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ { \ /* First order interpolator */ \ - value = sampler##S(Data.p##S[DataPosInt], Data.p##S[DataPosInt+1], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \ \ /* Direct path final mix buffer and panning */ \ outsamp = lpFilter4P(DryFilter, 0, value); \ @@ -134,24 +129,25 @@ static __inline ALfloat cos_lerp16(ALfloat val1, ALfloat val2, ALint frac) DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \ DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \ \ - /* Room path final mix buffer and panning */ \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter2P(WetFilter[out], 0, value); \ - WetBuffer[out][j] += outsamp*WetSend[out]; \ - } \ - \ - DataPosFrac += increment; \ - DataPosInt += DataPosFrac>>FRACTIONBITS; \ - DataPosFrac &= FRACTIONMASK; \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ j++; \ } \ if(j == SamplesToDo) \ { \ - ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \ - ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \ - ((DataPosFrac-increment)&FRACTIONMASK)); \ - value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ + value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \ \ outsamp = lpFilter4PC(DryFilter, 0, value); \ PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \ @@ -162,151 +158,298 @@ static __inline ALfloat cos_lerp16(ALfloat val1, ALfloat val2, ALint frac) PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \ PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \ PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \ + } \ + for(out = 0;out < MAX_SENDS;out++) \ + { \ + if(!WetBuffer[out]) \ + continue; \ + \ + pos = DataPosInt; \ + frac = DataPosFrac; \ + j -= BufferSize; \ + \ + if(j == 0) \ + { \ + value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \ + \ + outsamp = lpFilter2PC(WetFilter[out], 0, value); \ + WetClickRemoval[out][0] -= outsamp*WetSend[out]; \ + } \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ + { \ + /* First order interpolator */ \ + value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \ + \ + /* Room path final mix buffer and panning */ \ + outsamp = lpFilter2P(WetFilter[out], 0, value); \ + WetBuffer[out][j] += outsamp*WetSend[out]; \ \ - for(out = 0;out < MAX_SENDS;out++) \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + j++; \ + } \ + if(j == SamplesToDo) \ { \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ + value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \ + \ outsamp = lpFilter2PC(WetFilter[out], 0, value); \ WetPendingClicks[out][0] += outsamp*WetSend[out]; \ } \ } \ + DataPosInt = pos; \ + DataPosFrac = frac; \ } while(0) #define DO_MIX_STEREO(S,sampler) do { \ const ALfloat scaler = 1.0f/Channels; \ + ALuint BufferIdx; \ + ALuint pos = DataPosInt; \ + ALuint frac = DataPosFrac; \ if(j == 0) \ { \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[DataPosInt*Channels + i], \ - Data.p##S[(DataPosInt+1)*Channels + i], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ \ outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \ ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \ ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \ ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \ - \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \ - WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \ - } \ } \ } \ - while(BufferSize--) \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ { \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[DataPosInt*Channels + i], \ - Data.p##S[(DataPosInt+1)*Channels + i], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ \ outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \ DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \ DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \ DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \ - \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ - WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \ - } \ } \ \ - DataPosFrac += increment; \ - DataPosInt += DataPosFrac>>FRACTIONBITS; \ - DataPosFrac &= FRACTIONMASK; \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ j++; \ } \ if(j == SamplesToDo) \ { \ - ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \ - ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \ - ((DataPosFrac-increment)&FRACTIONMASK)); \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[pos*Channels + i], \ - Data.p##S[(pos+1)*Channels + i], \ - frac); \ + value = sampler##S(Data.p##S[p*Channels + i], \ + Data.p##S[(p+1)*Channels + i], f); \ \ outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \ PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \ PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \ PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \ + } \ + } \ + for(out = 0;out < MAX_SENDS;out++) \ + { \ + if(!WetBuffer[out]) \ + continue; \ + \ + pos = DataPosInt; \ + frac = DataPosFrac; \ + j -= BufferSize; \ \ - for(out = 0;out < MAX_SENDS;out++) \ + if(j == 0) \ + { \ + for(i = 0;i < Channels;i++) \ { \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ + \ + outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \ + WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \ + } \ + } \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ + { \ + for(i = 0;i < Channels;i++) \ + { \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ + \ + outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ + WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \ + } \ + \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + j++; \ + } \ + if(j == SamplesToDo) \ + { \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ + for(i = 0;i < Channels;i++) \ + { \ + value = sampler##S(Data.p##S[p*Channels + i], \ + Data.p##S[(p+1)*Channels + i], f); \ + \ outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \ WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \ } \ } \ } \ + DataPosInt = pos; \ + DataPosFrac = frac; \ } while(0) #define DO_MIX_MC(S,sampler) do { \ const ALfloat scaler = 1.0f/Channels; \ + ALuint BufferIdx; \ + ALuint pos = DataPosInt; \ + ALuint frac = DataPosFrac; \ if(j == 0) \ { \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[DataPosInt*Channels + i], \ - Data.p##S[(DataPosInt+1)*Channels + i], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ \ outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \ ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \ - \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\ - WetClickRemoval[out][0] -= outsamp*WetSend[out]; \ - } \ } \ } \ - while(BufferSize--) \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ { \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[DataPosInt*Channels + i], \ - Data.p##S[(DataPosInt+1)*Channels + i], \ - DataPosFrac); \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ \ outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \ DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \ - \ - for(out = 0;out < MAX_SENDS;out++) \ - { \ - outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ - WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \ - } \ } \ \ - DataPosFrac += increment; \ - DataPosInt += DataPosFrac>>FRACTIONBITS; \ - DataPosFrac &= FRACTIONMASK; \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ j++; \ } \ if(j == SamplesToDo) \ { \ - ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \ - ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \ - ((DataPosFrac-increment)&FRACTIONMASK)); \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ for(i = 0;i < Channels;i++) \ { \ - value = sampler##S(Data.p##S[pos*Channels + i], \ - Data.p##S[(pos+1)*Channels + i], \ - frac); \ + value = sampler##S(Data.p##S[p*Channels + i], \ + Data.p##S[(p+1)*Channels + i], f); \ \ outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \ PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \ + } \ + } \ + for(out = 0;out < MAX_SENDS;out++) \ + { \ + if(!WetBuffer[out]) \ + continue; \ + \ + pos = DataPosInt; \ + frac = DataPosFrac; \ + j -= BufferSize; \ + \ + if(j == 0) \ + { \ + for(i = 0;i < Channels;i++) \ + { \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ + \ + outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \ + WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \ + } \ + } \ + for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ + { \ + for(i = 0;i < Channels;i++) \ + { \ + value = sampler##S(Data.p##S[pos*Channels + i], \ + Data.p##S[(pos+1)*Channels + i], frac); \ \ - for(out = 0;out < MAX_SENDS;out++) \ + outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ + WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \ + } \ + \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + j++; \ + } \ + if(j == SamplesToDo) \ + { \ + ALuint p = pos; \ + ALuint f = frac; \ + if(p >= DataSize) \ + { \ + ALuint64 pos64 = pos; \ + pos64 <<= FRACTIONBITS; \ + pos64 += frac; \ + pos64 -= increment; \ + p = pos64>>FRACTIONBITS; \ + f = pos64&FRACTIONMASK; \ + } \ + for(i = 0;i < Channels;i++) \ { \ - outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\ - WetPendingClicks[out][0] += outsamp*WetSend[out]; \ + value = sampler##S(Data.p##S[p*Channels + i], \ + Data.p##S[(p+1)*Channels + i], f); \ + \ + outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \ + WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \ } \ } \ } \ + DataPosInt = pos; \ + DataPosFrac = frac; \ } while(0) @@ -393,8 +536,6 @@ static void MixSource(ALsource *Source, ALCcontext *Context, ALfloat (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo, ALfloat *ClickRemoval, ALfloat *PendingClicks) { - static ALfloat DummyBuffer[BUFFERSIZE]; - static ALfloat DummyClickRemoval[OUTPUTCHANNELS]; ALfloat *WetBuffer[MAX_SENDS]; ALfloat DrySend[OUTPUTCHANNELS]; ALfloat *WetClickRemoval[MAX_SENDS]; @@ -436,7 +577,8 @@ static void MixSource(ALsource *Source, ALCcontext *Context, for(i = 0;i < MAX_SENDS;i++) { WetFilter[i] = &Source->Params.Send[i].iirFilter; - if(Source->Send[i].Slot) + if(Source->Send[i].Slot && + Source->Send[i].Slot->effect.type != AL_EFFECT_NULL) { WetBuffer[i] = Source->Send[i].Slot->WetBuffer; WetClickRemoval[i] = Source->Send[i].Slot->ClickRemoval; @@ -444,9 +586,9 @@ static void MixSource(ALsource *Source, ALCcontext *Context, } else { - WetBuffer[i] = DummyBuffer; - WetClickRemoval[i] = DummyClickRemoval; - WetPendingClicks[i] = DummyClickRemoval; + WetBuffer[i] = NULL; + WetClickRemoval[i] = NULL; + WetPendingClicks[i] = NULL; } } |