56 std::uint64_t& bytes)
noexcept {
57 const auto bins =
static_cast<std::uint64_t
>(fft_size / 2 + 1);
60 analysis_config.
order = fft_size / 16;
61 std::uint64_t analysis_bytes = 0;
63 if (!charge.
add<SampleType>(bins) || !charge.
add<SampleType>(bins) ||
65 analysis_config, target_max_bytes, analysis_bytes) ||
68 bytes = charge.
total();
77 auto effective_config = config;
78 if (!std::isfinite(effective_config.max_gain_db) || effective_config.max_gain_db < 0.0f)
80 if (effective_config.order <= 0)
81 effective_config.order = effective_config.fft_size / 16;
83 analysis_config.
fft_size = effective_config.fft_size;
84 analysis_config.
order = effective_config.order;
88 const auto analysis_status = next_analyzer.
prepare(analysis_config);
90 return analysis_status;
92 const auto commit = [&]() {
93 const auto next_num_bins = effective_config.fft_size / 2 + 1;
94 std::vector<SampleType> next_log_mag(
static_cast<size_t>(next_num_bins), SampleType{0});
95 std::vector<SampleType> next_envelope(
static_cast<size_t>(next_num_bins),
97 config_ = effective_config;
98 num_bins_ = next_num_bins;
99 envelope_analyzer_ = std::move(next_analyzer);
100 log_mag_ = std::move(next_log_mag);
101 envelope_ = std::move(next_envelope);
102 max_gain_ln_ =
static_cast<SampleType
>(effective_config.max_gain_db * 0.1151293f);
105#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
108 }
catch (
const std::bad_alloc&) {
110 }
catch (
const std::length_error&) {
122 return config_.order;
131 assert(channels >= 1);
132 if (!std::isfinite(warp) || warp <= SampleType{0})
134 if (warp == SampleType{1})
144 SampleType max_power = SampleType{0};
145 double energy_before = 0.0;
146 for (
int k = 0; k < num_bins_; ++k) {
147 SampleType power = SampleType{0};
148 for (
int ch = 0; ch < channels; ++ch) {
149 const SampleType re = frames[ch][k].real();
150 const SampleType im = frames[ch][k].imag();
151 power += re * re + im * im;
153 energy_before +=
static_cast<double>(power);
154 log_mag_[
static_cast<size_t>(k)] = power /
static_cast<SampleType
>(channels);
155 max_power = std::max(max_power, log_mag_[
static_cast<size_t>(k)]);
157 const SampleType floor_power =
158 std::max(max_power *
static_cast<SampleType
>(1
e-4),
static_cast<SampleType
>(1
e-24));
159 for (
int k = 0; k < num_bins_; ++k)
160 log_mag_[
static_cast<size_t>(k)] =
161 static_cast<SampleType
>(0.5) *
162 std::log(std::max(log_mag_[
static_cast<size_t>(k)], floor_power));
164 const auto envelope_result = envelope_analyzer_.estimate(log_mag_, envelope_);
165 assert(envelope_result.ok());
166 if (!envelope_result.ok())
171 double energy_after = 0.0;
172 for (
int k = 0; k < num_bins_; ++k) {
173 const SampleType pos =
174 std::min(
static_cast<SampleType
>(k) * warp,
static_cast<SampleType
>(num_bins_ - 1));
175 const int i0 =
static_cast<int>(pos);
176 const int i1 = std::min(i0 + 1, num_bins_ - 1);
177 const SampleType frac = pos -
static_cast<SampleType
>(i0);
178 const SampleType warped = envelope_[
static_cast<size_t>(i0)] * (SampleType{1} - frac) +
179 envelope_[
static_cast<size_t>(i1)] * frac;
180 SampleType gain_ln = warped - envelope_[
static_cast<size_t>(k)];
181 gain_ln = std::clamp(gain_ln, -max_gain_ln_, max_gain_ln_);
182 const SampleType gain = std::exp(gain_ln);
183 for (
int ch = 0; ch < channels; ++ch) {
184 frames[ch][k] *= gain;
185 energy_after +=
static_cast<double>(std::norm(frames[ch][k]));
205 constexpr double kEnergyFloor = 1
e-9;
206 if (energy_after > kEnergyFloor && energy_before > kEnergyFloor) {
207 SampleType norm =
static_cast<SampleType
>(std::sqrt(energy_before / energy_after));
214 norm = std::clamp(norm,
static_cast<SampleType
>(1.0 / 256.0),
215 static_cast<SampleType
>(256.0));
216 if (std::isfinite(
static_cast<double>(norm))) {
217 for (
int k = 0; k < num_bins_; ++k)
218 for (
int ch = 0; ch < channels; ++ch)
219 frames[ch][k] *= norm;
228 SampleType max_gain_ln_ =
static_cast<SampleType
>(6.9);
230 std::vector<SampleType> log_mag_;
231 std::vector<SampleType> envelope_;
Log-magnitude spectrum to liftered log-envelope.
Definition source_filter_analysis.hpp:83
SourceFilterAnalysisStatus prepare(const Config &config)
Definition source_filter_analysis.hpp:107
static bool checked_retained_bytes(const Config &config, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition source_filter_analysis.hpp:90
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
bool add_retained_bytes(std::uint64_t bytes) noexcept
Definition checked_allocation.hpp:78
Definition spectral_envelope_shifter.hpp:51
int order() const
Definition spectral_envelope_shifter.hpp:121
void process_group(std::complex< SampleType > *const *frames, int channels, int num_bins, SampleType warp)
Estimate the group envelope and rescale all channels' bins by E(k * warp) / E(k).
Definition spectral_envelope_shifter.hpp:128
int num_bins() const
Definition spectral_envelope_shifter.hpp:118
static bool checked_retained_bytes(int fft_size, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition spectral_envelope_shifter.hpp:55
SourceFilterAnalysisStatus prepare(const SpectralEnvelopeShifterConfig &config)
RT contract: prepare() allocates FFT and scratch/envelope storage and is not audio-thread safe.
Definition spectral_envelope_shifter.hpp:76
SpectralEnvelopeShifterT()=default
Definition additive_bank.hpp:218
SourceFilterAnalysisStatus
Definition source_filter_analysis.hpp:28
@ InvalidGain
Definition source_filter_analysis.hpp:46
@ Ok
Definition source_filter_analysis.hpp:29
@ AllocationFailure
Definition source_filter_analysis.hpp:38
@ e
Definition formant_filter_bank.hpp:20
SpectralEnvelopeShifterT< double > SpectralEnvelopeShifter64
Definition spectral_envelope_shifter.hpp:235
SpectralEnvelopeShifterT< float > SpectralEnvelopeShifter
Definition spectral_envelope_shifter.hpp:234
Prepared, allocation-free spectral-envelope and linear-prediction analysis.
Definition source_filter_analysis.hpp:60
int true_envelope_iterations
Definition source_filter_analysis.hpp:65
int fft_size
Definition source_filter_analysis.hpp:63
SampleType convergence_tolerance
Maximum remaining positive log-magnitude residual.
Definition source_filter_analysis.hpp:68
int order
Definition source_filter_analysis.hpp:64
Definition spectral_envelope_shifter.hpp:38
int fft_size
Definition spectral_envelope_shifter.hpp:39
int order
Cepstral cutoff (quefrency bins kept).
Definition spectral_envelope_shifter.hpp:42
float max_gain_db
Finite, nonnegative gain clamp for the applied correction, in dB (safety bound for degenerate envelop...
Definition spectral_envelope_shifter.hpp:48
int true_envelope_iterations
True-envelope refinement passes (0 = plain liftering).
Definition spectral_envelope_shifter.hpp:45