Use span<FloatBufferLine> for MixSamples

This commit is contained in:
Chris Robinson 2019-05-29 21:58:37 -07:00
parent 8af7b4c6e0
commit 893ffe9a84
15 changed files with 91 additions and 96 deletions

View File

@ -136,11 +136,9 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R
const ALfloat peak_gain = mPeakGain; const ALfloat peak_gain = mPeakGain;
const ALfloat freq_min = mFreqMinNorm; const ALfloat freq_min = mFreqMinNorm;
const ALfloat bandwidth = mBandwidthNorm; const ALfloat bandwidth = mBandwidthNorm;
ALfloat env_delay;
ALsizei c, i;
env_delay = mEnvDelay; ALfloat env_delay{mEnvDelay};
for(i = 0;i < samplesToDo;i++) for(ALsizei i{0};i < samplesToDo;i++)
{ {
ALfloat w0, sample, a; ALfloat w0, sample, a;
@ -158,8 +156,9 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R
} }
mEnvDelay = env_delay; mEnvDelay = env_delay;
const al::span<FloatBufferLine> output{samplesOut, samplesOut+numOutput};
ASSUME(numInput > 0); ASSUME(numInput > 0);
for(c = 0;c < numInput;++c) for(ALsizei c{0};c < numInput;++c)
{ {
/* This effectively inlines BiquadFilter_setParams for a peaking /* This effectively inlines BiquadFilter_setParams for a peaking
* filter and BiquadFilter_processC. The alpha and cosine components * filter and BiquadFilter_processC. The alpha and cosine components
@ -167,10 +166,10 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R
* envelope. Because the filter changes for each sample, the * envelope. Because the filter changes for each sample, the
* coefficients are transient and don't need to be held. * coefficients are transient and don't need to be held.
*/ */
ALfloat z1 = mChans[c].Filter.z1; ALfloat z1{mChans[c].Filter.z1};
ALfloat z2 = mChans[c].Filter.z2; ALfloat z2{mChans[c].Filter.z2};
for(i = 0;i < samplesToDo;i++) for(ALsizei i{0};i < samplesToDo;i++)
{ {
const ALfloat alpha = mEnv[i].alpha; const ALfloat alpha = mEnv[i].alpha;
const ALfloat cos_w0 = mEnv[i].cos_w0; const ALfloat cos_w0 = mEnv[i].cos_w0;
@ -194,8 +193,8 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R
mChans[c].Filter.z2 = z2; mChans[c].Filter.z2 = z2;
/* Now, mix the processed sound data to the output. */ /* Now, mix the processed sound data to the output. */
MixSamples(mBufferOut, numOutput, &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), MixSamples(mBufferOut, output, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo,
mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0, samplesToDo); 0, samplesToDo);
} }
} }

View File

@ -205,10 +205,9 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST
const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS};
ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; ALfloat *RESTRICT delaybuf{mSampleBuffer.data()};
ALsizei offset{mOffset}; ALsizei offset{mOffset};
ALsizei i, c;
ALsizei base;
for(base = 0;base < samplesToDo;) const al::span<FloatBufferLine> output{samplesOut, samplesOut+numOutput};
for(ALsizei base{0};base < samplesToDo;)
{ {
const ALsizei todo = mini(256, samplesToDo-base); const ALsizei todo = mini(256, samplesToDo-base);
ALint moddelays[2][256]; ALint moddelays[2][256];
@ -230,7 +229,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST
} }
mLfoOffset = (mLfoOffset+todo) % mLfoRange; mLfoOffset = (mLfoOffset+todo) % mLfoRange;
for(i = 0;i < todo;i++) for(ALsizei i{0};i < todo;i++)
{ {
// Feed the buffer's input first (necessary for delays < 1). // Feed the buffer's input first (necessary for delays < 1).
delaybuf[offset&bufmask] = samplesIn[0][base+i]; delaybuf[offset&bufmask] = samplesIn[0][base+i];
@ -254,10 +253,9 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST
offset++; offset++;
} }
for(c = 0;c < 2;c++) for(ALsizei c{0};c < 2;c++)
MixSamples(temps[c], numOutput, MixSamples(temps[c], output, mGains[c].Current, mGains[c].Target, samplesToDo-base,
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mGains[c].Current, base, todo);
mGains[c].Target, samplesToDo-base, base, todo);
base += todo; base += todo;
} }

View File

@ -92,9 +92,8 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo
void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput)
{ {
MixSamples(samplesIn[0].data(), numOutput, MixSamples(samplesIn[0].data(), {samplesOut, samplesOut+numOutput}, mCurrentGains,
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mCurrentGains, mTargetGains, mTargetGains, samplesToDo, 0, samplesToDo);
samplesToDo, 0, samplesToDo);
} }

View File

@ -157,10 +157,10 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI
mFilter.setComponents(z1, z2); mFilter.setComponents(z1, z2);
mOffset = offset; mOffset = offset;
const al::span<FloatBufferLine> output{samplesOut, samplesOut+numOutput};
for(ALsizei c{0};c < 2;c++) for(ALsizei c{0};c < 2;c++)
MixSamples(mTempBuffer[c], numOutput, MixSamples(mTempBuffer[c], output, mGains[c].Current, mGains[c].Target, samplesToDo, 0,
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mGains[c].Current, samplesToDo);
mGains[c].Target, samplesToDo, 0, samplesToDo);
} }

View File

@ -160,6 +160,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot,
void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput)
{ {
const al::span<FloatBufferLine> output{samplesOut, samplesOut+numOutput};
ASSUME(numInput > 0); ASSUME(numInput > 0);
for(ALsizei c{0};c < numInput;c++) for(ALsizei c{0};c < numInput;c++)
{ {
@ -168,9 +169,8 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R
mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo);
mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo);
MixSamples(mSampleBuffer, numOutput, MixSamples(mSampleBuffer, output, mChans[c].CurrentGains, mChans[c].TargetGains,
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mChans[c].CurrentGains, samplesToDo, 0, samplesToDo);
mChans[c].TargetGains, samplesToDo, 0, samplesToDo);
} }
} }

View File

@ -198,8 +198,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE
} }
/* Now, mix the processed sound data to the output. */ /* Now, mix the processed sound data to the output. */
MixSamples(BufferOut, numOutput, &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), MixSamples(BufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains,
mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); maxi(samplesToDo, 512), 0, samplesToDo);
} }

View File

@ -143,10 +143,10 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot,
void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput)
{ {
const ALsizei step = mStep; const ALsizei step{mStep};
ALsizei base;
for(base = 0;base < samplesToDo;) const al::span<FloatBufferLine> output{samplesOut, samplesOut+numOutput};
for(ALsizei base{0};base < samplesToDo;)
{ {
alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES];
ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base);
@ -165,8 +165,8 @@ void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *R
for(i = 0;i < td;i++) for(i = 0;i < td;i++)
temps[i] *= modsamples[i]; temps[i] *= modsamples[i];
MixSamples(temps, numOutput, &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), MixSamples(temps, output, mChans[c].CurrentGains, mChans[c].TargetGains,
mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo-base, base, td); samplesToDo-base, base, td);
} }
base += td; base += td;

View File

@ -321,8 +321,8 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE
mCount = count; mCount = count;
/* Now, mix the processed sound data to the output. */ /* Now, mix the processed sound data to the output. */
MixSamples(bufferOut, numOutput, &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), MixSamples(bufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains,
mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); maxi(samplesToDo, 512), 0, samplesToDo);
} }

View File

@ -375,7 +375,7 @@ struct ReverbState final : public EffectState {
alignas(16) FloatBufferLine mEarlyBuffer[NUM_LINES]{}; alignas(16) FloatBufferLine mEarlyBuffer[NUM_LINES]{};
alignas(16) FloatBufferLine mLateBuffer[NUM_LINES]{}; alignas(16) FloatBufferLine mLateBuffer[NUM_LINES]{};
using MixOutT = void (ReverbState::*)(const ALsizei numOutput, FloatBufferLine *samplesOut, using MixOutT = void (ReverbState::*)(const al::span<FloatBufferLine> samplesOut,
const ALsizei todo); const ALsizei todo);
MixOutT mMixOut{&ReverbState::MixOutPlain}; MixOutT mMixOut{&ReverbState::MixOutPlain};
@ -383,7 +383,7 @@ struct ReverbState final : public EffectState {
std::array<std::array<BandSplitter,NUM_LINES>,2> mAmbiSplitter; std::array<std::array<BandSplitter,NUM_LINES>,2> mAmbiSplitter;
void MixOutPlain(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) void MixOutPlain(const al::span<FloatBufferLine> samplesOut, const ALsizei todo)
{ {
ASSUME(todo > 0); ASSUME(todo > 0);
@ -392,8 +392,7 @@ struct ReverbState final : public EffectState {
{ {
std::fill_n(mTempSamples[0].begin(), todo, 0.0f); std::fill_n(mTempSamples[0].begin(), todo, 0.0f);
MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo);
MixSamples(mTempSamples[0].data(), numOutput, MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c],
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mEarly.CurrentGain[c],
mEarly.PanGain[c], todo, 0, todo); mEarly.PanGain[c], todo, 0, todo);
} }
@ -401,13 +400,12 @@ struct ReverbState final : public EffectState {
{ {
std::fill_n(mTempSamples[0].begin(), todo, 0.0f); std::fill_n(mTempSamples[0].begin(), todo, 0.0f);
MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo);
MixSamples(mTempSamples[0].data(), numOutput, MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c],
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mLate.CurrentGain[c], todo, 0, todo);
mLate.PanGain[c], todo, 0, todo);
} }
} }
void MixOutAmbiUp(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) void MixOutAmbiUp(const al::span<FloatBufferLine> samplesOut, const ALsizei todo)
{ {
ASSUME(todo > 0); ASSUME(todo > 0);
@ -422,8 +420,7 @@ struct ReverbState final : public EffectState {
const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo);
MixSamples(mTempSamples[0].data(), numOutput, MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c],
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mEarly.CurrentGain[c],
mEarly.PanGain[c], todo, 0, todo); mEarly.PanGain[c], todo, 0, todo);
} }
@ -435,9 +432,8 @@ struct ReverbState final : public EffectState {
const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]};
mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo);
MixSamples(mTempSamples[0].data(), numOutput, MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c],
&reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(samplesOut[0]), mLate.CurrentGain[c], todo, 0, todo);
mLate.PanGain[c], todo, 0, todo);
} }
} }
@ -1530,7 +1526,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST
mFadeCount = fadeCount; mFadeCount = fadeCount;
/* Finally, mix early reflections and late reverb. */ /* Finally, mix early reflections and late reverb. */
(this->*mMixOut)(numOutput, samplesOut, samplesToDo); (this->*mMixOut)({samplesOut, samplesOut+numOutput}, samplesToDo);
} }

View File

@ -32,7 +32,7 @@ template<typename TypeTag, typename InstTag>
const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen);
template<typename InstTag> template<typename InstTag>
void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); void Mix_(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize);
template<typename InstTag> template<typename InstTag>
void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span<const FloatBufferLine> InSamples, const ALsizei InPos, const ALsizei BufferSize); void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span<const FloatBufferLine> InSamples, const ALsizei InPos, const ALsizei BufferSize);

View File

@ -144,21 +144,20 @@ void MixDirectHrtf_<CTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
template<> template<>
void Mix_<CTag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], void Mix_<CTag>(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer,
ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos,
const ALsizei BufferSize) const ALsizei BufferSize)
{ {
ASSUME(OutChans > 0);
ASSUME(BufferSize > 0); ASSUME(BufferSize > 0);
const ALfloat delta{(Counter > 0) ? 1.0f / static_cast<ALfloat>(Counter) : 0.0f}; const ALfloat delta{(Counter > 0) ? 1.0f / static_cast<ALfloat>(Counter) : 0.0f};
for(ALsizei c{0};c < OutChans;c++) for(FloatBufferLine &output : OutBuffer)
{ {
ALfloat *RESTRICT dst{&OutBuffer[c][OutPos]}; ALfloat *RESTRICT dst{output.data()+OutPos};
ALsizei pos{0}; ALfloat gain{*CurrentGains};
ALfloat gain{CurrentGains[c]}; const ALfloat diff{*TargetGains - gain};
const ALfloat diff{TargetGains[c] - gain}; ALsizei pos{0};
if(std::fabs(diff) > std::numeric_limits<float>::epsilon()) if(std::fabs(diff) > std::numeric_limits<float>::epsilon())
{ {
ALsizei minsize{mini(BufferSize, Counter)}; ALsizei minsize{mini(BufferSize, Counter)};
@ -170,11 +169,13 @@ void Mix_<CTag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer
step_count += 1.0f; step_count += 1.0f;
} }
if(pos == Counter) if(pos == Counter)
gain = TargetGains[c]; gain = *TargetGains;
else else
gain += step*step_count; gain += step*step_count;
CurrentGains[c] = gain; *CurrentGains = gain;
} }
++CurrentGains;
++TargetGains;
if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD))
continue; continue;

View File

@ -190,21 +190,20 @@ void MixDirectHrtf_<NEONTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut
template<> template<>
void Mix_<NEONTag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], void Mix_<NEONTag>(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer,
ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos,
const ALsizei BufferSize) const ALsizei BufferSize)
{ {
ASSUME(OutChans > 0);
ASSUME(BufferSize > 0); ASSUME(BufferSize > 0);
const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f}; const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f};
for(ALsizei c{0};c < OutChans;c++) for(FloatBufferLine &output : OutBuffer)
{ {
ALfloat *RESTRICT dst{al::assume_aligned<16>(&OutBuffer[c][OutPos])}; ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)};
ALsizei pos{0}; ALfloat gain{*CurrentGains};
ALfloat gain{CurrentGains[c]}; const ALfloat diff{*TargetGains - gain};
const ALfloat diff{TargetGains[c] - gain};
ALsizei pos{0};
if(std::fabs(diff) > std::numeric_limits<float>::epsilon()) if(std::fabs(diff) > std::numeric_limits<float>::epsilon())
{ {
ALsizei minsize{mini(BufferSize, Counter)}; ALsizei minsize{mini(BufferSize, Counter)};
@ -245,16 +244,18 @@ void Mix_<NEONTag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuf
step_count += 1.0f; step_count += 1.0f;
} }
if(pos == Counter) if(pos == Counter)
gain = TargetGains[c]; gain = *TargetGains;
else else
gain += step*step_count; gain += step*step_count;
CurrentGains[c] = gain; *CurrentGains = gain;
/* Mix until pos is aligned with 4 or the mix is done. */ /* Mix until pos is aligned with 4 or the mix is done. */
minsize = mini(BufferSize, (pos+3)&~3); minsize = mini(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++) for(;pos < minsize;pos++)
dst[pos] += data[pos]*gain; dst[pos] += data[pos]*gain;
} }
++CurrentGains;
++TargetGains;
if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD))
continue; continue;

View File

@ -147,21 +147,20 @@ void MixDirectHrtf_<SSETag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
template<> template<>
void Mix_<SSETag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], void Mix_<SSETag>(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer,
ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos,
const ALsizei BufferSize) const ALsizei BufferSize)
{ {
ASSUME(OutChans > 0);
ASSUME(BufferSize > 0); ASSUME(BufferSize > 0);
const ALfloat delta{(Counter > 0) ? 1.0f / static_cast<ALfloat>(Counter) : 0.0f}; const ALfloat delta{(Counter > 0) ? 1.0f / static_cast<ALfloat>(Counter) : 0.0f};
for(ALsizei c{0};c < OutChans;c++) for(FloatBufferLine &output : OutBuffer)
{ {
ALfloat *RESTRICT dst{al::assume_aligned<16>(&OutBuffer[c][OutPos])}; ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)};
ALsizei pos{0}; ALfloat gain{*CurrentGains};
ALfloat gain{CurrentGains[c]}; const ALfloat diff{*TargetGains - gain};
const ALfloat diff{TargetGains[c] - gain};
ALsizei pos{0};
if(std::fabs(diff) > std::numeric_limits<float>::epsilon()) if(std::fabs(diff) > std::numeric_limits<float>::epsilon())
{ {
ALsizei minsize{mini(BufferSize, Counter)}; ALsizei minsize{mini(BufferSize, Counter)};
@ -199,16 +198,18 @@ void Mix_<SSETag>(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuff
step_count += 1.0f; step_count += 1.0f;
} }
if(pos == Counter) if(pos == Counter)
gain = TargetGains[c]; gain = *TargetGains;
else else
gain += step*step_count; gain += step*step_count;
CurrentGains[c] = gain; *CurrentGains = gain;
/* Mix until pos is aligned with 4 or the mix is done. */ /* Mix until pos is aligned with 4 or the mix is done. */
minsize = mini(BufferSize, (pos+3)&~3); minsize = mini(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++) for(;pos < minsize;pos++)
dst[pos] += data[pos]*gain; dst[pos] += data[pos]*gain;
} }
++CurrentGains;
++TargetGains;
if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD))
continue; continue;

View File

@ -800,23 +800,23 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
SilentTarget : parms.Gains.Target}; SilentTarget : parms.Gains.Target};
MixSamples(samples, voice->mDirect.ChannelsPerOrder[0], const auto outcount = static_cast<size_t>(voice->mDirect.ChannelsPerOrder[0]);
&reinterpret_cast<float(&)[BUFFERSIZE]>(voice->mDirect.Buffer[0]), MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current,
parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); TargetGains, Counter, OutPos, DstBufferSize);
ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData;
ALsizei chanoffset{voice->mDirect.ChannelsPerOrder[0]}; size_t chanoffset{outcount};
using FilterProc = void (NfcFilter::*)(float*,const float*,int); using FilterProc = void (NfcFilter::*)(float*,const float*,int);
auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](FilterProc process, ALsizei order) -> void auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](FilterProc process, ALsizei order) -> void
{ {
if(voice->mDirect.ChannelsPerOrder[order] < 1) const auto outcount = static_cast<size_t>(
return; voice->mDirect.ChannelsPerOrder[order]);
if(outcount < 1) return;
(parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize);
MixSamples(nfcsamples, voice->mDirect.ChannelsPerOrder[order], MixSamples(nfcsamples, {voice->mDirect.Buffer+chanoffset, outcount},
&reinterpret_cast<float(&)[BUFFERSIZE]>(voice->mDirect.Buffer[chanoffset]),
parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter,
OutPos, DstBufferSize); OutPos, DstBufferSize);
chanoffset += voice->mDirect.ChannelsPerOrder[order]; chanoffset += outcount;
}; };
apply_nfc(&NfcFilter::process1, 1); apply_nfc(&NfcFilter::process1, 1);
apply_nfc(&NfcFilter::process2, 2); apply_nfc(&NfcFilter::process2, 2);
@ -826,9 +826,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
{ {
const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ?
SilentTarget : parms.Gains.Target}; SilentTarget : parms.Gains.Target};
MixSamples(samples, voice->mDirect.Channels, const auto outcount = static_cast<size_t>(voice->mDirect.Channels);
&reinterpret_cast<float(&)[BUFFERSIZE]>(voice->mDirect.Buffer[0]), MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current,
parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); TargetGains, Counter, OutPos, DstBufferSize);
} }
} }
@ -844,9 +844,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget :
parms.Gains.Target}; parms.Gains.Target};
MixSamples(samples, send.Channels, const auto outcount = static_cast<size_t>(send.Channels);
&reinterpret_cast<float(&)[BUFFERSIZE]>(send.Buffer[0]), parms.Gains.Current, MixSamples(samples, {send.Buffer, outcount}, parms.Gains.Current, TargetGains,
TargetGains, Counter, OutPos, DstBufferSize); Counter, OutPos, DstBufferSize);
}; };
std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send); std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send);
} }

View File

@ -293,9 +293,9 @@ struct ALvoice {
void DeinitVoice(ALvoice *voice) noexcept; void DeinitVoice(ALvoice *voice) noexcept;
using MixerFunc = void(*)(const ALfloat *data, const ALsizei OutChans, using MixerFunc = void(*)(const ALfloat *data, const al::span<FloatBufferLine> OutBuffer,
ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos,
const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); const ALsizei BufferSize);
using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains,
const al::span<const FloatBufferLine> InSamples, const ALsizei InPos, const al::span<const FloatBufferLine> InSamples, const ALsizei InPos,
const ALsizei BufferSize); const ALsizei BufferSize);