Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
realtime_pitch_time_geometry.hpp
Go to the documentation of this file.
1#pragma once
2
7
16
17#include <algorithm>
18#include <cmath>
19#include <complex>
20#include <cstdint>
21#include <limits>
22
23namespace pulp::signal {
24
27enum class FormantMode { follow, preserve };
28
44
49
60
78
79inline constexpr int kRealtimePitchTimeMaximumChannels = 64;
80
81template <typename SampleType>
97
100template <typename SampleType>
102 const RealtimePitchTimeConfig& config, double max_pitch_ratio,
103 std::uint64_t requested_max_bytes,
105 const auto target_max_bytes = std::min(requested_max_bytes, kTargetAddressMaximumBytes);
106 if (config.true_envelope_iterations < 0 ||
107 config.true_envelope_iterations > kSourceFilterMaximumEnvelopeIterations)
109 if (config.mode == PitchTimeMode::time_stretch
110 && (!std::isfinite(config.max_time_ratio) || config.max_time_ratio < 1.0f))
112 const bool quality = config.quality == PitchTimeQuality::quality;
113 int fft_size = quality ? 4096 : 1024;
114 int analysis_hop = quality ? 512 : 256;
115 if (config.fft_size != 0 || config.analysis_hop != 0) {
116 if (!is_valid_spectral_frame_geometry(config.fft_size, config.analysis_hop)
117 || (config.fft_size % config.analysis_hop) != 0)
119 fft_size = config.fft_size;
120 analysis_hop = config.analysis_hop;
121 }
122
123 const double max_stretch = config.mode == PitchTimeMode::time_stretch
124 ? static_cast<double>(config.max_time_ratio)
125 : max_pitch_ratio;
126 const double synthesis_hop =
127 std::ceil(max_stretch * static_cast<double>(analysis_hop)) + 1.0;
128 if (!std::isfinite(synthesis_hop)
129 || synthesis_hop > static_cast<double>(std::numeric_limits<int>::max()))
131
133 candidate.fft_size = fft_size;
134 candidate.analysis_hop = analysis_hop;
135 candidate.engine_config = {fft_size, analysis_hop, config.channels,
136 std::max(config.max_block, analysis_hop),
137 static_cast<int>(synthesis_hop)};
138 // The processor maps analysis frame k to input time k * analysis_hop for
139 // its stretched-output frame map and its priming contract, so it keeps the
140 // frame grid anchored at the first input sample.
141 candidate.engine_config.full_overlap_stream_start = false;
142 if (config.mode == PitchTimeMode::time_stretch) {
143 // A causal driver cannot publish final output until the spectral
144 // analysis window has advanced through its priming span. Once primed,
145 // output is published in synthesis-hop quanta, so reserve one complete
146 // maximum hop beyond that span. Express the result in output samples:
147 // the upper symmetric ratio endpoint is the worst case.
148 const long double lag =
149 static_cast<long double>(fft_size + analysis_hop)
150 * static_cast<long double>(config.max_time_ratio)
151 + static_cast<long double>(candidate.engine_config.max_synthesis_hop);
152 if (!std::isfinite(lag)
153 || lag > static_cast<long double>(std::numeric_limits<int>::max()))
155 candidate.maximum_stream_output_lag_samples =
156 static_cast<int>(std::ceil(lag));
157 }
158 const auto engine_geometry = checked_spectral_frame_engine_geometry<SampleType>(
159 candidate.engine_config, target_max_bytes);
160 if (!engine_geometry) return PitchTimePrepareStatus::unrepresentable_capacity;
161
162 const std::int64_t span_base = static_cast<std::int64_t>(fft_size)
163 + 2 * static_cast<std::int64_t>(analysis_hop)
164 + candidate.engine_config.max_block;
165 const long double span = static_cast<long double>(span_base)
166 * static_cast<long double>(std::max(max_stretch, 1.0))
167 + static_cast<long double>(fft_size) + 64.0L;
168 if (!std::isfinite(span)
169 || span > static_cast<long double>(kSpectralFrameEngineMaximumRingSize))
171 std::uint64_t ring_size = 1;
172 const auto required_ring_size = static_cast<std::uint64_t>(std::ceil(span));
173 while (ring_size < required_ring_size) ring_size <<= 1u;
174 candidate.ring_size = static_cast<int>(ring_size);
175
176 const auto channels = static_cast<std::uint64_t>(config.channels);
177 const auto bins = static_cast<std::uint64_t>(fft_size / 2 + 1);
178 std::uint64_t channel_hop_elements = 0;
179 if (!checked_capacity_product(channels, ring_size, UINT64_MAX,
180 candidate.stretch_ring_elements)
182 channels, static_cast<std::uint64_t>(candidate.engine_config.max_synthesis_hop),
183 UINT64_MAX, channel_hop_elements)
184 || !checked_capacity_product(channel_hop_elements, 4u, UINT64_MAX,
185 candidate.drain_elements)
187 channels, static_cast<std::uint64_t>(candidate.engine_config.max_block), UINT64_MAX,
188 candidate.finalize_zero_elements))
190
191 CheckedRetainedByteCharge charge(target_max_bytes);
192 if (!charge.add_retained_bytes(engine_geometry->retained_bytes)
193 || !charge.add<SampleType>(candidate.stretch_ring_elements)
194 || !charge.add<SampleType>(candidate.drain_elements)
195 || !charge.add<SampleType>(candidate.finalize_zero_elements)
196 || !charge.add<SampleType*>(channels) || !charge.add<const SampleType*>(channels))
198
199 std::uint64_t component_bytes = 0;
200 const auto component_fits = [&charge, &component_bytes](bool valid) noexcept {
201 return valid && charge.add_retained_bytes(component_bytes);
202 };
203 typename FreezeHoldT<SampleType>::Config freeze_config;
204 freeze_config.fft_size = fft_size;
205 freeze_config.channels = config.channels;
206 freeze_config.analysis_hop = analysis_hop;
207 if (!component_fits(
209 fft_size, target_max_bytes, component_bytes))
210 || !component_fits(
212 fft_size, target_max_bytes, component_bytes))
213 || !component_fits(
215 freeze_config, target_max_bytes, component_bytes))
216 || !component_fits(
218 fft_size, target_max_bytes, component_bytes)))
220
221 if (config.noise_morphing) {
222 StnConfig stn_config;
223 stn_config.num_bins = static_cast<int>(bins);
224 stn_config.time_median = quality ? 7 : 5;
225 stn_config.freq_median = quality ? 11 : 7;
226 if (!component_fits(
228 stn_config, target_max_bytes, component_bytes)))
230 std::uint64_t morpher_bytes = 0;
231 std::uint64_t all_morpher_bytes = 0;
233 static_cast<int>(bins), target_max_bytes, morpher_bytes)
234 || !checked_capacity_product(morpher_bytes, channels, UINT64_MAX,
235 all_morpher_bytes)
236 || !charge.add<NoiseMorpherT<SampleType>>(channels)
237 || !charge.add_retained_bytes(all_morpher_bytes)
238 || !charge.add<SampleType>(bins) || !charge.add<SampleType>(channels * bins)
239 || !charge.add<std::complex<SampleType>>(bins))
241 }
242 if (config.sinc_resampling) {
243 if (!component_fits(
245 16, 512, target_max_bytes, component_bytes))
246 || !charge.add<SampleType>(32u))
248 }
249
250 candidate.retained_bytes = charge.total();
251 prepared = candidate;
253}
254
255} // namespace pulp::signal
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
static bool checked_retained_bytes(const Config &requested, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition freeze_hold.hpp:489
static bool checked_retained_bytes(int fft_size, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition multichannel_phase_coordinator.hpp:41
RT contract: prepare() and prepare_masked_scratch() allocate storage and must run off the audio threa...
Definition noise_morpher.hpp:42
static bool checked_retained_bytes(int num_bins, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition noise_morpher.hpp:44
static bool checked_retained_bytes(int half_width, int phases, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition sinc_resampler.hpp:39
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
static bool checked_retained_bytes(const StnConfig &config, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition stn_decomposer.hpp:76
static bool checked_retained_bytes(int fft_size, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition transient_phase_policy.hpp:56
Spectral freeze / infinite hold for phase-vocoder frame groups.
Phase-vocoder phase propagation for coherent channel groups.
Definition additive_bank.hpp:218
PitchTimeMode
Definition realtime_pitch_time_geometry.hpp:26
@ realtime_pitch
Definition realtime_pitch_time_geometry.hpp:26
@ time_stretch
Definition realtime_pitch_time_geometry.hpp:26
std::optional< SpectralFrameEngineGeometry > checked_spectral_frame_engine_geometry(const SpectralFrameEngineConfig &config, std::uint64_t target_max_bytes=kTargetAddressMaximumBytes) noexcept
Derive every integer and typed backing-store capacity used by prepare().
Definition spectral_frame_engine.hpp:151
@ backpressure
Definition finite_stretch_builder.hpp:41
bool is_valid_spectral_frame_geometry(int fft_size, int analysis_hop) noexcept
Definition spectral_frame_engine.hpp:108
constexpr int kSourceFilterMaximumEnvelopeIterations
Definition source_filter_analysis.hpp:53
PitchTimeStreamFinalizePlanStatus
Definition realtime_pitch_time_geometry.hpp:37
@ needs_drain
Definition realtime_pitch_time_geometry.hpp:39
@ invalid_mode
Definition realtime_pitch_time_geometry.hpp:41
@ invalid_sample_rate
Definition auto_ducked_send.hpp:18
@ ready
Definition auto_ducked_send.hpp:18
PitchTimeStreamFinalizeStatus
Definition realtime_pitch_time_geometry.hpp:30
@ draining
Definition realtime_pitch_time_geometry.hpp:31
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
PitchTimeQuality
Definition realtime_pitch_time_geometry.hpp:25
@ low_latency
Definition realtime_pitch_time_geometry.hpp:25
@ quality
Definition realtime_pitch_time_geometry.hpp:25
constexpr int kRealtimePitchTimeMaximumChannels
Definition realtime_pitch_time_geometry.hpp:79
constexpr std::uint64_t kTargetAddressMaximumBytes
Definition checked_allocation.hpp:9
@ unrepresentable_capacity
Definition finite_stretch_builder.hpp:26
@ invalid_mode
Definition finite_stretch_builder.hpp:20
@ prepared
Definition finite_stretch_builder.hpp:19
@ complete
Definition finite_stretch_builder.hpp:30
PitchTimePrepareStatus
Definition realtime_pitch_time_geometry.hpp:50
@ unrepresentable_capacity
Definition realtime_pitch_time_geometry.hpp:58
@ invalid_channel_count
Definition realtime_pitch_time_geometry.hpp:53
@ invalid_spectral_geometry
Definition realtime_pitch_time_geometry.hpp:57
@ invalid_max_time_ratio
Definition realtime_pitch_time_geometry.hpp:55
@ prepared
Definition realtime_pitch_time_geometry.hpp:51
@ invalid_max_pitch_semitones
Definition realtime_pitch_time_geometry.hpp:56
@ invalid_max_block
Definition realtime_pitch_time_geometry.hpp:54
PitchTimeStreamFeedStatus
Definition realtime_pitch_time_geometry.hpp:29
@ accepted
Definition realtime_pitch_time_geometry.hpp:29
@ invalid_request
Definition realtime_pitch_time_geometry.hpp:29
@ input_closed
Definition realtime_pitch_time_geometry.hpp:29
constexpr std::uint64_t kSpectralFrameEngineMaximumRingSize
Definition spectral_frame_engine.hpp:95
FormantMode
Definition realtime_pitch_time_geometry.hpp:27
@ follow
Definition realtime_pitch_time_geometry.hpp:27
@ preserve
Definition realtime_pitch_time_geometry.hpp:27
PitchTimePrepareStatus checked_realtime_pitch_time_prepared_geometry(const RealtimePitchTimeConfig &config, double max_pitch_ratio, std::uint64_t requested_max_bytes, RealtimePitchTimePreparedGeometry< SampleType > &prepared) noexcept
Derive all processor geometry and compose the retained-storage contracts of its owned DSP primitives ...
Definition realtime_pitch_time_geometry.hpp:101
Time-stretch the noise component of a sound by morphing, not by phase-vocoder propagation.
Fractional-delay resampling by a Kaiser-windowed sinc kernel.
Spectral-envelope estimation and formant warping for phase-vocoder frame groups.
Streaming STFT analysis + weighted overlap-add (WOLA) synthesis for DSP-grade spectral processing — d...
Sines / Transients / Noise (STN) decomposition of a spectral frame stream by median-filter masking.
Two sizing modes.
Definition freeze_hold.hpp:410
int fft_size
Definition freeze_hold.hpp:411
int analysis_hop
Definition freeze_hold.hpp:413
int channels
Definition freeze_hold.hpp:412
Definition realtime_pitch_time_geometry.hpp:45
int samples
Definition realtime_pitch_time_geometry.hpp:47
PitchTimeStreamFinalizePlanStatus status
Definition realtime_pitch_time_geometry.hpp:46
Definition realtime_pitch_time_geometry.hpp:61
bool transient_preservation
Definition realtime_pitch_time_geometry.hpp:71
FormantMode formant_mode
Definition realtime_pitch_time_geometry.hpp:69
float max_pitch_semitones
Definition realtime_pitch_time_geometry.hpp:66
int max_block
Definition realtime_pitch_time_geometry.hpp:65
int fft_size
Definition realtime_pitch_time_geometry.hpp:75
int channels
Definition realtime_pitch_time_geometry.hpp:64
float max_time_ratio
Definition realtime_pitch_time_geometry.hpp:67
int analysis_hop
Definition realtime_pitch_time_geometry.hpp:76
int true_envelope_iterations
Definition realtime_pitch_time_geometry.hpp:70
float transient_sensitivity
Definition realtime_pitch_time_geometry.hpp:72
PitchTimeQuality quality
Definition realtime_pitch_time_geometry.hpp:63
PitchTimeMode mode
Definition realtime_pitch_time_geometry.hpp:62
bool sinc_resampling
Definition realtime_pitch_time_geometry.hpp:74
bool noise_morphing
Definition realtime_pitch_time_geometry.hpp:73
float pitch_smoothing_seconds
Definition realtime_pitch_time_geometry.hpp:68
Definition realtime_pitch_time_geometry.hpp:82
std::uint64_t finalize_zero_elements
Definition realtime_pitch_time_geometry.hpp:94
std::uint64_t drain_elements
Definition realtime_pitch_time_geometry.hpp:93
int maximum_stream_output_lag_samples
Conservative output-domain delay required by a causal time-stretch stream over the complete admitted ...
Definition realtime_pitch_time_geometry.hpp:91
int ring_size
Definition realtime_pitch_time_geometry.hpp:86
std::uint64_t retained_bytes
Definition realtime_pitch_time_geometry.hpp:95
int fft_size
Definition realtime_pitch_time_geometry.hpp:84
SpectralFrameEngineConfig engine_config
Definition realtime_pitch_time_geometry.hpp:83
int analysis_hop
Definition realtime_pitch_time_geometry.hpp:85
std::uint64_t stretch_ring_elements
Definition realtime_pitch_time_geometry.hpp:92
Configuration for a SpectralFrameEngine.
Definition spectral_frame_engine.hpp:56
Definition stn_decomposer.hpp:39
int freq_median
odd; bins for the vertical (transient) median
Definition stn_decomposer.hpp:42
int num_bins
fft_size/2 + 1
Definition stn_decomposer.hpp:40
int time_median
odd; frames for the horizontal (tonal) median
Definition stn_decomposer.hpp:41
Spectral-flux transient detection for phase-vocoder streams.