47template <
typename SampleType>
49 static_assert(std::is_floating_point_v<SampleType>);
54template <
typename SampleType>
56 static_assert(std::is_floating_point_v<SampleType>);
60 SampleType
max_hz = SampleType{20000};
83template <
typename SampleType>
85 static_assert(std::is_floating_point_v<SampleType>);
96 std::array<std::uint32_t, kSpectralBandMaskMaximumBands>
owned_bins{};
103template <
typename SampleType>
105 static_assert(std::is_floating_point_v<SampleType>);
116 std::array<SampleType, kSpectralBandMaskMaximumBins>
gain_linear{};
121template <
typename SampleType>
124 SampleType& effective_min,
125 SampleType& effective_max)
noexcept {
128 const bool valid_edge_policy =
132 || layout.boundary_kernel
134 if (layout.active_bands == 0
137 || !valid_edge_policy
139 || !std::isfinite(layout.min_hz)
140 || !std::isfinite(layout.max_hz)
141 || !std::isfinite(layout.transition_fraction)
142 || layout.min_hz < SampleType{0}
143 || layout.max_hz <= layout.min_hz
144 || layout.transition_fraction < SampleType{0}
145 || layout.transition_fraction > SampleType{0.5}
149 effective_min = std::clamp(layout.min_hz, SampleType{0}, nyquist);
150 effective_max = std::clamp(layout.max_hz, SampleType{0}, nyquist);
151 if (!(effective_max > effective_min))
return false;
153 && !(effective_min > SampleType{0}))
156 for (std::uint32_t band = 0; band < layout.active_bands; ++band) {
157 const auto gain_db = layout.bands[band].gain_db;
160 if (!std::isfinite(gain_db)
161 || gain_db < SampleType{-192}
162 || gain_db > SampleType{48})
168template <
typename SampleType>
174 return (hz - min_hz) / (max_hz - min_hz);
175 return std::log(hz / min_hz) / std::log(max_hz / min_hz);
178template <
typename SampleType>
184 return min_hz + coordinate * (max_hz - min_hz);
185 return min_hz * std::pow(max_hz / min_hz, coordinate);
188template <
typename SampleType>
190 const auto x = std::clamp(position, SampleType{0}, SampleType{1});
191 constexpr SampleType pi =
192 static_cast<SampleType
>(3.14159265358979323846264338327950288L);
193 return SampleType{0.5} - SampleType{0.5} * std::cos(pi * x);
196template <
typename SampleType>
198 std::uint32_t index)
noexcept {
199 const auto& band = layout.bands[index];
202 : std::pow(SampleType{10}, band.gain_db * SampleType{0.05});
205template <
typename SampleType>
211 std::uint32_t band_count)
noexcept {
212 const SampleType coordinate = std::clamp(
214 SampleType{0}, SampleType{1});
215 const SampleType scaled = coordinate *
static_cast<SampleType
>(band_count);
216 return std::min<std::uint32_t>(
static_cast<std::uint32_t
>(scaled),
227template <
typename SampleType>
231 SampleType sample_rate,
233 static_assert(std::is_floating_point_v<SampleType>);
235 || !std::isfinite(sample_rate)
236 || sample_rate <= SampleType{0})
239 const int num_bins = fft_size / 2 + 1;
244 const SampleType nyquist = sample_rate * SampleType{0.5};
245 SampleType min_hz = SampleType{0};
246 SampleType max_hz = SampleType{0};
251 candidate.fft_size = fft_size;
252 candidate.num_bins = num_bins;
253 candidate.sample_rate = sample_rate;
254 candidate.bin_width_hz = sample_rate /
static_cast<SampleType
>(fft_size);
255 candidate.effective_min_hz = min_hz;
256 candidate.effective_max_hz = max_hz;
257 candidate.active_bands = layout.active_bands;
259 for (
int bin = 0; bin < num_bins; ++bin) {
260 const SampleType hz =
static_cast<SampleType
>(bin)
261 * candidate.bin_width_hz;
262 if (hz < min_hz || hz > max_hz)
continue;
264 hz, min_hz, max_hz, layout.spacing, layout.active_bands);
265 ++candidate.owned_bins[band];
266 ++candidate.viewport_bins;
268 for (std::uint32_t band = 0; band < layout.active_bands; ++band)
269 if (candidate.owned_bins[band] > 0) ++candidate.represented_bands;
271 out_resolution = candidate;
278template <
typename SampleType>
281 SampleType sample_rate,
283 static_assert(std::is_floating_point_v<SampleType>);
285 || !std::isfinite(sample_rate)
286 || sample_rate <= SampleType{0})
289 const int num_bins = fft_size / 2 + 1;
294 const SampleType nyquist = sample_rate * SampleType{0.5};
295 SampleType min_hz = SampleType{0};
296 SampleType max_hz = SampleType{0};
301 candidate.fft_size = fft_size;
302 candidate.num_bins = num_bins;
303 candidate.sample_rate = sample_rate;
304 candidate.effective_min_hz = min_hz;
305 candidate.effective_max_hz = max_hz;
306 candidate.active_bands = layout.active_bands;
307 candidate.transition_frames = layout.transition_frames;
308 candidate.version = layout.version;
310 const auto band_count = layout.active_bands;
311 for (std::uint32_t edge = 0; edge <= band_count; ++edge) {
312 const auto coordinate =
static_cast<SampleType
>(edge)
313 /
static_cast<SampleType
>(band_count);
315 coordinate, min_hz, max_hz, layout.spacing);
318 const SampleType half_width = layout.transition_fraction
319 /
static_cast<SampleType
>(band_count);
320 const bool smooth = layout.boundary_kernel
322 && half_width > SampleType{0};
324 for (
int bin = 0; bin < num_bins; ++bin) {
325 const SampleType hz = (
static_cast<SampleType
>(bin)
326 /
static_cast<SampleType
>(fft_size)) * sample_rate;
327 SampleType gain = SampleType{0};
333 }
else if (hz > max_hz) {
338 const SampleType coordinate = std::clamp(
340 SampleType{0}, SampleType{1});
341 const SampleType scaled = coordinate *
static_cast<SampleType
>(band_count);
343 hz, min_hz, max_hz, layout.spacing, band_count);
348 const auto boundary_index =
static_cast<std::uint32_t
>(
349 std::floor(scaled + SampleType{0.5}));
350 if (boundary_index > 0 && boundary_index < band_count) {
351 const SampleType boundary =
static_cast<SampleType
>(boundary_index)
352 /
static_cast<SampleType
>(band_count);
353 if (std::abs(coordinate - boundary) <= half_width) {
356 const auto position = (coordinate - (boundary - half_width))
357 / (SampleType{2} * half_width);
362 if (coordinate <= half_width) {
364 (coordinate + half_width) / (SampleType{2} * half_width));
366 }
else if (coordinate >= SampleType{1} - half_width) {
368 (coordinate - (SampleType{1} - half_width))
369 / (SampleType{2} * half_width));
371 * (SampleType{1} - mix);
376 candidate.gain_linear[
static_cast<std::size_t
>(bin)] = gain;
379 out_table = candidate;
386template <
typename SampleType>
391 static_assert(std::is_floating_point_v<SampleType>);
392 if (frames ==
nullptr || channels <= 0 || num_bins <= 0
393 || table.num_bins != num_bins
396 || table.fft_size / 2 + 1 != num_bins
397 || !std::isfinite(table.sample_rate)
398 || table.sample_rate <= SampleType{0}
401 for (
int channel = 0; channel < channels; ++channel)
402 if (frames[channel] ==
nullptr)
return false;
403 for (
int bin = 0; bin < num_bins; ++bin) {
404 const auto gain = table.gain_linear[
static_cast<std::size_t
>(bin)];
405 if (!std::isfinite(gain) || gain < SampleType{0})
return false;
408 for (
int channel = 0; channel < channels; ++channel) {
409 for (
int bin = 0; bin < num_bins; ++bin) {
410 auto& value = frames[channel][bin];
411 if (!std::isfinite(value.real()) || !std::isfinite(value.imag()))
414 const auto gain = table.gain_linear[
static_cast<std::size_t
>(bin)];
415 if (gain == SampleType{0}) {
419 const auto maximum = std::numeric_limits<SampleType>::max();
420 const auto limit =
maximum / gain;
421 const auto scale_component = [gain, limit,
maximum](SampleType component) {
422 return std::abs(component) > limit
423 ? std::copysign(
maximum, component)
426 value = {scale_component(value.real()), scale_component(value.imag())};
SampleType band_gain(const SpectralBandLayoutT< SampleType > &layout, std::uint32_t index) noexcept
Definition spectral_band_mask.hpp:197
SampleType band_coordinate(SampleType hz, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing) noexcept
Definition spectral_band_mask.hpp:169
bool valid_spectral_band_layout(const SpectralBandLayoutT< SampleType > &layout, SampleType nyquist, SampleType &effective_min, SampleType &effective_max) noexcept
Definition spectral_band_mask.hpp:122
SampleType frequency_at_coordinate(SampleType coordinate, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing) noexcept
Definition spectral_band_mask.hpp:179
SampleType raised_cosine(SampleType position) noexcept
Definition spectral_band_mask.hpp:189
std::uint32_t band_index_at_frequency(SampleType hz, SampleType min_hz, SampleType max_hz, SpectralBandSpacing spacing, std::uint32_t band_count) noexcept
Definition spectral_band_mask.hpp:206
Definition additive_bank.hpp:218
constexpr std::uint32_t kSpectralBandMaskMaximumTransitionFrames
Definition spectral_band_mask.hpp:30
SpectralMaskBoundaryKernel
Definition spectral_band_mask.hpp:42
@ raised_cosine
Definition spectral_band_mask.hpp:44
@ hard
Definition spectral_band_mask.hpp:43
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
bool apply_spectral_mask(std::complex< SampleType > *const *frames, int channels, int num_bins, const SpectralMaskTableT< SampleType > &table) noexcept
Multiply one coherent positive-frequency frame group by a prepared mask.
Definition spectral_band_mask.hpp:387
SpectralMaskTableT< float > SpectralMaskTable
Definition spectral_band_mask.hpp:439
bool is_valid_spectral_frame_geometry(int fft_size, int analysis_hop) noexcept
Definition spectral_frame_engine.hpp:108
SpectralBandResolutionT< double > SpectralBandResolution64
Definition spectral_band_mask.hpp:438
SpectralBandEdgePolicy
Definition spectral_band_mask.hpp:37
@ extend_edge_band
Definition spectral_band_mask.hpp:39
@ mute_outside
Definition spectral_band_mask.hpp:38
SpectralBandLayoutT< float > SpectralBandLayout
Definition spectral_band_mask.hpp:435
SpectralBandResolutionT< float > SpectralBandResolution
Definition spectral_band_mask.hpp:437
bool analyze_spectral_band_resolution(const SpectralBandLayoutT< SampleType > &layout, int fft_size, SampleType sample_rate, SpectralBandResolutionT< SampleType > &out_resolution) noexcept
Report the number of discrete FFT bin centers directly owned by each band.
Definition spectral_band_mask.hpp:228
constexpr int kSpectralFrameEngineMaximumFftSize
Definition spectral_frame_engine.hpp:94
constexpr std::size_t kSpectralBandMaskMaximumBins
Definition spectral_band_mask.hpp:28
@ logarithmic
Definition modulation_curve.hpp:29
SpectralBandT< float > SpectralBand
Definition spectral_band_mask.hpp:433
bool build_spectral_mask(const SpectralBandLayoutT< SampleType > &layout, int fft_size, SampleType sample_rate, SpectralMaskTableT< SampleType > &out_table) noexcept
Compile a complete positive-frequency gain table.
Definition spectral_band_mask.hpp:279
SpectralMaskTableT< double > SpectralMaskTable64
Definition spectral_band_mask.hpp:440
@ maximum
Definition spectrum_trace.hpp:34
SpectralBandSpacing
Definition spectral_band_mask.hpp:32
@ logarithmic
Definition spectral_band_mask.hpp:34
@ linear
Definition spectral_band_mask.hpp:33
constexpr int kSpectralFrameEngineMinimumFftSize
Definition spectral_frame_engine.hpp:93
@ linear
2-point. Cheapest; audible imaging when pitching up.
Definition granular.hpp:133
constexpr std::size_t kSpectralBandMaskMaximumBands
Definition spectral_band_mask.hpp:27
SpectralBandT< double > SpectralBand64
Definition spectral_band_mask.hpp:434
SpectralBandLayoutT< double > SpectralBandLayout64
Definition spectral_band_mask.hpp:436
Streaming STFT analysis + weighted overlap-add (WOLA) synthesis for DSP-grade spectral processing — d...
Definition spectral_band_mask.hpp:55
float max_hz
Definition spectral_band_mask.hpp:60
float min_hz
Definition spectral_band_mask.hpp:59
float transition_fraction
Definition spectral_band_mask.hpp:69
SpectralBandEdgePolicy edge_policy
Definition spectral_band_mask.hpp:62
std::uint64_t version
Definition spectral_band_mask.hpp:74
SpectralBandSpacing spacing
Definition spectral_band_mask.hpp:61
std::uint32_t transition_frames
Definition spectral_band_mask.hpp:73
std::array< SpectralBandT< float >, kSpectralBandMaskMaximumBands > bands
Definition spectral_band_mask.hpp:75
std::uint32_t active_bands
Definition spectral_band_mask.hpp:58
SpectralMaskBoundaryKernel boundary_kernel
Definition spectral_band_mask.hpp:63
Control-side report of how discrete FFT bin centers represent an authored viewport.
Definition spectral_band_mask.hpp:84
int fft_size
Definition spectral_band_mask.hpp:87
float sample_rate
Definition spectral_band_mask.hpp:89
std::uint32_t viewport_bins
Definition spectral_band_mask.hpp:95
float effective_max_hz
Definition spectral_band_mask.hpp:92
float effective_min_hz
Definition spectral_band_mask.hpp:91
std::uint32_t represented_bands
Definition spectral_band_mask.hpp:94
std::array< std::uint32_t, kSpectralBandMaskMaximumBands > owned_bins
Definition spectral_band_mask.hpp:96
float bin_width_hz
Definition spectral_band_mask.hpp:90
std::uint32_t active_bands
Definition spectral_band_mask.hpp:93
bool fully_represented() const noexcept
Definition spectral_band_mask.hpp:98
int num_bins
Definition spectral_band_mask.hpp:88
Definition spectral_band_mask.hpp:48
bool muted
Definition spectral_band_mask.hpp:51
float gain_db
Definition spectral_band_mask.hpp:50
Definition spectral_band_mask.hpp:104
std::array< float, kSpectralBandMaskMaximumBins > gain_linear
Definition spectral_band_mask.hpp:116
std::uint32_t transition_frames
Definition spectral_band_mask.hpp:113
float sample_rate
Definition spectral_band_mask.hpp:109
std::array< float, kSpectralBandMaskMaximumBands+1 > band_edges_hz
Definition spectral_band_mask.hpp:115
float effective_max_hz
Definition spectral_band_mask.hpp:111
std::uint32_t active_bands
Definition spectral_band_mask.hpp:112
int num_bins
Definition spectral_band_mask.hpp:108
float effective_min_hz
Definition spectral_band_mask.hpp:110
std::uint64_t version
Definition spectral_band_mask.hpp:114
int fft_size
Definition spectral_band_mask.hpp:107