28template <
typename SampleType =
float>
31 static_assert(std::is_floating_point_v<SampleType>);
36 if (!std::isfinite(threshold) || threshold < SampleType{0})
return false;
37 threshold_magnitude_ = threshold;
48 bool process(std::complex<SampleType>*
const* frames,
int channels,
int num_bins,
49 const SampleType* thresholds =
nullptr) noexcept {
50 if (frames ==
nullptr || channels <= 0 || num_bins <= 0)
return false;
51 for (
int ch = 0; ch < channels; ++ch)
52 if (frames[ch] ==
nullptr)
return false;
53 if (thresholds !=
nullptr) {
54 for (
int bin = 0; bin < num_bins; ++bin) {
55 if (!std::isfinite(thresholds[bin])
56 || thresholds[bin] < SampleType{0})
61 for (
int ch = 0; ch < channels; ++ch) {
62 for (
int bin = 0; bin < num_bins; ++bin) {
63 auto& value = frames[ch][bin];
64 if (!std::isfinite(value.real()) || !std::isfinite(value.imag())) {
68 const SampleType threshold =
69 thresholds !=
nullptr ? thresholds[bin] : threshold_magnitude_;
70 if (std::abs(value) < threshold) value = {};
77 SampleType threshold_magnitude_ = SampleType{0};
80template <
typename SampleType =
float>
83 static_assert(std::is_floating_point_v<SampleType>);
90 std::uint64_t target_max_bytes,
91 std::uint64_t& bytes)
noexcept {
97 std::uint64_t frame_elements = 0;
98 std::uint64_t history_elements = 0;
100 static_cast<std::uint64_t
>(
num_bins),
101 std::numeric_limits<std::uint64_t>::max(),
105 std::numeric_limits<std::uint64_t>::max(),
110 if (!charge.
add<SampleType>(history_elements)
111 || !charge.
add<SampleType>(frame_elements)
112 || !charge.
add<std::uint16_t>(frame_elements)
113 || !charge.
add<std::complex<SampleType>>(frame_elements))
115 bytes = charge.
total();
121 std::uint64_t ignored = 0;
134 const auto frame_elements =
static_cast<std::size_t
>(
channels)
135 *
static_cast<std::size_t
>(
num_bins);
136 std::vector<SampleType> new_history(
137 frame_elements *
static_cast<std::size_t
>(
blur_frames), SampleType{0});
138 std::vector<SampleType> new_means(frame_elements, SampleType{0});
139 std::vector<std::uint16_t> new_nonzero_counts(frame_elements, 0);
140 std::vector<std::complex<SampleType>> new_phases(
141 frame_elements, std::complex<SampleType>{SampleType{1}, SampleType{0}});
143 history_.swap(new_history);
144 means_.swap(new_means);
145 nonzero_counts_.swap(new_nonzero_counts);
146 phases_.swap(new_phases);
158 std::fill(history_.begin(), history_.end(), SampleType{0});
159 std::fill(means_.begin(), means_.end(), SampleType{0});
160 std::fill(nonzero_counts_.begin(), nonzero_counts_.end(), std::uint16_t{0});
161 std::fill(phases_.begin(), phases_.end(),
162 std::complex<SampleType>{SampleType{1}, SampleType{0}});
174 || blur_frames_ <= 0)
176 for (
int ch = 0; ch < channels_; ++ch)
177 if (frames[ch] ==
nullptr)
return false;
179 const auto frame_elements =
static_cast<std::size_t
>(channels_)
180 *
static_cast<std::size_t
>(num_bins_);
181 const auto history_offset =
static_cast<std::size_t
>(write_frame_)
183 const bool history_full = filled_frames_ >= blur_frames_;
184 const auto divisor =
static_cast<SampleType
>(
185 std::min(filled_frames_ + 1, blur_frames_));
187 for (
int ch = 0; ch < channels_; ++ch) {
188 for (
int bin = 0; bin < num_bins_; ++bin) {
189 const auto index =
static_cast<std::size_t
>(ch)
190 *
static_cast<std::size_t
>(num_bins_)
191 +
static_cast<std::size_t
>(bin);
192 auto& value = frames[ch][bin];
193 SampleType magnitude = SampleType{0};
194 if (std::isfinite(value.real()) && std::isfinite(value.imag())) {
195 const SampleType real = value.real();
196 const SampleType imag = value.imag();
197 const SampleType scale = std::max(std::abs(real), std::abs(imag));
198 if (scale > SampleType{0}) {
199 const SampleType scaled_real = real / scale;
200 const SampleType scaled_imag = imag / scale;
201 const SampleType scaled_magnitude =
202 std::hypot(scaled_real, scaled_imag);
203 phases_[index] = {scaled_real / scaled_magnitude,
204 scaled_imag / scaled_magnitude};
206 std::numeric_limits<SampleType>::max();
207 magnitude = scale >
maximum / scaled_magnitude
209 : scale * scaled_magnitude;
213 auto& old_magnitude = history_[history_offset + index];
214 if (old_magnitude > SampleType{0}) --nonzero_counts_[index];
215 if (magnitude > SampleType{0}) ++nonzero_counts_[index];
216 auto& mean = means_[index];
218 mean = std::fma(SampleType{1} / divisor,
219 magnitude - old_magnitude, mean);
221 mean += (magnitude - mean) / divisor;
222 if (nonzero_counts_[index] == 0)
223 mean = SampleType{0};
224 else if (!std::isfinite(mean))
225 mean = std::numeric_limits<SampleType>::max();
226 old_magnitude = magnitude;
227 value = phases_[index] * std::max(mean, SampleType{0});
231 write_frame_ = (write_frame_ + 1) % blur_frames_;
232 if (filled_frames_ < blur_frames_) ++filled_frames_;
236 int channels() const noexcept {
return channels_; }
237 int num_bins() const noexcept {
return num_bins_; }
245 int blur_frames_ = 0;
246 int write_frame_ = 0;
247 int filled_frames_ = 0;
248 std::uint64_t retained_bytes_ = 0;
249 std::vector<SampleType> history_;
250 std::vector<SampleType> means_;
251 std::vector<std::uint16_t> nonzero_counts_;
252 std::vector<std::complex<SampleType>> phases_;
Definition checked_allocation.hpp:57
bool add(std::uint64_t elements) noexcept
Definition checked_allocation.hpp:63
std::uint64_t total() const noexcept
Definition checked_allocation.hpp:83
Definition spectral_gate_blur.hpp:81
static constexpr int maximum_channels
Definition spectral_gate_blur.hpp:85
bool prepare(int channels, int num_bins, int blur_frames)
Allocate fixed history off the audio thread.
Definition spectral_gate_blur.hpp:128
int filled_frames() const noexcept
Definition spectral_gate_blur.hpp:239
static bool checked_retained_bytes(int channels, int num_bins, int blur_frames, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition spectral_gate_blur.hpp:89
void reset() noexcept
Clear the finite history without changing prepared capacity.
Definition spectral_gate_blur.hpp:157
int blur_frames() const noexcept
Definition spectral_gate_blur.hpp:238
std::uint64_t retained_bytes() const noexcept
Definition spectral_gate_blur.hpp:240
bool process(std::complex< SampleType > *const *frames, int channels, int num_bins) noexcept
Apply a causal box blur across at most blur_frames() analysis frames.
Definition spectral_gate_blur.hpp:171
static bool supports_configuration(int channels, int num_bins, int blur_frames) noexcept
Definition spectral_gate_blur.hpp:119
int num_bins() const noexcept
Definition spectral_gate_blur.hpp:237
static constexpr int maximum_frames
Definition spectral_gate_blur.hpp:87
int channels() const noexcept
Definition spectral_gate_blur.hpp:236
static constexpr int maximum_bins
Definition spectral_gate_blur.hpp:86
Definition spectral_gate_blur.hpp:29
bool set_threshold_magnitude(SampleType threshold) noexcept
Set the scalar linear-magnitude threshold.
Definition spectral_gate_blur.hpp:35
bool process(std::complex< SampleType > *const *frames, int channels, int num_bins, const SampleType *thresholds=nullptr) noexcept
Gate a coherent channel group in place.
Definition spectral_gate_blur.hpp:48
SampleType threshold_magnitude() const noexcept
Definition spectral_gate_blur.hpp:41
Definition additive_bank.hpp:218
SpectralFrameBlurT< double > SpectralFrameBlur64
Definition spectral_gate_blur.hpp:258
bool checked_capacity_product(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &product) noexcept
Definition checked_allocation.hpp:12
SpectralFrameBlurT< float > SpectralFrameBlur
Definition spectral_gate_blur.hpp:257
@ maximum
Definition spectrum_trace.hpp:34
constexpr std::uint64_t kTargetAddressMaximumBytes
Definition checked_allocation.hpp:9
SpectralGateT< double > SpectralGate64
Definition spectral_gate_blur.hpp:256
SpectralGateT< float > SpectralGate
Definition spectral_gate_blur.hpp:255