57 static_assert(std::is_floating_point_v<T>,
"Dither requires a floating-point sample type");
69 explicit Dither(
int targetBits = 16,
bool noiseShaping =
false) noexcept
70 : noiseShaping_(noiseShaping)
72 static std::atomic<uint32_t> seedGenerator{ 0x193A6B54u };
74 rngState_ = seedGenerator.fetch_add(0x9E3779B9u, std::memory_order_relaxed);
77 if (rngState_ == 0) rngState_ = 1;
89 constexpr int maxBits = (
sizeof(T) == 4) ? 24 : 32;
90 targetBits_ = std::clamp(bits, 8, maxBits);
94 int64_t levels = int64_t(1) << (targetBits_ - 1);
96 quantScale_ =
static_cast<T
>(levels);
97 quantStep_ = T(1) / quantScale_;
98 loLevel_ = -quantScale_;
99 hiLevel_ = quantScale_ - T(1);
103 errorCap_ = T(2) * quantStep_;
112 std::fill(errorState_.begin(), errorState_.end(), T(0));
124 if (noiseShaping_ && channel >= 0 && channel < kMaxChannels)
125 return processSampleInternal<true>(input, channel);
127 return processSampleInternal<false>(input, channel);
142 if (noiseShaping_ && channel >= 0 && channel < kMaxChannels)
144 for (
int i = 0; i < numSamples; ++i)
145 data[i] = processSampleInternal<true>(data[i], channel);
149 for (
int i = 0; i < numSamples; ++i)
150 data[i] = processSampleInternal<false>(data[i], channel);
158 static constexpr int kMaxChannels = 16;
163 template <
bool ApplyNoiseShaping>
164 [[nodiscard]]
inline T processSampleInternal(T input,
int channel)
noexcept
167 const T noise = (nextRandom() + nextRandom()) * quantStep_;
169 T preQuantise = input;
171 if constexpr (ApplyNoiseShaping)
173 preQuantise -= errorState_[
static_cast<size_t>(channel)];
177 const T dithered = preQuantise + noise;
183 const T level = std::clamp(std::nearbyint(dithered * quantScale_), loLevel_, hiLevel_);
184 const T quantised = level * quantStep_;
186 if constexpr (ApplyNoiseShaping)
196 const T err = quantised - preQuantise;
197 errorState_[
static_cast<size_t>(channel)] = std::clamp(err, -errorCap_, errorCap_);
207 [[nodiscard]]
inline T nextRandom() noexcept
209 rngState_ ^= rngState_ << 13;
210 rngState_ ^= rngState_ >> 17;
211 rngState_ ^= rngState_ << 5;
213 constexpr T scale = T(1) /
static_cast<T
>(std::numeric_limits<uint32_t>::max());
214 return static_cast<T
>(rngState_) * scale - T(0.5);
217 int targetBits_ = 16;
218 T quantStep_ = T(1) / T(32768);
219 T quantScale_ = T(32768);
220 T loLevel_ = T(-32768);
221 T hiLevel_ = T(32767);
222 T errorCap_ = T(2) / T(32768);
223 bool noiseShaping_ =
false;
225 std::array<T, kMaxChannels> errorState_{};