Restructure voice data members
This should improve access patters by packing each buffer channel's data together, which is more inline with its use.
This commit is contained in:
+23
-19
@@ -2161,12 +2161,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
if(device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
/* Reinitialize the NFC filters for new parameters. */
|
||||
ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
|
||||
(device->AvgSpeakerDist * device->Frequency);
|
||||
std::for_each(voice->mDirect.Params, voice->mDirect.Params+voice->mNumChannels,
|
||||
[w1](DirectParams ¶ms) noexcept -> void
|
||||
{ params.NFCtrlFilter.init(w1); }
|
||||
);
|
||||
const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC /
|
||||
(device->AvgSpeakerDist * device->Frequency)};
|
||||
auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void
|
||||
{ chandata.mDryParams.NFCtrlFilter.init(w1); };
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
||||
init_nfc);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2591,7 +2591,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
|
||||
* property set (including the dynamically-sized Send[] array) in one
|
||||
* chunk.
|
||||
*/
|
||||
const size_t sizeof_voice{RoundUp(ALvoice::Sizeof(num_sends), 16)};
|
||||
const size_t sizeof_voice{RoundUp(sizeof(ALvoice), 16)};
|
||||
const size_t size{sizeof(ALvoice*) + sizeof_voice};
|
||||
|
||||
auto voices = static_cast<ALvoice**>(al_calloc(16, RoundUp(size*num_voices, 16)));
|
||||
@@ -2605,9 +2605,9 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
|
||||
const ALsizei s_count = mini(old_sends, num_sends);
|
||||
|
||||
/* Copy the old voice data to the new storage. */
|
||||
auto copy_voice = [&voice,num_sends,sizeof_voice,s_count](ALvoice *old_voice) -> ALvoice*
|
||||
auto copy_voice = [&voice,s_count](ALvoice *old_voice) -> ALvoice*
|
||||
{
|
||||
voice = new (voice) ALvoice{static_cast<size_t>(num_sends)};
|
||||
voice = new (voice) ALvoice{};
|
||||
|
||||
/* Make sure the old voice's Update (if any) is cleared so it
|
||||
* doesn't get deleted on deinit.
|
||||
@@ -2647,16 +2647,21 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
|
||||
|
||||
voice->mFlags = old_voice->mFlags;
|
||||
|
||||
std::copy(old_voice->mResampleData.begin(), old_voice->mResampleData.end(),
|
||||
voice->mResampleData.end());
|
||||
|
||||
voice->mDirect = old_voice->mDirect;
|
||||
std::copy_n(old_voice->mSend.begin(), s_count, voice->mSend.begin());
|
||||
voice->mSend = old_voice->mSend;
|
||||
voice->mChans = old_voice->mChans;
|
||||
|
||||
/* Clear old send data/params. */
|
||||
std::fill(voice->mSend.begin()+s_count, voice->mSend.end(), ALvoice::SendData{});
|
||||
auto clear_chan_sends = [s_count](ALvoice::ChannelData &chandata) -> void
|
||||
{
|
||||
std::fill(chandata.mWetParams.begin()+s_count, chandata.mWetParams.end(),
|
||||
SendParams{});
|
||||
};
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.end(), clear_chan_sends);
|
||||
|
||||
/* Set this voice's reference. */
|
||||
ALvoice *ret = voice;
|
||||
/* Increment pointer to the next storage space. */
|
||||
voice = reinterpret_cast<ALvoice*>(reinterpret_cast<char*>(voice) + sizeof_voice);
|
||||
ALvoice *ret{voice++};
|
||||
return ret;
|
||||
};
|
||||
viter = std::transform(context->Voices, context->Voices+v_count, viter, copy_voice);
|
||||
@@ -2666,10 +2671,9 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
|
||||
std::for_each(context->Voices, voices_end, DeinitVoice);
|
||||
}
|
||||
/* Finish setting the voices and references. */
|
||||
auto init_voice = [&voice,num_sends,sizeof_voice]() -> ALvoice*
|
||||
auto init_voice = [&voice]() -> ALvoice*
|
||||
{
|
||||
ALvoice *ret = new (voice) ALvoice{static_cast<size_t>(num_sends)};
|
||||
voice = reinterpret_cast<ALvoice*>(reinterpret_cast<char*>(voice) + sizeof_voice);
|
||||
ALvoice *ret{new (voice++) ALvoice{}};
|
||||
return ret;
|
||||
};
|
||||
std::generate(viter, voices+num_voices, init_voice);
|
||||
|
||||
+74
-73
@@ -554,22 +554,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
}
|
||||
ASSUME(num_channels > 0);
|
||||
|
||||
std::for_each(std::begin(voice->mDirect.Params),
|
||||
std::begin(voice->mDirect.Params)+num_channels,
|
||||
[](DirectParams ¶ms) -> void
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels,
|
||||
[NumSends](ALvoice::ChannelData &chandata) -> void
|
||||
{
|
||||
params.Hrtf.Target = HrtfParams{};
|
||||
ClearArray(params.Gains.Target);
|
||||
}
|
||||
);
|
||||
std::for_each(voice->mSend.begin(), voice->mSend.end(),
|
||||
[num_channels](ALvoice::SendData &send) -> void
|
||||
{
|
||||
std::for_each(std::begin(send.Params), std::begin(send.Params)+num_channels,
|
||||
[](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }
|
||||
);
|
||||
}
|
||||
);
|
||||
chandata.mDryParams.Hrtf.Target = HrtfParams{};
|
||||
ClearArray(chandata.mDryParams.Gains.Target);
|
||||
std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends,
|
||||
[](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); });
|
||||
});
|
||||
|
||||
voice->mFlags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC);
|
||||
if(isbformat)
|
||||
@@ -592,7 +584,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)};
|
||||
|
||||
/* Only need to adjust the first channel of a B-Format source. */
|
||||
voice->mDirect.Params[0].NFCtrlFilter.adjust(w0);
|
||||
voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0);
|
||||
|
||||
std::copy(std::begin(Device->NumChannelsPerOrder),
|
||||
std::end(Device->NumChannelsPerOrder),
|
||||
@@ -622,12 +614,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
/* NOTE: W needs to be scaled due to FuMa normalization. */
|
||||
const ALfloat &scale0 = AmbiScale::FromFuMa[0];
|
||||
ComputePanGains(&Device->Dry, coeffs, DryGain*scale0,
|
||||
voice->mDirect.Params[0].Gains.Target);
|
||||
voice->mChans[0].mDryParams.Gains.Target);
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i]*scale0,
|
||||
voice->mSend[i].Params[0].Gains.Target);
|
||||
voice->mChans[0].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -638,7 +630,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
* is what we want for FOA input. The first channel may have
|
||||
* been previously re-adjusted if panned, so reset it.
|
||||
*/
|
||||
voice->mDirect.Params[0].NFCtrlFilter.adjust(0.0f);
|
||||
voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f);
|
||||
|
||||
voice->mDirect.ChannelsPerOrder[0] = 1;
|
||||
voice->mDirect.ChannelsPerOrder[1] = minz(voice->mDirect.Buffer.size()-1, 3);
|
||||
@@ -681,14 +673,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
};
|
||||
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
ComputePanGains(&Device->Dry, matrix[c], DryGain,
|
||||
voice->mDirect.Params[c].Gains.Target);
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
ComputePanGains(&Device->Dry, matrix[c], DryGain,
|
||||
voice->mChans[c].mDryParams.Gains.Target);
|
||||
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, matrix[c], WetGain[i],
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,7 +697,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
{
|
||||
int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
|
||||
if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain;
|
||||
if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain;
|
||||
}
|
||||
|
||||
/* Auxiliary sends still use normal channel panning since they mix to
|
||||
@@ -718,7 +712,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i],
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -739,16 +733,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
* source direction.
|
||||
*/
|
||||
GetHrtfCoeffs(Device->mHrtf, ev, az, Distance, Spread,
|
||||
voice->mDirect.Params[0].Hrtf.Target.Coeffs,
|
||||
voice->mDirect.Params[0].Hrtf.Target.Delay);
|
||||
voice->mDirect.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain;
|
||||
voice->mChans[0].mDryParams.Hrtf.Target.Coeffs,
|
||||
voice->mChans[0].mDryParams.Hrtf.Target.Delay);
|
||||
voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain * downmix_gain;
|
||||
|
||||
/* Remaining channels use the same results as the first. */
|
||||
for(ALsizei c{1};c < num_channels;c++)
|
||||
{
|
||||
/* Skip LFE */
|
||||
if(chans[c].channel != LFE)
|
||||
voice->mDirect.Params[c].Hrtf.Target = voice->mDirect.Params[0].Hrtf.Target;
|
||||
if(chans[c].channel == LFE) continue;
|
||||
voice->mChans[c].mDryParams.Hrtf.Target = voice->mChans[0].mDryParams.Hrtf.Target;
|
||||
}
|
||||
|
||||
/* Calculate the directional coefficients once, which apply to all
|
||||
@@ -757,16 +751,17 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
ALfloat coeffs[MAX_AMBI_CHANNELS];
|
||||
CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs);
|
||||
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
{
|
||||
/* Skip LFE */
|
||||
if(chans[c].channel != LFE)
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain,
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
}
|
||||
/* Skip LFE */
|
||||
if(chans[c].channel == LFE)
|
||||
continue;
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain,
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -786,9 +781,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
*/
|
||||
GetHrtfCoeffs(Device->mHrtf, chans[c].elevation, chans[c].angle,
|
||||
std::numeric_limits<float>::infinity(), Spread,
|
||||
voice->mDirect.Params[c].Hrtf.Target.Coeffs,
|
||||
voice->mDirect.Params[c].Hrtf.Target.Delay);
|
||||
voice->mDirect.Params[c].Hrtf.Target.Gain = DryGain;
|
||||
voice->mChans[c].mDryParams.Hrtf.Target.Coeffs,
|
||||
voice->mChans[c].mDryParams.Hrtf.Target.Delay);
|
||||
voice->mChans[c].mDryParams.Hrtf.Target.Gain = DryGain;
|
||||
|
||||
/* Normal panning for auxiliary sends. */
|
||||
ALfloat coeffs[MAX_AMBI_CHANNELS];
|
||||
@@ -798,7 +793,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i],
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -822,7 +817,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
|
||||
/* Adjust NFC filters. */
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
voice->mDirect.Params[c].NFCtrlFilter.adjust(w0);
|
||||
voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0);
|
||||
|
||||
std::copy(std::begin(Device->NumChannelsPerOrder),
|
||||
std::end(Device->NumChannelsPerOrder),
|
||||
@@ -851,25 +846,26 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
if(Device->Dry.Buffer == Device->RealOut.Buffer)
|
||||
{
|
||||
int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel);
|
||||
if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain;
|
||||
if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain,
|
||||
voice->mDirect.Params[c].Gains.Target);
|
||||
voice->mChans[c].mDryParams.Gains.Target);
|
||||
}
|
||||
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
{
|
||||
/* Skip LFE */
|
||||
if(chans[c].channel != LFE)
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain,
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
}
|
||||
/* Skip LFE */
|
||||
if(chans[c].channel == LFE)
|
||||
continue;
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain,
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -884,7 +880,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * Frequency)};
|
||||
|
||||
for(ALsizei c{0};c < num_channels;c++)
|
||||
voice->mDirect.Params[c].NFCtrlFilter.adjust(w0);
|
||||
voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0);
|
||||
|
||||
std::copy(std::begin(Device->NumChannelsPerOrder),
|
||||
std::end(Device->NumChannelsPerOrder),
|
||||
@@ -900,7 +896,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
if(Device->Dry.Buffer == Device->RealOut.Buffer)
|
||||
{
|
||||
int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel);
|
||||
if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain;
|
||||
if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -913,12 +909,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
);
|
||||
|
||||
ComputePanGains(&Device->Dry, coeffs, DryGain,
|
||||
voice->mDirect.Params[c].Gains.Target);
|
||||
voice->mChans[c].mDryParams.Gains.Target);
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
{
|
||||
if(const ALeffectslot *Slot{SendSlots[i]})
|
||||
ComputePanGains(&Slot->Wet, coeffs, WetGain[i],
|
||||
voice->mSend[i].Params[c].Gains.Target);
|
||||
voice->mChans[c].mWetParams[i].Gains.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -933,14 +929,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
voice->mDirect.FilterType = AF_None;
|
||||
if(gainHF != 1.0f) voice->mDirect.FilterType |= AF_LowPass;
|
||||
if(gainLF != 1.0f) voice->mDirect.FilterType |= AF_HighPass;
|
||||
voice->mDirect.Params[0].LowPass.setParams(BiquadType::HighShelf,
|
||||
gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f));
|
||||
voice->mDirect.Params[0].HighPass.setParams(BiquadType::LowShelf,
|
||||
gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f));
|
||||
auto &lowpass = voice->mChans[0].mDryParams.LowPass;
|
||||
auto &highpass = voice->mChans[0].mDryParams.HighPass;
|
||||
lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale,
|
||||
lowpass.rcpQFromSlope(gainHF, 1.0f));
|
||||
highpass.setParams(BiquadType::LowShelf, gainLF, lfScale,
|
||||
highpass.rcpQFromSlope(gainLF, 1.0f));
|
||||
for(ALsizei c{1};c < num_channels;c++)
|
||||
{
|
||||
voice->mDirect.Params[c].LowPass.copyParamsFrom(voice->mDirect.Params[0].LowPass);
|
||||
voice->mDirect.Params[c].HighPass.copyParamsFrom(voice->mDirect.Params[0].HighPass);
|
||||
voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass);
|
||||
voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass);
|
||||
}
|
||||
}
|
||||
for(ALsizei i{0};i < NumSends;i++)
|
||||
@@ -953,14 +951,17 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
|
||||
voice->mSend[i].FilterType = AF_None;
|
||||
if(gainHF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass;
|
||||
if(gainLF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass;
|
||||
voice->mSend[i].Params[0].LowPass.setParams(BiquadType::HighShelf,
|
||||
gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f));
|
||||
voice->mSend[i].Params[0].HighPass.setParams(BiquadType::LowShelf,
|
||||
gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f));
|
||||
|
||||
auto &lowpass = voice->mChans[0].mWetParams[i].LowPass;
|
||||
auto &highpass = voice->mChans[0].mWetParams[i].HighPass;
|
||||
lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale,
|
||||
lowpass.rcpQFromSlope(gainHF, 1.0f));
|
||||
highpass.setParams(BiquadType::LowShelf, gainLF, lfScale,
|
||||
highpass.rcpQFromSlope(gainLF, 1.0f));
|
||||
for(ALsizei c{1};c < num_channels;c++)
|
||||
{
|
||||
voice->mSend[i].Params[c].LowPass.copyParamsFrom(voice->mSend[i].Params[0].LowPass);
|
||||
voice->mSend[i].Params[c].HighPass.copyParamsFrom(voice->mSend[i].Params[0].HighPass);
|
||||
voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass);
|
||||
voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-25
@@ -540,8 +540,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
ASSUME(increment > 0);
|
||||
|
||||
ALCdevice *Device{Context->Device};
|
||||
const ALsizei NumSends{Device->NumAuxSends};
|
||||
const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0};
|
||||
|
||||
ASSUME(NumSends >= 0);
|
||||
ASSUME(IrSize >= 0);
|
||||
|
||||
ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ?
|
||||
@@ -553,29 +555,29 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
/* No fading, just overwrite the old/current params. */
|
||||
for(ALsizei chan{0};chan < NumChannels;chan++)
|
||||
{
|
||||
DirectParams &parms = voice->mDirect.Params[chan];
|
||||
ALvoice::ChannelData &chandata = voice->mChans[chan];
|
||||
DirectParams &parms = chandata.mDryParams;
|
||||
if(!(voice->mFlags&VOICE_HAS_HRTF))
|
||||
std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target),
|
||||
std::begin(parms.Gains.Current));
|
||||
else
|
||||
parms.Hrtf.Old = parms.Hrtf.Target;
|
||||
auto set_current = [chan](ALvoice::SendData &send) -> void
|
||||
for(ALsizei send{0};send < NumSends;++send)
|
||||
{
|
||||
if(send.Buffer.empty())
|
||||
return;
|
||||
if(voice->mSend[send].Buffer.empty())
|
||||
continue;
|
||||
|
||||
SendParams &parms = send.Params[chan];
|
||||
SendParams &parms = chandata.mWetParams[chan];
|
||||
std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target),
|
||||
std::begin(parms.Gains.Current));
|
||||
};
|
||||
std::for_each(voice->mSend.begin(), voice->mSend.end(), set_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((voice->mFlags&VOICE_HAS_HRTF))
|
||||
{
|
||||
for(ALsizei chan{0};chan < NumChannels;chan++)
|
||||
{
|
||||
DirectParams &parms = voice->mDirect.Params[chan];
|
||||
DirectParams &parms = voice->mChans[chan].mDryParams;
|
||||
if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
|
||||
{
|
||||
/* The old HRTF params are silent, so overwrite the old
|
||||
@@ -626,14 +628,14 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
const al::span<ALfloat> SrcData{Device->SourceData, SrcBufferSize};
|
||||
|
||||
/* Load the previous samples into the source data first, and clear the rest. */
|
||||
auto srciter = std::copy_n(voice->mResampleData[chan].mPrevSamples.begin(),
|
||||
auto srciter = std::copy_n(voice->mChans[chan].mPrevSamples.begin(),
|
||||
MAX_RESAMPLE_PADDING, SrcData.begin());
|
||||
std::fill(srciter, SrcData.end(), 0.0f);
|
||||
|
||||
if(UNLIKELY(!BufferListItem))
|
||||
srciter = std::copy(
|
||||
voice->mResampleData[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING,
|
||||
voice->mResampleData[chan].mPrevSamples.end(), srciter);
|
||||
voice->mChans[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING,
|
||||
voice->mChans[chan].mPrevSamples.end(), srciter);
|
||||
else if(isstatic)
|
||||
srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels,
|
||||
SampleSize, chan, DataPosInt, srciter, SrcData.end());
|
||||
@@ -654,8 +656,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
|
||||
/* Store the last source samples used for next time. */
|
||||
std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
|
||||
voice->mResampleData[chan].mPrevSamples.size(),
|
||||
voice->mResampleData[chan].mPrevSamples.begin());
|
||||
voice->mChans[chan].mPrevSamples.size(),
|
||||
voice->mChans[chan].mPrevSamples.begin());
|
||||
|
||||
/* Resample, then apply ambisonic upsampling as needed. */
|
||||
const ALfloat *ResampledData{Resample(&voice->mResampleState,
|
||||
@@ -663,20 +665,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
Device->ResampledData, DstBufferSize)};
|
||||
if((voice->mFlags&VOICE_IS_AMBISONIC))
|
||||
{
|
||||
const ALfloat hfscale{voice->mResampleData[chan].mAmbiScale};
|
||||
const ALfloat hfscale{voice->mChans[chan].mAmbiScale};
|
||||
/* Beware the evil const_cast. It's safe since it's pointing to
|
||||
* either SourceData or ResampledData (both non-const), but the
|
||||
* resample method takes the source as const float* and may
|
||||
* return it without copying to output, making it currently
|
||||
* unavoidable.
|
||||
*/
|
||||
voice->mResampleData[chan].mAmbiSplitter.applyHfScale(
|
||||
const_cast<ALfloat*>(ResampledData), hfscale, DstBufferSize);
|
||||
voice->mChans[chan].mAmbiSplitter.applyHfScale(const_cast<ALfloat*>(ResampledData),
|
||||
hfscale, DstBufferSize);
|
||||
}
|
||||
|
||||
/* Now filter and mix to the appropriate outputs. */
|
||||
{
|
||||
DirectParams &parms = voice->mDirect.Params[chan];
|
||||
DirectParams &parms = voice->mChans[chan].mDryParams;
|
||||
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass,
|
||||
Device->FilteredData, ResampledData, DstBufferSize,
|
||||
voice->mDirect.FilterType)};
|
||||
@@ -832,21 +834,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc
|
||||
}
|
||||
|
||||
ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData;
|
||||
auto mix_send = [vstate,Counter,OutPos,DstBufferSize,chan,ResampledData,&FilterBuf](ALvoice::SendData &send) -> void
|
||||
for(ALsizei send{0};send < NumSends;++send)
|
||||
{
|
||||
if(send.Buffer.empty())
|
||||
return;
|
||||
if(voice->mSend[send].Buffer.empty())
|
||||
continue;
|
||||
|
||||
SendParams &parms = send.Params[chan];
|
||||
SendParams &parms = voice->mChans[chan].mWetParams[send];
|
||||
const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass,
|
||||
FilterBuf, ResampledData, DstBufferSize, send.FilterType)};
|
||||
FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)};
|
||||
|
||||
const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget :
|
||||
parms.Gains.Target};
|
||||
MixSamples(samples, send.Buffer, parms.Gains.Current, TargetGains, Counter, OutPos,
|
||||
DstBufferSize);
|
||||
MixSamples(samples, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains,
|
||||
Counter, OutPos, DstBufferSize);
|
||||
};
|
||||
std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send);
|
||||
}
|
||||
/* Update positions */
|
||||
DataPosFrac += increment*DstBufferSize;
|
||||
|
||||
+19
-25
@@ -253,39 +253,33 @@ struct ALvoice {
|
||||
|
||||
ALuint mFlags;
|
||||
|
||||
struct ResampleData {
|
||||
struct DirectData {
|
||||
int FilterType;
|
||||
al::span<FloatBufferLine> Buffer;
|
||||
ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
};
|
||||
DirectData mDirect;
|
||||
|
||||
struct SendData {
|
||||
int FilterType;
|
||||
al::span<FloatBufferLine> Buffer;
|
||||
};
|
||||
std::array<SendData,MAX_SENDS> mSend;
|
||||
|
||||
struct ChannelData {
|
||||
alignas(16) std::array<ALfloat,MAX_RESAMPLE_PADDING*2> mPrevSamples;
|
||||
|
||||
ALfloat mAmbiScale;
|
||||
BandSplitter mAmbiSplitter;
|
||||
|
||||
DirectParams mDryParams;
|
||||
std::array<SendParams,MAX_SENDS> mWetParams;
|
||||
};
|
||||
std::array<ResampleData,MAX_INPUT_CHANNELS> mResampleData;
|
||||
std::array<ChannelData,MAX_INPUT_CHANNELS> mChans;
|
||||
|
||||
struct {
|
||||
int FilterType;
|
||||
DirectParams Params[MAX_INPUT_CHANNELS];
|
||||
|
||||
al::span<FloatBufferLine> Buffer;
|
||||
ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
|
||||
} mDirect;
|
||||
|
||||
struct SendData {
|
||||
int FilterType;
|
||||
SendParams Params[MAX_INPUT_CHANNELS];
|
||||
|
||||
al::span<FloatBufferLine> Buffer;
|
||||
};
|
||||
al::FlexArray<SendData> mSend;
|
||||
|
||||
ALvoice(size_t numsends) : mSend{numsends} { }
|
||||
ALvoice() = default;
|
||||
ALvoice(const ALvoice&) = delete;
|
||||
ALvoice& operator=(const ALvoice&) = delete;
|
||||
|
||||
static constexpr size_t Sizeof(size_t numsends) noexcept
|
||||
{
|
||||
return maxz(sizeof(ALvoice),
|
||||
al::FlexArray<SendData>::Sizeof(numsends, offsetof(ALvoice, mSend)));
|
||||
}
|
||||
};
|
||||
|
||||
void DeinitVoice(ALvoice *voice) noexcept;
|
||||
|
||||
+21
-19
@@ -2938,40 +2938,42 @@ START_API_FUNC
|
||||
BandSplitter splitter{400.0f / static_cast<ALfloat>(device->Frequency)};
|
||||
|
||||
const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder);
|
||||
auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ResampleData &resdata) -> void
|
||||
auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void
|
||||
{
|
||||
resdata.mPrevSamples.fill(0.0f);
|
||||
resdata.mAmbiScale = scales[*(OrderFromChan++)];
|
||||
resdata.mAmbiSplitter = splitter;
|
||||
chandata.mPrevSamples.fill(0.0f);
|
||||
chandata.mAmbiScale = scales[*(OrderFromChan++)];
|
||||
chandata.mAmbiSplitter = splitter;
|
||||
};
|
||||
std::for_each(voice->mResampleData.begin(),
|
||||
voice->mResampleData.begin()+voice->mNumChannels, init_ambi);
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
||||
init_ambi);
|
||||
|
||||
voice->mFlags |= VOICE_IS_AMBISONIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear previous samples. */
|
||||
auto clear_prevs = [](ALvoice::ResampleData &resdata) -> void
|
||||
{ resdata.mPrevSamples.fill(0.0f); };
|
||||
std::for_each(voice->mResampleData.begin(),
|
||||
voice->mResampleData.begin()+voice->mNumChannels, clear_prevs);
|
||||
auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void
|
||||
{ chandata.mPrevSamples.fill(0.0f); };
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
||||
clear_prevs);
|
||||
}
|
||||
|
||||
std::fill_n(std::begin(voice->mDirect.Params), voice->mNumChannels, DirectParams{});
|
||||
std::for_each(voice->mSend.begin(), voice->mSend.end(),
|
||||
[voice](ALvoice::SendData &send) -> void
|
||||
{ std::fill_n(std::begin(send.Params), voice->mNumChannels, SendParams{}); }
|
||||
);
|
||||
auto clear_params = [device](ALvoice::ChannelData &chandata) -> void
|
||||
{
|
||||
chandata.mDryParams = DirectParams{};
|
||||
std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
|
||||
};
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
||||
clear_params);
|
||||
|
||||
if(device->AvgSpeakerDist > 0.0f)
|
||||
{
|
||||
const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC /
|
||||
(device->AvgSpeakerDist * device->Frequency)};
|
||||
std::for_each(voice->mDirect.Params+0, voice->mDirect.Params+voice->mNumChannels,
|
||||
[w1](DirectParams &parms) noexcept -> void
|
||||
{ parms.NFCtrlFilter.init(w1); }
|
||||
);
|
||||
auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void
|
||||
{ chandata.mDryParams.NFCtrlFilter.init(w1); };
|
||||
std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels,
|
||||
init_nfc);
|
||||
}
|
||||
|
||||
voice->mSourceID.store(source->id, std::memory_order_relaxed);
|
||||
|
||||
Reference in New Issue
Block a user