aboutsummaryrefslogtreecommitdiffstats
path: root/alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-06-23 09:44:58 -0700
committerChris Robinson <[email protected]>2021-06-23 09:44:58 -0700
commit5b2489c3e8d19d0be49b94131b6e6a813d37e5ea (patch)
treec213b78d6a43392d82dd9b8fd9901e3b445f2738 /alc
parent2b7c446363b695e1a506b92a0c5a3cf82361f6b2 (diff)
Convert AmbDecConf to DecoderConfig for loading
This keeps AmbDecConf uses confined to multi-channel panning initialization, and avoids spreading conversions and maps all over.
Diffstat (limited to 'alc')
-rw-r--r--alc/panning.cpp623
1 files changed, 312 insertions, 311 deletions
diff --git a/alc/panning.cpp b/alc/panning.cpp
index b158caff..f2869681 100644
--- a/alc/panning.cpp
+++ b/alc/panning.cpp
@@ -38,6 +38,7 @@
#include "AL/alext.h"
#include "al/auxeffectslot.h"
+#include "albit.h"
#include "alconfig.h"
#include "alc/context.h"
#include "almalloc.h"
@@ -132,88 +133,72 @@ void AllocChannels(ALCdevice *device, const size_t main_chans, const size_t real
}
-struct ChannelMap {
- Channel ChanName;
- float Config[MaxAmbi2DChannels];
+using ChannelCoeffs = std::array<float,MaxAmbiChannels>;
+enum DecoderMode : bool {
+ SingleBand = false,
+ DualBand = true
};
-bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, uint (&speakermap)[MAX_OUTPUT_CHANNELS])
-{
- auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> uint
+template<DecoderMode Mode, size_t N>
+struct DecoderConfig;
+
+template<size_t N>
+struct DecoderConfig<SingleBand, N> {
+ uint8_t mOrder{};
+ bool mIs3D{};
+ std::array<Channel,N> mChannels{};
+ std::array<float,MaxAmbiOrder+1> mOrderGain{};
+ std::array<ChannelCoeffs,N> mCoeffs{};
+};
+
+template<size_t N>
+struct DecoderConfig<DualBand, N> {
+ uint8_t mOrder{};
+ bool mIs3D{};
+ std::array<Channel,N> mChannels{};
+ std::array<float,MaxAmbiOrder+1> mOrderGain{};
+ std::array<ChannelCoeffs,N> mCoeffs{};
+ std::array<float,MaxAmbiOrder+1> mOrderGainLF{};
+ std::array<ChannelCoeffs,N> mCoeffsLF{};
+};
+
+template<>
+struct DecoderConfig<DualBand, 0> {
+ uint8_t mOrder{};
+ bool mIs3D{};
+ al::span<const Channel> mChannels;
+ al::span<const float> mOrderGain;
+ al::span<const ChannelCoeffs> mCoeffs;
+ al::span<const float> mOrderGainLF;
+ al::span<const ChannelCoeffs> mCoeffsLF;
+
+ template<size_t N>
+ DecoderConfig& operator=(const DecoderConfig<SingleBand,N> &rhs) noexcept
{
- /* NOTE: AmbDec does not define any standard speaker names, however
- * for this to work we have to by able to find the output channel
- * the speaker definition corresponds to. Therefore, OpenAL Soft
- * requires these channel labels to be recognized:
- *
- * LF = Front left
- * RF = Front right
- * LS = Side left
- * RS = Side right
- * LB = Back left
- * RB = Back right
- * CE = Front center
- * CB = Back center
- *
- * Additionally, surround51 will acknowledge back speakers for side
- * channels, and surround51rear will acknowledge side speakers for
- * back channels, to avoid issues with an ambdec expecting 5.1 to
- * use the side channels when the device is configured for back,
- * and vice-versa.
- */
- Channel ch{};
- if(speaker.Name == "LF")
- ch = FrontLeft;
- else if(speaker.Name == "RF")
- ch = FrontRight;
- else if(speaker.Name == "CE")
- ch = FrontCenter;
- else if(speaker.Name == "LS")
- {
- if(device->FmtChans == DevFmtX51Rear)
- ch = BackLeft;
- else
- ch = SideLeft;
- }
- else if(speaker.Name == "RS")
- {
- if(device->FmtChans == DevFmtX51Rear)
- ch = BackRight;
- else
- ch = SideRight;
- }
- else if(speaker.Name == "LB")
- {
- if(device->FmtChans == DevFmtX51)
- ch = SideLeft;
- else
- ch = BackLeft;
- }
- else if(speaker.Name == "RB")
- {
- if(device->FmtChans == DevFmtX51)
- ch = SideRight;
- else
- ch = BackRight;
- }
- else if(speaker.Name == "CB")
- ch = BackCenter;
- else
- {
- ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str());
- return INVALID_CHANNEL_INDEX;
- }
- const uint chidx{GetChannelIdxByName(device->RealOut, ch)};
- if(chidx == INVALID_CHANNEL_INDEX)
- ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str());
- return chidx;
- };
- std::transform(conf->Speakers.get(), conf->Speakers.get()+conf->NumSpeakers,
- std::begin(speakermap), map_spkr);
- /* Return success if no invalid entries are found. */
- auto spkrmap_end = std::begin(speakermap) + conf->NumSpeakers;
- return std::find(std::begin(speakermap), spkrmap_end, INVALID_CHANNEL_INDEX) == spkrmap_end;
-}
+ mOrder = rhs.mOrder;
+ mIs3D = rhs.mIs3D;
+ mChannels = rhs.mChannels;
+ mOrderGain = rhs.mOrderGain;
+ mCoeffs = rhs.mCoeffs;
+ mOrderGainLF = {};
+ mCoeffsLF = {};
+ return *this;
+ }
+
+ template<size_t N>
+ DecoderConfig& operator=(const DecoderConfig<DualBand,N> &rhs) noexcept
+ {
+ mOrder = rhs.mOrder;
+ mIs3D = rhs.mIs3D;
+ mChannels = rhs.mChannels;
+ mOrderGain = rhs.mOrderGain;
+ mCoeffs = rhs.mCoeffs;
+ mOrderGainLF = rhs.mOrderGainLF;
+ mCoeffsLF = rhs.mCoeffsLF;
+ return *this;
+ }
+};
+using DecoderView = DecoderConfig<DualBand, 0>;
void InitNearFieldCtrl(ALCdevice *device, float ctrl_dist, uint order, bool is3d)
@@ -234,13 +219,10 @@ void InitNearFieldCtrl(ALCdevice *device, float ctrl_dist, uint order, bool is3d
std::fill(iter, std::end(device->NumChannelsPerOrder), 0u);
}
-void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf,
- const uint (&speakermap)[MAX_OUTPUT_CHANNELS])
+void InitDistanceComp(ALCdevice *device, DecoderView decoder,
+ const al::span<const float,MAX_OUTPUT_CHANNELS> dists)
{
- auto get_max = std::bind(maxf, _1,
- std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2));
- const float maxdist{std::accumulate(conf->Speakers.get(),
- conf->Speakers.get()+conf->NumSpeakers, 0.0f, get_max)};
+ const float maxdist{std::accumulate(std::begin(dists), std::end(dists), 0.0f, maxf)};
const char *devname{device->DeviceName.c_str()};
if(!GetConfigValueBool(devname, "decoder", "distance-comp", 1) || !(maxdist > 0.0f))
@@ -248,12 +230,16 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf,
const auto distSampleScale = static_cast<float>(device->Frequency) / SpeedOfSoundMetersPerSec;
std::vector<DistanceComp::ChanData> ChanDelay;
+ ChanDelay.reserve(device->RealOut.Buffer.size());
size_t total{0u};
- ChanDelay.reserve(conf->NumSpeakers + 1);
- for(size_t i{0u};i < conf->NumSpeakers;i++)
+ for(size_t chidx{0};chidx < decoder.mChannels.size();++chidx)
{
- const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i];
- const uint chan{speakermap[i]};
+ const Channel ch{decoder.mChannels[chidx]};
+ const uint idx{device->RealOut.ChannelIndex[ch]};
+ if(idx == INVALID_CHANNEL_INDEX)
+ continue;
+
+ const float distance{dists[chidx]};
/* Distance compensation only delays in steps of the sample rate. This
* is a bit less accurate since the delay time falls to the nearest
@@ -261,24 +247,24 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf,
* phase offsets. This means at 48khz, for instance, the distance delay
* will be in steps of about 7 millimeters.
*/
- float delay{std::floor((maxdist - speaker.Distance)*distSampleScale + 0.5f)};
+ float delay{std::floor((maxdist - distance)*distSampleScale + 0.5f)};
if(delay > float{MAX_DELAY_LENGTH-1})
{
- ERR("Delay for speaker \"%s\" exceeds buffer length (%f > %d)\n",
- speaker.Name.c_str(), delay, MAX_DELAY_LENGTH-1);
+ ERR("Delay for channel %u (%s) exceeds buffer length (%f > %d)\n", idx,
+ GetLabelFromChannel(ch), delay, MAX_DELAY_LENGTH-1);
delay = float{MAX_DELAY_LENGTH-1};
}
- ChanDelay.resize(maxz(ChanDelay.size(), chan+1));
- ChanDelay[chan].Length = static_cast<uint>(delay);
- ChanDelay[chan].Gain = speaker.Distance / maxdist;
- TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan,
- speaker.Name.c_str(), ChanDelay[chan].Length, ChanDelay[chan].Gain);
+ ChanDelay.resize(maxz(ChanDelay.size(), idx+1));
+ ChanDelay[idx].Length = static_cast<uint>(delay);
+ ChanDelay[idx].Gain = distance / maxdist;
+ TRACE("Channel %s distance comp: %u samples, %f gain\n", GetLabelFromChannel(ch),
+ ChanDelay[idx].Length, ChanDelay[idx].Gain);
/* Round up to the next 4th sample, so each channel buffer starts
* 16-byte aligned.
*/
- total += RoundUp(ChanDelay[chan].Length, 4);
+ total += RoundUp(ChanDelay[idx].Length, 4);
}
if(total > 0)
@@ -300,6 +286,13 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf,
}
+inline auto& GetAmbiScales(AmbDecScale scaletype) noexcept
+{
+ if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa();
+ if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D();
+ return AmbiScale::FromN3D();
+}
+
inline auto& GetAmbiScales(DevAmbiScaling scaletype) noexcept
{
if(scaletype == DevAmbiScaling::FuMa) return AmbiScale::FromFuMa();
@@ -314,72 +307,147 @@ inline auto& GetAmbiLayout(DevAmbiLayout layouttype) noexcept
}
-using ChannelCoeffs = std::array<float,MaxAmbiChannels>;
-enum DecoderMode : bool {
- SingleBand = false,
- DualBand = true
-};
-
-template<DecoderMode Mode, size_t N>
-struct DecoderConfig;
-
-template<size_t N>
-struct DecoderConfig<SingleBand, N> {
- uint8_t mOrder;
- bool mIs3D;
- std::array<Channel,N> mChannels;
- std::array<float,MaxAmbiOrder+1> mOrderGain;
- std::array<ChannelCoeffs,N> mCoeffs;
-};
-
-template<size_t N>
-struct DecoderConfig<DualBand, N> {
- uint8_t mOrder;
- bool mIs3D;
- std::array<Channel,N> mChannels;
- std::array<float,MaxAmbiOrder+1> mOrderGain;
- std::array<ChannelCoeffs,N> mCoeffs;
- std::array<float,MaxAmbiOrder+1> mOrderGainLF;
- std::array<ChannelCoeffs,N> mCoeffsLF;
-};
+DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf,
+ DecoderConfig<DualBand, MAX_OUTPUT_CHANNELS> &decoder)
+{
+ decoder.mOrder = (conf->ChanMask > Ambi2OrderMask) ? uint8_t{3} :
+ (conf->ChanMask > Ambi1OrderMask) ? uint8_t{2} : uint8_t{1};
+ decoder.mIs3D = (conf->ChanMask&AmbiPeriphonicMask) != 0;
+
+ std::copy_n(std::begin(conf->HFOrderGain),
+ std::min(al::size(conf->HFOrderGain), al::size(decoder.mOrderGain)),
+ std::begin(decoder.mOrderGain));
+ std::copy_n(std::begin(conf->LFOrderGain),
+ std::min(al::size(conf->LFOrderGain), al::size(decoder.mOrderGainLF)),
+ std::begin(decoder.mOrderGainLF));
+
+ const uint8_t *acnmap{};
+ std::array<uint8_t,MaxAmbiChannels> idx_map{};
+ if(decoder.mIs3D)
+ {
+ acnmap = AmbiIndex::FromACN().data();
+ uint flags{conf->ChanMask};
+ auto elem = idx_map.begin();
+ while(flags)
+ {
+ int acn{al::countr_zero(flags)};
+ flags &= ~(1u<<acn);
-template<>
-struct DecoderConfig<DualBand, 0> {
- uint8_t mOrder;
- bool mIs3D;
- al::span<const Channel> mChannels;
- al::span<const float> mOrderGain;
- al::span<const ChannelCoeffs> mCoeffs;
- al::span<const float> mOrderGainLF;
- al::span<const ChannelCoeffs> mCoeffsLF;
+ *elem = static_cast<uint8_t>(acn);
+ ++elem;
+ }
+ }
+ else
+ {
+ acnmap = AmbiIndex::FromACN2D().data();
+ uint flags{conf->ChanMask};
+ auto elem = idx_map.begin();
+ while(flags)
+ {
+ int acn{al::countr_zero(flags)};
+ flags &= ~(1u<<acn);
- template<size_t N>
- DecoderConfig& operator=(const DecoderConfig<SingleBand,N> &rhs) noexcept
+ switch(acn)
+ {
+ case 0: *elem = 0; break;
+ case 1: *elem = 1; break;
+ case 3: *elem = 2; break;
+ case 4: *elem = 3; break;
+ case 8: *elem = 4; break;
+ case 9: *elem = 5; break;
+ case 15: *elem = 6; break;
+ default: return DecoderView{};
+ }
+ ++elem;
+ }
+ }
+ auto&& coeffscale = GetAmbiScales(conf->CoeffScale);
+ const auto num_coeffs = static_cast<uint>(al::popcount(conf->ChanMask));
+ const auto hfmatrix = conf->HFMatrix;
+ const auto lfmatrix = conf->LFMatrix;
+
+ uint chan_count{0};
+ using const_speaker_span = al::span<const AmbDecConf::SpeakerConf>;
+ for(auto &speaker : const_speaker_span{conf->Speakers.get(), conf->NumSpeakers})
{
- mOrder = rhs.mOrder;
- mIs3D = rhs.mIs3D;
- mChannels = rhs.mChannels;
- mOrderGain = rhs.mOrderGain;
- mCoeffs = rhs.mCoeffs;
- mOrderGainLF = {};
- mCoeffsLF = {};
- return *this;
+ /* NOTE: AmbDec does not define any standard speaker names, however
+ * for this to work we have to by able to find the output channel
+ * the speaker definition corresponds to. Therefore, OpenAL Soft
+ * requires these channel labels to be recognized:
+ *
+ * LF = Front left
+ * RF = Front right
+ * LS = Side left
+ * RS = Side right
+ * LB = Back left
+ * RB = Back right
+ * CE = Front center
+ * CB = Back center
+ *
+ * Additionally, surround51 will acknowledge back speakers for side
+ * channels, and surround51rear will acknowledge side speakers for
+ * back channels, to avoid issues with an ambdec expecting 5.1 to
+ * use the side channels when the device is configured for back,
+ * and vice-versa.
+ */
+ Channel ch{};
+ if(speaker.Name == "LF")
+ ch = FrontLeft;
+ else if(speaker.Name == "RF")
+ ch = FrontRight;
+ else if(speaker.Name == "CE")
+ ch = FrontCenter;
+ else if(speaker.Name == "LS")
+ ch = (device->FmtChans == DevFmtX51Rear) ? BackLeft : SideLeft;
+ else if(speaker.Name == "RS")
+ ch = (device->FmtChans == DevFmtX51Rear) ? BackRight : SideRight;
+ else if(speaker.Name == "LB")
+ ch = (device->FmtChans == DevFmtX51) ? SideLeft : BackLeft;
+ else if(speaker.Name == "RB")
+ ch = (device->FmtChans == DevFmtX51) ? SideRight : BackRight;
+ else if(speaker.Name == "CB")
+ ch = BackCenter;
+ else
+ {
+ ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str());
+ continue;
+ }
+
+ decoder.mChannels[chan_count] = ch;
+ for(size_t src{0};src < num_coeffs;++src)
+ {
+ const size_t dst{idx_map[src]};
+ const size_t acn{acnmap[dst]};
+ decoder.mCoeffs[chan_count][dst] = hfmatrix[chan_count][src] / coeffscale[acn];
+ }
+ if(conf->FreqBands > 1)
+ {
+ for(size_t src{0};src < num_coeffs;++src)
+ {
+ const size_t dst{idx_map[src]};
+ const size_t acn{acnmap[dst]};
+ decoder.mCoeffsLF[chan_count][dst] = lfmatrix[chan_count][src] / coeffscale[acn];
+ }
+ }
+ ++chan_count;
}
- template<size_t N>
- DecoderConfig& operator=(const DecoderConfig<DualBand,N> &rhs) noexcept
+ DecoderView ret{};
+ if(chan_count > 0)
{
- mOrder = rhs.mOrder;
- mIs3D = rhs.mIs3D;
- mChannels = rhs.mChannels;
- mOrderGain = rhs.mOrderGain;
- mCoeffs = rhs.mCoeffs;
- mOrderGainLF = rhs.mOrderGainLF;
- mCoeffsLF = rhs.mCoeffsLF;
- return *this;
+ ret.mOrder = decoder.mOrder;
+ ret.mIs3D = decoder.mIs3D;
+ ret.mChannels = {decoder.mChannels.data(), chan_count};
+ ret.mOrderGain = decoder.mOrderGain;
+ ret.mCoeffs = {decoder.mCoeffs.data(), chan_count};
+ if(conf->FreqBands > 1)
+ {
+ ret.mOrderGainLF = decoder.mOrderGainLF;
+ ret.mCoeffsLF = {decoder.mCoeffsLF.data(), chan_count};
+ }
}
-};
-using DecoderView = DecoderConfig<DualBand, 0>;
+ return ret;
+}
constexpr DecoderConfig<SingleBand, 1> MonoConfig{
0, false, {{FrontCenter}},
@@ -464,49 +532,38 @@ constexpr DecoderConfig<DualBand, 6> X71Config{
}}
};
-void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=false)
+void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=false,
+ DecoderView decoder={})
{
- DecoderView decoder{};
- switch(device->FmtChans)
+ if(!decoder.mOrder)
{
- case DevFmtMono:
- decoder = MonoConfig;
- break;
- case DevFmtStereo:
- decoder = StereoConfig;
- break;
- case DevFmtQuad:
- decoder = QuadConfig;
- break;
- case DevFmtX51:
- decoder = X51Config;
- break;
- case DevFmtX51Rear:
- decoder = X51RearConfig;
- break;
- case DevFmtX61:
- decoder = X61Config;
- break;
- case DevFmtX71:
- decoder = X71Config;
- break;
- case DevFmtAmbi3D:
- const char *devname{device->DeviceName.c_str()};
- auto&& acnmap = GetAmbiLayout(device->mAmbiLayout);
- auto&& n3dscale = GetAmbiScales(device->mAmbiScale);
-
- /* For DevFmtAmbi3D, the ambisonic order is already set. */
- const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)};
- std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap),
- [&n3dscale](const uint8_t &acn) noexcept -> BFChannelConfig
- { return BFChannelConfig{1.0f/n3dscale[acn], acn}; });
- AllocChannels(device, count, 0);
-
- float nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)};
- if(nfc_delay > 0.0f)
- InitNearFieldCtrl(device, nfc_delay * SpeedOfSoundMetersPerSec, device->mAmbiOrder,
- true);
- return;
+ switch(device->FmtChans)
+ {
+ case DevFmtMono: decoder = MonoConfig; break;
+ case DevFmtStereo: decoder = StereoConfig; break;
+ case DevFmtQuad: decoder = QuadConfig; break;
+ case DevFmtX51: decoder = X51Config; break;
+ case DevFmtX51Rear: decoder = X51RearConfig; break;
+ case DevFmtX61: decoder = X61Config; break;
+ case DevFmtX71: decoder = X71Config; break;
+ case DevFmtAmbi3D:
+ const char *devname{device->DeviceName.c_str()};
+ auto&& acnmap = GetAmbiLayout(device->mAmbiLayout);
+ auto&& n3dscale = GetAmbiScales(device->mAmbiScale);
+
+ /* For DevFmtAmbi3D, the ambisonic order is already set. */
+ const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)};
+ std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap),
+ [&n3dscale](const uint8_t &acn) noexcept -> BFChannelConfig
+ { return BFChannelConfig{1.0f/n3dscale[acn], acn}; });
+ AllocChannels(device, count, 0);
+
+ float nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)};
+ if(nfc_delay > 0.0f)
+ InitNearFieldCtrl(device, nfc_delay * SpeedOfSoundMetersPerSec, device->mAmbiOrder,
+ true);
+ return;
+ }
}
const bool dual_band{hqdec && !decoder.mCoeffsLF.empty()};
@@ -590,87 +647,7 @@ void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=
(decoder.mOrder > 1) ? "second" : "first",
decoder.mIs3D ? " periphonic" : "");
device->AmbiDecoder = BFormatDec::Create(ambicount, chancoeffs, chancoeffslf,
- std::move(stablizer));
-}
-
-void InitCustomPanning(ALCdevice *device, const bool hqdec, const bool stablize,
- const AmbDecConf *conf, const uint (&speakermap)[MAX_OUTPUT_CHANNELS])
-{
- if(!hqdec && conf->FreqBands != 1)
- ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n",
- conf->XOverFreq);
- device->mXOverFreq = conf->XOverFreq;
-
- const uint order{(conf->ChanMask > Ambi2OrderMask) ? 3u :
- (conf->ChanMask > Ambi1OrderMask) ? 2u : 1u};
- device->mAmbiOrder = order;
-
- size_t count;
- if((conf->ChanMask&AmbiPeriphonicMask))
- {
- count = AmbiChannelsFromOrder(order);
- std::transform(AmbiIndex::FromACN().begin(), AmbiIndex::FromACN().begin()+count,
- std::begin(device->Dry.AmbiMap),
- [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; }
- );
- }
- else
- {
- count = Ambi2DChannelsFromOrder(order);
- std::transform(AmbiIndex::FromACN2D().begin(), AmbiIndex::FromACN2D().begin()+count,
- std::begin(device->Dry.AmbiMap),
- [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; }
- );
- }
- AllocChannels(device, count, device->channelsFromFmt());
-
- std::unique_ptr<FrontStablizer> stablizer;
- if(stablize)
- {
- /* Only enable the stablizer if the decoder does not output to the
- * front-center channel.
- */
- size_t cidx{0};
- for(;cidx < conf->NumSpeakers;++cidx)
- {
- if(speakermap[cidx] == FrontCenter)
- break;
- }
- bool hasfc{false};
- if(cidx < conf->NumSpeakers && conf->FreqBands != 1)
- {
- for(const auto &coeff : conf->LFMatrix[cidx])
- hasfc |= coeff != 0.0f;
- }
- if(!hasfc && cidx < conf->NumSpeakers)
- {
- for(const auto &coeff : conf->HFMatrix[cidx])
- hasfc |= coeff != 0.0f;
- }
- if(!hasfc)
- {
- stablizer = CreateStablizer(device->channelsFromFmt(), device->Frequency);
- TRACE("Front stablizer enabled\n");
- }
- }
-
- TRACE("Enabling %s-band %s-order%s ambisonic decoder\n",
- (!hqdec || conf->FreqBands == 1) ? "single" : "dual",
- (conf->ChanMask > Ambi2OrderMask) ? "third" :
- (conf->ChanMask > Ambi1OrderMask) ? "second" : "first",
- (conf->ChanMask&AmbiPeriphonicMask) ? " periphonic" : ""
- );
- device->AmbiDecoder = BFormatDec::Create(conf, hqdec, count, device->Frequency, speakermap,
- std::move(stablizer));
-
- auto accum_spkr_dist = std::bind(std::plus<float>{}, _1,
- std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2));
- const float accum_dist{std::accumulate(conf->Speakers.get(),
- conf->Speakers.get()+conf->NumSpeakers, 0.0f, accum_spkr_dist)};
- InitNearFieldCtrl(device, accum_dist / static_cast<float>(conf->NumSpeakers), order,
- !!(conf->ChanMask&AmbiPeriphonicMask));
-
- InitDistanceComp(device, conf, speakermap);
+ device->mXOverFreq/static_cast<float>(device->Frequency), std::move(stablizer));
}
void InitHrtfPanning(ALCdevice *device)
@@ -867,39 +844,49 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, HrtfRequestMode hrtf_appreq
const char *layout{nullptr};
switch(device->FmtChans)
{
- case DevFmtQuad: layout = "quad"; break;
- case DevFmtX51: /* fall-through */
- case DevFmtX51Rear: layout = "surround51"; break;
- case DevFmtX61: layout = "surround61"; break;
- case DevFmtX71: layout = "surround71"; break;
- /* Mono, Stereo, and Ambisonics output don't use custom decoders. */
- case DevFmtMono:
- case DevFmtStereo:
- case DevFmtAmbi3D:
- break;
+ case DevFmtQuad: layout = "quad"; break;
+ case DevFmtX51: /* fall-through */
+ case DevFmtX51Rear: layout = "surround51"; break;
+ case DevFmtX61: layout = "surround61"; break;
+ case DevFmtX71: layout = "surround71"; break;
+ /* Mono, Stereo, and Ambisonics output don't use custom decoders. */
+ case DevFmtMono:
+ case DevFmtStereo:
+ case DevFmtAmbi3D:
+ break;
}
- uint speakermap[MAX_OUTPUT_CHANNELS];
- AmbDecConf *pconf{nullptr};
- AmbDecConf conf{};
- if(layout)
+ std::unique_ptr<DecoderConfig<DualBand,MAX_OUTPUT_CHANNELS>> decoder_store;
+ DecoderView decoder{};
+ float speakerdists[MaxChannels]{};
+ auto load_config = [device,&decoder_store,&decoder,&speakerdists](const char *config)
{
- if(auto decopt = ConfigValueStr(devname, "decoder", layout))
+ AmbDecConf conf{};
+ if(auto err = conf.load(config))
{
- if(auto err = conf.load(decopt->c_str()))
- {
- ERR("Failed to load layout file %s\n", decopt->c_str());
- ERR(" %s\n", err->c_str());
- }
- else if(conf.NumSpeakers > MAX_OUTPUT_CHANNELS)
- ERR("Unsupported decoder speaker count %zu (max %d)\n", conf.NumSpeakers,
- MAX_OUTPUT_CHANNELS);
- else if(conf.ChanMask > Ambi3OrderMask)
- ERR("Unsupported decoder channel mask 0x%04x (max 0x%x)\n", conf.ChanMask,
- Ambi3OrderMask);
- else if(MakeSpeakerMap(device, &conf, speakermap))
- pconf = &conf;
+ ERR("Failed to load layout file %s\n", config);
+ ERR(" %s\n", err->c_str());
}
+ else if(conf.NumSpeakers > MAX_OUTPUT_CHANNELS)
+ ERR("Unsupported decoder speaker count %zu (max %d)\n", conf.NumSpeakers,
+ MAX_OUTPUT_CHANNELS);
+ else if(conf.ChanMask > Ambi3OrderMask)
+ ERR("Unsupported decoder channel mask 0x%04x (max 0x%x)\n", conf.ChanMask,
+ Ambi3OrderMask);
+ else
+ {
+ device->mXOverFreq = clampf(conf.XOverFreq, 100.0f, 1000.0f);
+
+ decoder_store = std::make_unique<decltype(decoder_store)::element_type>();
+ decoder = MakeDecoderView(device, &conf, *decoder_store);
+ for(size_t i{0};i < decoder.mChannels.size();++i)
+ speakerdists[i] = conf.Speakers[i].Distance;
+ }
+ };
+ if(layout)
+ {
+ if(auto decopt = ConfigValueStr(devname, "decoder", layout))
+ load_config(decopt->c_str());
}
/* Enable the stablizer only for formats that have front-left, front-
@@ -910,10 +897,24 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, HrtfRequestMode hrtf_appreq
&& device->RealOut.ChannelIndex[FrontRight] != INVALID_CHANNEL_INDEX
&& GetConfigValueBool(devname, nullptr, "front-stablizer", 0) != 0};
const bool hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 1) != 0};
- if(!pconf)
- InitPanning(device, hqdec, stablize);
- else
- InitCustomPanning(device, hqdec, stablize, pconf, speakermap);
+ InitPanning(device, hqdec, stablize, decoder);
+ if(decoder.mOrder > 0)
+ {
+ float accum_dist{0.0f}, spkr_count{0.0f};
+ for(auto dist : speakerdists)
+ {
+ if(dist > 0.0f)
+ {
+ accum_dist += dist;
+ spkr_count += 1.0f;
+ }
+ }
+ if(spkr_count > 0)
+ {
+ InitNearFieldCtrl(device, accum_dist / spkr_count, decoder.mOrder, decoder.mIs3D);
+ InitDistanceComp(device, decoder, speakerdists);
+ }
+ }
if(auto *ambidec{device->AmbiDecoder.get()})
{
device->PostProcess = ambidec->hasStablizer() ? &ALCdevice::ProcessAmbiDecStablized