52 const auto fft_size =
static_cast<std::uint64_t
>(
53 config.fft_size > 0 ? config.fft_size : (
quality ? 4096 : 1024));
54 const auto analysis_hop =
static_cast<std::uint64_t
>(
55 config.analysis_hop > 0 ? config.analysis_hop : (
quality ? 512 : 256));
56 const auto signed_max =
static_cast<std::uint64_t
>(
57 std::numeric_limits<std::int64_t>::max());
58 std::uint64_t eof_padding = 0;
59 std::uint64_t padded_input = 0;
64 const long double maximum_hop_value =
65 std::ceil(
static_cast<long double>(config.max_time_ratio)
66 *
static_cast<long double>(analysis_hop)) + 1.0L;
67 if (!std::isfinite(maximum_hop_value)
68 || maximum_hop_value >
static_cast<long double>(std::numeric_limits<int>::max()))
70 std::uint64_t frame_count = 0;
71 std::uint64_t maximum_output = 0;
73 2u, signed_max, frame_count)
75 static_cast<std::uint64_t
>(maximum_hop_value),
76 signed_max, maximum_output))
89 float (*)(
void* context, std::uint64_t input_frame)
noexcept;
91template <
typename SampleType =
float>
95 const SampleType*
const*
input =
nullptr;
106template <
typename SampleType =
float>
117 drain_before_pending_ =
false;
122 prepare_status_ = validate(config);
125 processor_prepare_status_ =
126 processor_.prepare(config.sample_rate, config.processor, config.target_max_bytes);
129 return prepare_status_;
133 return prepare_status_;
144 if (drain_before_pending_)
return drain_one();
145 if (pending_.kind != PendingKind::none)
return execute_pending();
146 if (input_consumed_ < config_.input_frames)
return begin_feed();
147 return finalize_one();
152 return processor_prepare_status_;
165 if (config.processor.channels < 1
168 if (config.input_frames > 0 && config.input ==
nullptr)
170 if (config.target_frames > config.output_capacity_frames)
172 if (config.output_capacity_frames > 0 && config.output ==
nullptr)
174 if (config.ratio_at_input_frame ==
nullptr
175 && std::isfinite(config.processor.max_time_ratio)
176 && config.processor.max_time_ratio >= 1.0f) {
177 const float minimum = 1.0f / config.processor.max_time_ratio;
178 if (!std::isfinite(config.constant_time_ratio)
179 || config.constant_time_ratio < minimum
180 || config.constant_time_ratio > config.processor.max_time_ratio)
183 for (
int channel = 0; channel < config.processor.channels; ++channel) {
184 if (config.input_frames > 0 && config.input[channel] ==
nullptr)
186 if (config.output_capacity_frames > 0 && config.output[channel] ==
nullptr)
189 const auto maximum_index =
static_cast<std::uint64_t
>(
190 std::min(std::numeric_limits<std::size_t>::max(),
191 static_cast<std::size_t
>(std::numeric_limits<std::ptrdiff_t>::max())));
192 if (config.input_frames > maximum_index || config.output_capacity_frames > maximum_index
193 || config.target_frames
194 >
static_cast<std::uint64_t
>(std::numeric_limits<std::int64_t>::max()))
199 std::uint64_t input_bytes = 0;
200 std::uint64_t output_bytes = 0;
202 config.target_max_bytes, &input_bytes)
204 config.target_max_bytes, &output_bytes))
206 if (std::isfinite(config.processor.max_time_ratio)
207 && config.processor.max_time_ratio >= 1.0f
212 const auto range_representable = [](std::uintptr_t address,
213 std::uint64_t bytes)
noexcept {
214 std::uint64_t end = 0;
216 std::numeric_limits<std::uintptr_t>::max(), end);
218 const auto ranges_overlap = [](std::uintptr_t
first, std::uint64_t first_bytes,
219 std::uintptr_t
second, std::uint64_t second_bytes)
noexcept {
220 if (first_bytes == 0 || second_bytes == 0)
return false;
221 std::uint64_t first_end = 0;
222 std::uint64_t second_end = 0;
224 std::numeric_limits<std::uintptr_t>::max(), first_end)
226 std::numeric_limits<std::uintptr_t>::max(), second_end))
230 for (
int channel = 0; channel <
config.processor.channels; ++channel) {
232 && !range_representable(
reinterpret_cast<std::uintptr_t
>(
config.input[channel]),
236 && !range_representable(
237 reinterpret_cast<std::uintptr_t
>(
config.output[channel]), output_bytes))
240 for (
int out_channel = 0; output_bytes > 0 && out_channel <
config.processor.channels;
242 const auto out_address =
reinterpret_cast<std::uintptr_t
>(
config.output[out_channel]);
243 for (
int input_channel = 0;
244 input_bytes > 0 && input_channel <
config.processor.channels; ++input_channel)
245 if (ranges_overlap(out_address, output_bytes,
246 reinterpret_cast<std::uintptr_t
>(
config.input[input_channel]),
249 for (
int prior = 0; prior < out_channel; ++prior)
250 if (ranges_overlap(out_address, output_bytes,
251 reinterpret_cast<std::uintptr_t
>(
config.output[prior]),
258 bool resolve_ratio(std::uint64_t boundary,
float& resolved)
noexcept {
259 const auto position = std::min(boundary, config_.input_frames);
260 const float ratio = config_.ratio_at_input_frame !=
nullptr
261 ? config_.ratio_at_input_frame(config_.ratio_context, position)
262 : config_.constant_time_ratio;
263 const float minimum = 1.0f / config_.processor.max_time_ratio;
273 const int until_boundary = processor_.samples_until_next_analysis_frame();
275 const auto remaining = config_.input_frames - input_consumed_;
276 pending_.kind = PendingKind::feed;
277 pending_.count =
static_cast<int>(std::min<std::uint64_t>(
278 remaining,
static_cast<std::uint64_t
>(
279 std::min(config_.processor.max_block, until_boundary))));
281 pending_.apply_ratio = pending_.count == until_boundary;
282 const auto boundary = input_consumed_ +
static_cast<std::uint64_t
>(pending_.count);
283 if (pending_.apply_ratio && !resolve_ratio(boundary, pending_.ratio))
285 return execute_pending();
289 if (pending_.apply_ratio) processor_.set_time_ratio(pending_.ratio);
290 if (pending_.kind == PendingKind::finalize)
return execute_finalize();
291 if (pending_.kind != PendingKind::feed)
293 for (
int channel = 0; channel < config_.processor.channels; ++channel)
294 input_ptrs_[
static_cast<std::size_t
>(channel)] =
295 config_.input[channel] +
static_cast<std::size_t
>(input_consumed_);
297 const auto status = processor_.feed(input_ptrs_.data(), pending_.count);
299 input_consumed_ +=
static_cast<std::uint64_t
>(pending_.count);
305 drain_before_pending_ =
true;
313 const int available = processor_.available_stretched();
314 if (available <= 0) {
315 drain_before_pending_ =
false;
318 const auto remaining = config_.target_frames - output_written_;
320 const int take =
static_cast<int>(std::min<std::uint64_t>(
321 static_cast<std::uint64_t
>(
322 std::min(available, config_.processor.max_block)),
324 for (
int channel = 0; channel < config_.processor.channels; ++channel)
325 output_ptrs_[
static_cast<std::size_t
>(channel)] =
326 config_.output[channel] +
static_cast<std::size_t
>(output_written_);
328 const int read = processor_.read_stretched(output_ptrs_.data(), take);
331 output_written_ +=
static_cast<std::uint64_t
>(
read);
332 drain_before_pending_ = processor_.available_stretched() > 0;
333 if (
static_cast<std::uint64_t
>(available) > remaining)
339 const int until_boundary = processor_.samples_until_next_analysis_frame();
341 const auto plan = processor_.plan_finalize(
342 std::min(config_.processor.max_block, until_boundary));
344 if (output_written_ != config_.target_frames)
350 if (processor_.available_stretched() <= 0)
352 drain_before_pending_ =
true;
357 pending_.kind = PendingKind::finalize;
358 pending_.count = plan.samples;
359 pending_.apply_ratio = pending_.count == until_boundary;
360 const auto boundary = input_consumed_ +
static_cast<std::uint64_t
>(pending_.count);
361 if (pending_.apply_ratio && !resolve_ratio(boundary, pending_.ratio))
363 return execute_pending();
368 const auto status = processor_.finalize(pending_.count);
372 if (processor_.available_stretched() != 0)
374 if (output_written_ != config_.target_frames)
382 drain_before_pending_ = processor_.available_stretched() > 0;
394 RealtimePitchTimeProcessorT<SampleType> processor_;
395 std::array<const SampleType*, kRealtimePitchTimeMaximumChannels> input_ptrs_ {};
396 std::array<SampleType*, kRealtimePitchTimeMaximumChannels> output_ptrs_ {};
397 std::uint64_t input_consumed_ = 0;
398 std::uint64_t output_written_ = 0;
399 enum class PendingKind { none, feed, finalize };
401 PendingKind kind = PendingKind::none;
404 bool apply_ratio =
false;
406 PendingWork pending_ {};
407 bool drain_before_pending_ =
false;
Definition finite_stretch_builder.hpp:107
FiniteStretchFailure failure() const noexcept
Definition finite_stretch_builder.hpp:154
FiniteStretchPrepareStatus prepare_status() const noexcept
Definition finite_stretch_builder.hpp:150
std::uint64_t output_frames_written() const noexcept
Definition finite_stretch_builder.hpp:158
bool complete() const noexcept
Definition finite_stretch_builder.hpp:159
FiniteStretchWorkOutcome last_work_outcome() const noexcept
Definition finite_stretch_builder.hpp:156
FiniteStretchStepStatus step() noexcept
Definition finite_stretch_builder.hpp:136
FiniteStretchConfigT< SampleType > Config
Definition finite_stretch_builder.hpp:109
PitchTimePrepareStatus processor_prepare_status() const noexcept
Definition finite_stretch_builder.hpp:151
FiniteStretchPrepareStatus prepare(const Config &config)
Definition finite_stretch_builder.hpp:111
std::uint64_t input_frames_consumed() const noexcept
Definition finite_stretch_builder.hpp:157
FiniteStretchWorkUnit last_work_unit() const noexcept
Definition finite_stretch_builder.hpp:155
std::uint64_t read(std::span< const std::uint8_t > b, std::size_t p, unsigned n) noexcept
Definition spectral_frame_codec.hpp:111
Definition additive_bank.hpp:218
@ time_stretch
Definition realtime_pitch_time_geometry.hpp:26
@ first
Definition dither.hpp:23
@ second
Definition dither.hpp:24
FiniteStretchBuilderT< double > FiniteStretchBuilder64
Definition finite_stretch_builder.hpp:419
FiniteStretchWorkUnit
Definition finite_stretch_builder.hpp:40
@ feed
Definition finite_stretch_builder.hpp:40
@ finalize
Definition finite_stretch_builder.hpp:40
@ none
Definition finite_stretch_builder.hpp:40
@ drain
Definition finite_stretch_builder.hpp:40
FiniteStretchWorkOutcome
Definition finite_stretch_builder.hpp:41
@ none
Definition finite_stretch_builder.hpp:41
@ advanced
Definition finite_stretch_builder.hpp:41
@ backpressure
Definition finite_stretch_builder.hpp:41
@ needs_drain
Definition realtime_pitch_time_geometry.hpp:39
@ ready
Definition realtime_pitch_time_geometry.hpp:38
@ complete
Definition realtime_pitch_time_geometry.hpp:40
@ draining
Definition realtime_pitch_time_geometry.hpp:31
@ complete
Definition realtime_pitch_time_geometry.hpp:33
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
@ quality
Definition realtime_pitch_time_geometry.hpp:25
bool checked_capacity_sum(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &sum) noexcept
Definition checked_allocation.hpp:21
FiniteStretchBuilderT< float > FiniteStretchBuilder
Definition finite_stretch_builder.hpp:418
FiniteStretchFailure
Definition finite_stretch_builder.hpp:32
@ output_too_long
Definition finite_stretch_builder.hpp:36
@ none
Definition finite_stretch_builder.hpp:33
@ processor_protocol_error
Definition finite_stretch_builder.hpp:37
@ invalid_ratio
Definition finite_stretch_builder.hpp:34
@ output_too_short
Definition finite_stretch_builder.hpp:35
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
FiniteStretchCounterGeometryStatus checked_finite_stretch_counter_geometry(const RealtimePitchTimeConfig &config, std::uint64_t input_frames) noexcept
Definition finite_stretch_builder.hpp:49
FiniteStretchCounterGeometryStatus
Definition finite_stretch_builder.hpp:43
@ output_counter_overflow
Definition finite_stretch_builder.hpp:46
@ input_counter_overflow
Definition finite_stretch_builder.hpp:45
@ representable
Definition finite_stretch_builder.hpp:44
constexpr int kRealtimePitchTimeMaximumChannels
Definition realtime_pitch_time_geometry.hpp:79
constexpr std::uint64_t kTargetAddressMaximumBytes
Definition checked_allocation.hpp:9
@ none
Definition dither.hpp:17
float(*)(void *context, std::uint64_t input_frame) noexcept FiniteStretchRatioAtInputFrame
Called for the analysis frame ending at input_frame.
Definition finite_stretch_builder.hpp:88
FiniteStretchPrepareStatus
Definition finite_stretch_builder.hpp:18
@ unrepresentable_capacity
Definition finite_stretch_builder.hpp:26
@ invalid_input
Definition finite_stretch_builder.hpp:21
@ processor_prepare_failed
Definition finite_stretch_builder.hpp:27
@ invalid_mode
Definition finite_stretch_builder.hpp:20
@ invalid_output
Definition finite_stretch_builder.hpp:22
@ invalid_ratio
Definition finite_stretch_builder.hpp:25
@ prepared
Definition finite_stretch_builder.hpp:19
@ invalid_output_layout
Definition finite_stretch_builder.hpp:23
@ invalid_target
Definition finite_stretch_builder.hpp:24
FiniteStretchConfigT< float > FiniteStretchConfig
Definition finite_stretch_builder.hpp:416
FiniteStretchConfigT< double > FiniteStretchConfig64
Definition finite_stretch_builder.hpp:417
FiniteStretchStepStatus
Definition finite_stretch_builder.hpp:30
@ failed
Definition finite_stretch_builder.hpp:30
@ progress
Definition finite_stretch_builder.hpp:30
@ complete
Definition finite_stretch_builder.hpp:30
PitchTimePrepareStatus
Definition realtime_pitch_time_geometry.hpp:50
@ invalid_sample_rate
Definition realtime_pitch_time_geometry.hpp:52
@ prepared
Definition realtime_pitch_time_geometry.hpp:51
@ accepted
Definition realtime_pitch_time_geometry.hpp:29
@ backpressure
Definition realtime_pitch_time_geometry.hpp:29
bool checked_allocation_bytes(std::uint64_t elements, std::uint64_t target_max_bytes, std::uint64_t *bytes=nullptr) noexcept
Definition checked_allocation.hpp:31
float minimum(const float *data, std::size_t count) noexcept
@ available
A value was read. It may legitimately be zero.
Definition latency_evidence.hpp:57
Realtime pitch shifting and time-scale modification for coherent channel groups, built on SpectralFra...
Definition finite_stretch_builder.hpp:92
SampleType *const * output
Definition finite_stretch_builder.hpp:97
const SampleType *const * input
Definition finite_stretch_builder.hpp:95
RealtimePitchTimeConfig processor
Definition finite_stretch_builder.hpp:94
std::uint64_t target_frames
Definition finite_stretch_builder.hpp:99
FiniteStretchRatioAtInputFrame ratio_at_input_frame
Definition finite_stretch_builder.hpp:101
std::uint64_t output_capacity_frames
Definition finite_stretch_builder.hpp:98
double sample_rate
Definition finite_stretch_builder.hpp:93
std::uint64_t target_max_bytes
Definition finite_stretch_builder.hpp:103
std::uint64_t input_frames
Definition finite_stretch_builder.hpp:96
float constant_time_ratio
Definition finite_stretch_builder.hpp:100
void * ratio_context
Definition finite_stretch_builder.hpp:102
Definition realtime_pitch_time_geometry.hpp:61