/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/macros.hpp" #include "mpt/random/default_engines.hpp" #include "mpt/random/engine.hpp" #include "openmpt/soundbase/MixSample.hpp" #include #include #include OPENMPT_NAMESPACE_BEGIN template class MultiChannelDither { private: std::vector DitherChannels; typename Tdither::prng_type prng; public: template MultiChannelDither(Trd &rd, std::size_t channels) : DitherChannels(channels) , prng(Tdither::prng_init(rd)) { return; } void Reset() { for(std::size_t channel = 0; channel < DitherChannels.size(); ++channel) { DitherChannels[channel] = Tdither{}; } } std::size_t GetChannels() const { return DitherChannels.size(); } template MPT_FORCEINLINE MixSampleInt process(std::size_t channel, MixSampleInt sample) { return DitherChannels[channel].template process(sample, prng); } template MPT_FORCEINLINE MixSampleFloat process(std::size_t channel, MixSampleFloat sample) { return DitherChannels[channel].template process(sample, prng); } }; template class Dithers : public DitherNames { public: static constexpr std::size_t NoDither = noDither; static constexpr std::size_t DefaultDither = defaultDither; static constexpr std::size_t DefaultChannels = defaultChannels; private: seeding_random_engine m_PRNG; AvailableDithers m_Dithers; public: template Dithers(Trd &rd, std::size_t mode = defaultDither, std::size_t channels = defaultChannels) : m_PRNG(mpt::make_prng(rd)) , m_Dithers(std::in_place_index, m_PRNG, channels) { SetMode(mode, channels); } AvailableDithers &Variant() { return m_Dithers; } static std::size_t GetNumDithers() { return std::variant_size::value; } static std::size_t GetDefaultDither() { return defaultDither; } static std::size_t GetNoDither() { return noDither; } private: template void set_mode(std::size_t mode, std::size_t channels) { if constexpr(i < std::variant_size::value) { if(mode == i) { m_Dithers.template emplace(m_PRNG, channels); } else { this->template set_mode(mode, channels); } } else { MPT_UNUSED(mode); m_Dithers.template emplace(m_PRNG, channels); } } public: void SetMode(std::size_t mode, std::size_t channels) { if((mode == GetMode()) && (channels == GetChannels())) { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); return; } set_mode(mode, channels); } void SetMode(std::size_t mode) { if(mode == GetMode()) { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); return; } set_mode(mode, GetChannels()); } void SetChannels(std::size_t channels) { if(channels == GetChannels()) { return; } set_mode(GetMode(), channels); } void Reset() { std::visit([](auto &dither) { return dither.Reset(); }, m_Dithers); } std::size_t GetMode() const { return m_Dithers.index(); } std::size_t GetChannels() const { return std::visit([](auto &dither) { return dither.GetChannels(); }, m_Dithers); } }; OPENMPT_NAMESPACE_END