diff --git a/al/source.cpp b/al/source.cpp index 63397ec8..733960ee 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -441,9 +441,9 @@ void InitVoice(ALvoice *voice, ALsource *source, ALbufferlistitem *BufferList, A voice->mLoopBuffer.store(source->Looping ? source->queue : nullptr, std::memory_order_relaxed); ALbuffer *buffer{BufferList->mBuffer}; + ALuint num_channels{buffer->channelsFromFmt()}; voice->mFrequency = buffer->Frequency; voice->mFmtChannels = buffer->mFmtChannels; - voice->mNumChannels = buffer->channelsFromFmt(); voice->mSampleSize = buffer->bytesFromFmt(); voice->mAmbiLayout = static_cast(buffer->AmbiLayout); voice->mAmbiScaling = static_cast(buffer->AmbiScaling); @@ -458,6 +458,11 @@ void InitVoice(ALvoice *voice, ALsource *source, ALbufferlistitem *BufferList, A */ voice->mStep = 0; + if(voice->mChans.capacity() > 2 && num_channels < voice->mChans.capacity()) + al::vector{}.swap(voice->mChans); + voice->mChans.reserve(maxu(2, num_channels)); + voice->mChans.resize(num_channels); + /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is not * higher order than the voice. No HF scaling is necessary to mix it. */ @@ -467,43 +472,38 @@ void InitVoice(ALvoice *voice, ALsource *source, ALbufferlistitem *BufferList, A const uint8_t *OrderFromChan{(voice->mFmtChannels == FmtBFormat2D) ? AmbiIndex::OrderFrom2DChannel.data() : AmbiIndex::OrderFromChannel.data()}; + const auto scales = BFormatDec::GetHFOrderScales(voice->mAmbiOrder, device->mAmbiOrder); const BandSplitter splitter{400.0f / static_cast(device->Frequency)}; - const auto scales = BFormatDec::GetHFOrderScales(voice->mAmbiOrder, device->mAmbiOrder); - auto init_ambi = [device,&scales,&OrderFromChan,splitter](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { chandata.mPrevSamples.fill(0.0f); chandata.mAmbiScale = scales[*(OrderFromChan++)]; chandata.mAmbiSplitter = splitter; chandata.mDryParams = DirectParams{}; std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - 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 = [device](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { chandata.mPrevSamples.fill(0.0f); chandata.mDryParams = DirectParams{}; std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_prevs); + } } if(device->AvgSpeakerDist > 0.0f) { const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * static_cast(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); + for(auto &chandata : voice->mChans) + chandata.mDryParams.NFCtrlFilter.init(w1); } source->PropsClean.test_and_set(std::memory_order_acq_rel); diff --git a/alc/alc.cpp b/alc/alc.cpp index 562005fd..d1964bd4 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1656,14 +1656,16 @@ void ALCcontext::allocVoiceChanges(size_t addcount) void ALCcontext::allocVoices(size_t addcount) { - constexpr size_t clustersize{4}; + constexpr size_t clustersize{32}; /* Convert element count to cluster count. */ addcount = (addcount+(clustersize-1)) / clustersize; if(addcount >= std::numeric_limits::max()/clustersize - mVoiceClusters.size()) throw std::runtime_error{"Allocating too many voices"}; + const size_t totalcount{(mVoiceClusters.size()+addcount) * clustersize}; + TRACE("Increasing allocated voices to %zu\n", totalcount); - auto newarray = ALvoiceArray::Create((mVoiceClusters.size()+addcount) * clustersize); + auto newarray = ALvoiceArray::Create(totalcount); while(addcount) { mVoiceClusters.emplace_back(std::make_unique(clustersize)); @@ -2292,28 +2294,26 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) vprops = next; } + auto voicelist = context->getVoicesSpan(); if(device->NumAuxSends < old_sends) { const ALuint num_sends{device->NumAuxSends}; /* Clear extraneous property set sends. */ - auto clear_sends = [num_sends](ALvoice *voice) -> void + for(ALvoice *voice : voicelist) { std::fill(std::begin(voice->mProps.Send)+num_sends, std::end(voice->mProps.Send), ALvoiceProps::SendData{}); std::fill(voice->mSend.begin()+num_sends, voice->mSend.end(), ALvoice::TargetData{}); - auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), SendParams{}); - }; - std::for_each(voice->mChans.begin(), voice->mChans.end(), clear_chan_sends); - }; - auto voicelist = context->getVoicesSpan(); - std::for_each(voicelist.begin(), voicelist.end(), clear_sends); + } + } } - auto reset_voice = [device](ALvoice *voice) -> void + for(ALvoice *voice : voicelist) { delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); @@ -2322,7 +2322,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) voice->mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, std::memory_order_acquire, std::memory_order_acquire); if(voice->mSourceID.load(std::memory_order_relaxed) == 0u) - return; + continue; voice->mStep = 0; voice->mFlags |= VOICE_IS_FADING; @@ -2338,30 +2338,26 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) const auto scales = BFormatDec::GetHFOrderScales(voice->mAmbiOrder, device->mAmbiOrder); - auto init_ambi = [device,&scales,&OrderFromChan,splitter](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { chandata.mPrevSamples.fill(0.0f); chandata.mAmbiScale = scales[*(OrderFromChan++)]; chandata.mAmbiSplitter = splitter; chandata.mDryParams = DirectParams{}; std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - 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 = [device](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { chandata.mPrevSamples.fill(0.0f); chandata.mDryParams = DirectParams{}; std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_prevs); + } voice->mFlags &= ~VOICE_IS_AMBISONIC; } @@ -2371,14 +2367,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* Reinitialize the NFC filters for new parameters. */ const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * static_cast(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); + for(auto &chandata : voice->mChans) + chandata.mDryParams.NFCtrlFilter.init(w1); } - }; - auto voicelist = context->getVoicesSpan(); - std::for_each(voicelist.begin(), voicelist.end(), reset_voice); + } srclock.unlock(); context->mPropsClean.test_and_set(std::memory_order_release); diff --git a/alc/alu.cpp b/alc/alu.cpp index 17eff6a5..13e57a09 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -744,17 +744,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const auto Frequency = static_cast(Device->Frequency); const ALuint NumSends{Device->NumAuxSends}; - const ALuint num_channels{voice->mNumChannels}; + const size_t num_channels{voice->mChans.size()}; ASSUME(num_channels > 0); - auto clear_target = [NumSends](ALvoice::ChannelData &chandata) -> void + for(auto &chandata : voice->mChans) { chandata.mDryParams.Hrtf.Target = HrtfFilter{}; chandata.mDryParams.Gains.Target.fill(0.0f); std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, [](SendParams ¶ms) -> void { params.Gains.Target.fill(0.0f); }); - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels, clear_target); + } DirectMode DirectChannels{props->DirectChannels}; const ChanMap *chans{nullptr}; @@ -922,7 +921,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo static const uint8_t ChansPerOrder[MAX_AMBI_ORDER+1]{1, 3, 5, 7,}; static const uint8_t OrderOffset[MAX_AMBI_ORDER+1]{0, 1, 4, 9,}; - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { const size_t acn{index_map[c]}; const size_t order{AmbiIndex::OrderFromChannel[acn]}; @@ -954,7 +953,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo */ voice->mDirect.Buffer = Device->RealOut.Buffer; - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; if(idx != INVALID_CHANNEL_INDEX) @@ -979,7 +978,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Auxiliary sends still use normal channel panning since they mix to * B-Format, which can't channel-match. */ - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); @@ -1013,7 +1012,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain.Base * downmix_gain; /* Remaining channels use the same results as the first. */ - for(ALuint c{1};c < num_channels;c++) + for(size_t c{1};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) continue; @@ -1026,7 +1025,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) @@ -1045,7 +1044,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * relative location around the listener, providing "virtual * speaker" responses. */ - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) @@ -1091,7 +1090,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; /* Adjust NFC filters. */ - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); voice->mFlags |= VOICE_HAS_NFC; @@ -1110,7 +1109,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); } - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { /* Special-case LFE */ if(chans[c].channel == LFE) @@ -1142,13 +1141,13 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * infinite distance, which results in a w0 of 0. */ constexpr float w0{0.0f}; - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); voice->mFlags |= VOICE_HAS_NFC; } - for(ALuint c{0};c < num_channels;c++) + for(size_t c{0};c < num_channels;c++) { /* Special-case LFE */ if(chans[c].channel == LFE) @@ -1193,7 +1192,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo auto &highpass = voice->mChans[0].mDryParams.HighPass; lowpass.setParamsFromSlope(BiquadType::HighShelf, hfNorm, DryGain.HF, 1.0f); highpass.setParamsFromSlope(BiquadType::LowShelf, lfNorm, DryGain.LF, 1.0f); - for(ALuint c{1};c < num_channels;c++) + for(size_t c{1};c < num_channels;c++) { voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass); voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass); @@ -1212,7 +1211,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo auto &highpass = voice->mChans[0].mWetParams[i].HighPass; lowpass.setParamsFromSlope(BiquadType::HighShelf, hfNorm, WetGain[i].HF, 1.0f); highpass.setParamsFromSlope(BiquadType::LowShelf, lfNorm, WetGain[i].LF, 1.0f); - for(ALuint c{1};c < num_channels;c++) + for(size_t c{1};c < num_channels;c++) { voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass); voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass); diff --git a/alc/voice.cpp b/alc/voice.cpp index bcfa9b46..369c2ad4 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -553,7 +553,6 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; - const ALuint NumChannels{mNumChannels}; const ALuint SampleSize{mSampleSize}; const ALuint increment{mStep}; if UNLIKELY(increment < 1) @@ -566,10 +565,10 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT return; } - ASSUME(NumChannels > 0); ASSUME(SampleSize > 0); - ASSUME(increment > 0); - const auto FrameSize = size_t{NumChannels} * SampleSize; + + const size_t FrameSize{mChans.size() * SampleSize}; + ASSUME(FrameSize > 0); ALCdevice *Device{Context->mDevice.get()}; const ALuint NumSends{Device->NumAuxSends}; @@ -582,9 +581,8 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT if(!Counter) { /* No fading, just overwrite the old/current params. */ - for(ALuint chan{0};chan < NumChannels;chan++) + for(auto &chandata : mChans) { - ChannelData &chandata = mChans[chan]; { DirectParams &parms = chandata.mDryParams; if(!(mFlags&VOICE_HAS_HRTF)) @@ -604,9 +602,9 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT } else if((mFlags&VOICE_HAS_HRTF)) { - for(ALuint chan{0};chan < NumChannels;chan++) + for(auto &chandata : mChans) { - DirectParams &parms = mChans[chan].mDryParams; + DirectParams &parms = chandata.mDryParams; if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) { /* The old HRTF params are silent, so overwrite the old @@ -680,10 +678,12 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT } ASSUME(DstBufferSize > 0); - for(ALuint chan{0};chan < NumChannels;chan++) + for(auto &chandata : mChans) { - ChannelData &chandata = mChans[chan]; - const al::span SrcData{Device->SourceData, SrcBufferSize}; + const size_t num_chans{mChans.size()}; + const auto chan = static_cast(std::distance(mChans.data(), + std::addressof(chandata))); + const al::span SrcData{Device->SourceData, SrcBufferSize}; /* Load the previous samples into the source data first, then load * what we can from the buffer queue. @@ -695,13 +695,13 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT srciter = std::copy(chandata.mPrevSamples.begin()+(MAX_RESAMPLER_PADDING>>1), chandata.mPrevSamples.end(), srciter); else if((mFlags&VOICE_IS_STATIC)) - srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, + srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, num_chans, SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); else if((mFlags&VOICE_IS_CALLBACK)) - srciter = LoadBufferCallback(BufferListItem, NumChannels, SampleSize, chan, + srciter = LoadBufferCallback(BufferListItem, num_chans, SampleSize, chan, mNumCallbackSamples, {srciter, SrcData.end()}); else - srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, + srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, num_chans, SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); if UNLIKELY(srciter != SrcData.end()) diff --git a/alc/voice.h b/alc/voice.h index 0324f329..6583d4f1 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -226,7 +226,6 @@ struct ALvoice { /* Properties for the attached buffer(s). */ FmtChannels mFmtChannels; ALuint mFrequency; - ALuint mNumChannels; ALuint mSampleSize; AmbiLayout mAmbiLayout; AmbiNorm mAmbiScaling; @@ -258,7 +257,7 @@ struct ALvoice { DirectParams mDryParams; std::array mWetParams; }; - std::array mChans; + al::vector mChans{2}; ALvoice() = default; ALvoice(const ALvoice&) = delete;