53 std::size_t channel_count,
57 if (!(source_frames_per_output > 0.0) ||
58 !std::isfinite(source_frames_per_output) || channel_count == 0 ||
64 ratio_ = source_frames_per_output;
65 channels_ = channel_count;
66 selection_ = selection;
68 tap_count_ = selection.wider.tap_count();
69 history_capacity_ = tap_count_;
70 half_width_ = selection.wider.half_width();
71 if (tap_count_ == 0 ||
72 channels_ > std::numeric_limits<std::size_t>::max() / tap_count_) {
77 history_.assign(channels_ * tap_count_, 0.0f);
82 const auto integer = std::floor(ratio_);
83 if (integer >
static_cast<double>(std::numeric_limits<std::int64_t>::max())) {
87 step_integer_ =
static_cast<std::int64_t
>(integer);
88 step_fraction_ = ratio_ - integer;
96 double default_source_frames_per_output,
97 double minimum_source_frames_per_output,
98 double maximum_source_frames_per_output,
99 std::size_t channel_count,
101 if (!bank.valid() || !(minimum_source_frames_per_output > 0.0) ||
102 !std::isfinite(minimum_source_frames_per_output) ||
103 minimum_source_frames_per_output > default_source_frames_per_output ||
104 !(maximum_source_frames_per_output > 0.0) ||
105 !std::isfinite(maximum_source_frames_per_output) ||
106 default_source_frames_per_output > maximum_source_frames_per_output ||
107 !bank.select(maximum_source_frames_per_output).valid())
109 const auto selection = bank.select(default_source_frames_per_output);
110 const auto status =
prepare(default_source_frames_per_output, channel_count,
113 variable_bank_ = bank;
114 maximum_ratio_ = maximum_source_frames_per_output;
115 minimum_ratio_ = minimum_source_frames_per_output;
116 fixed_latency_output_frames_ = std::ceil(
117 static_cast<double>(half_width_) / minimum_source_frames_per_output);
118 const auto history_frames = std::ceil(
119 fixed_latency_output_frames_ * maximum_source_frames_per_output) +
120 static_cast<double>(tap_count_) + 2.0;
121 if (!std::isfinite(history_frames) ||
123 static_cast<double>(std::numeric_limits<std::size_t>::max())) {
127 history_capacity_ =
static_cast<std::size_t
>(history_frames);
128 if (channels_ > std::numeric_limits<std::size_t>::max() /
134 history_.assign(channels_ * history_capacity_, 0.0f);
139 variable_ratio_ =
true;
144 std::vector<float>().swap(history_);
148 maximum_ratio_ = 0.0;
149 minimum_ratio_ = 0.0;
150 fixed_latency_output_frames_ = 0.0;
151 step_fraction_ = 0.0;
155 history_capacity_ = 0;
159 variable_ratio_ =
false;
161 accepted_frames_ = 0;
163 center_fraction_ = 0.0;
167 acquisition_index_ = 0;
168 acquisition_fraction_ = 0.0;
170 source_end_frame_ = 0;
171 last_valid_output_frames_ = 0;
172 source_ended_ =
false;
178 std::fill(history_.begin(), history_.end(), 0.0f);
179 accepted_frames_ = 0;
180 center_index_ = identity_ ? 0 : -
static_cast<std::int64_t
>(half_width_);
181 center_fraction_ = 0.0;
186 acquisition_index_ = 0;
187 acquisition_fraction_ = 0.0;
189 source_end_frame_ = 0;
190 last_valid_output_frames_ = 0;
191 source_ended_ =
false;
194 bool prepared() const noexcept {
return prepared_; }
195 bool identity() const noexcept {
return identity_; }
196 double ratio() const noexcept {
return ratio_; }
197 std::uint32_t
half_width() const noexcept {
return half_width_; }
200 return plan(output_frames, ratio_);
204 double source_frames_per_output)
const noexcept {
207 if (!prepared_)
return result;
208 if (!(source_frames_per_output > 0.0) ||
209 !std::isfinite(source_frames_per_output) ||
210 (!variable_ratio_ && source_frames_per_output != ratio_) ||
211 (variable_ratio_ && source_frames_per_output > maximum_ratio_)) {
220 if (variable_ratio_) {
221 auto center = center_index_;
222 auto fraction = center_fraction_;
223 if (!adjust_position_for_ratio(source_frames_per_output, center,
228 auto acquisition = acquisition_index_;
229 auto acquisition_fraction = acquisition_fraction_;
230 for (std::size_t frame = 0; frame < output_frames; ++frame) {
231 if (!advance(acquisition, acquisition_fraction,
232 source_frames_per_output)) {
237 auto required_through =
static_cast<std::uint64_t
>(acquisition);
238 if (acquisition_fraction > 0.0) ++required_through;
239 if (required_through > accepted_frames_) {
240 const auto needed = required_through - accepted_frames_;
241 if (needed > std::numeric_limits<std::size_t>::max()) {
249 auto center = center_index_;
250 auto fraction = center_fraction_;
251 initial_position(source_frames_per_output, center, fraction);
252 if (!adjust_position_for_ratio(source_frames_per_output, center,
257 std::int64_t highest = -1;
258 for (std::size_t frame = 0; frame < output_frames; ++frame) {
259 if (center > std::numeric_limits<std::int64_t>::max() -
260 static_cast<std::int64_t
>(half_width_)) {
264 highest = center +
static_cast<std::int64_t
>(half_width_);
265 if (!advance(center, fraction, source_frames_per_output)) {
270 if (highest < 0)
return result;
271 const auto required_through =
static_cast<std::uint64_t
>(highest) + 1u;
272 if (required_through > accepted_frames_) {
273 const auto needed = required_through - accepted_frames_;
274 if (needed > std::numeric_limits<std::size_t>::max()) {
285 return process(input, output, ratio_);
289 double source_frames_per_output)
noexcept {
290 return process_impl(input, output, source_frames_per_output, input.num_samples(),
false,
298 bool end_of_source)
noexcept {
299 return process_impl(input, output, ratio_, valid_input_frames, end_of_source,
true);
304 std::size_t valid_input_frames,
bool end_of_source,
305 double source_frames_per_output)
noexcept {
306 return process_impl(input, output, source_frames_per_output,
307 valid_input_frames, end_of_source,
true);
311 return last_valid_output_frames_;
315 if (!source_ended_ || identity_ || source_end_frame_ == 0)
317 const auto next_position =
318 static_cast<long double>(center_index_) +
static_cast<long double>(center_fraction_);
319 const auto end_position =
static_cast<long double>(source_end_frame_) -
320 static_cast<long double>(selection_.wider.first_offset());
321 const auto distance = end_position - next_position;
322 if (!(distance > 0.0L))
324 const auto frames = std::ceil(distance /
static_cast<long double>(ratio_));
325 if (!std::isfinite(frames) ||
326 frames >=
static_cast<long double>(std::numeric_limits<std::uint64_t>::max())) {
327 return std::numeric_limits<std::uint64_t>::max();
329 return static_cast<std::uint64_t
>(frames);
339 std::size_t valid_input_frames,
bool end_of_source,
340 bool finite_source)
noexcept {
341 const auto expected =
plan(output.num_samples(), source_frames_per_output);
342 if (!expected.valid())
343 return expected.status;
344 if (input.num_channels() != channels_ || output.num_channels() != channels_) {
347 if (input.num_samples() != expected.input_frames)
349 if (finite_source && (valid_input_frames > input.num_samples() ||
350 (!end_of_source && valid_input_frames != input.num_samples()) ||
351 (source_ended_ && valid_input_frames != 0))) {
354 last_valid_output_frames_ = output.num_samples();
355 if (finite_source && !source_ended_) {
356 if (valid_input_frames > std::numeric_limits<std::uint64_t>::max() - accepted_frames_) {
359 source_end_frame_ = accepted_frames_ + valid_input_frames;
360 source_ended_ = end_of_source;
362 if (finite_source && source_ended_)
363 last_valid_output_frames_ = 0;
366 for (std::size_t channel = 0; channel < channels_; ++channel)
367 std::copy(input.channel(channel).begin(), input.channel(channel).end(),
368 output.channel(channel).begin());
369 if (finite_source && source_ended_)
370 last_valid_output_frames_ = valid_input_frames;
373 if (input.num_samples() > std::numeric_limits<std::uint64_t>::max() - accepted_frames_) {
377 std::array<float, 128> taps{};
378 auto center = center_index_;
379 auto fraction = center_fraction_;
380 initial_position(source_frames_per_output, center, fraction);
381 if (!adjust_position_for_ratio(source_frames_per_output, center, fraction))
383 const auto new_input_start = accepted_frames_;
384 if (output.num_samples() != 0) {
385 const auto first_required =
386 center +
static_cast<std::int64_t
>(selection_.wider.first_offset());
387 if (first_required >= 0 &&
388 static_cast<std::uint64_t
>(first_required) < new_input_start &&
389 static_cast<std::uint64_t
>(first_required) < history_start_) {
393 for (std::size_t frame = 0; frame < output.num_samples(); ++frame) {
394 if (finite_source && source_ended_ && source_end_frame_ != 0) {
395 const auto first_required =
396 center +
static_cast<std::int64_t
>(selection_.wider.first_offset());
397 const auto last_required =
398 first_required +
static_cast<std::int64_t
>(tap_count_ - 1);
399 if (last_required >= 0 &&
400 (first_required < 0 ||
401 static_cast<std::uint64_t
>(first_required) < source_end_frame_)) {
402 last_valid_output_frames_ = frame + 1;
405 for (std::size_t channel = 0; channel < channels_; ++channel) {
406 for (std::size_t tap = 0; tap < tap_count_; ++tap) {
407 const auto source_index =
408 center +
static_cast<std::int64_t
>(selection_.wider.first_offset()) +
409 static_cast<std::int64_t
>(tap);
410 taps[tap] = source_sample(channel, source_index, input, new_input_start);
413 variable_ratio_ ? variable_bank_.select(source_frames_per_output) : selection_;
416 output.channel(channel)[frame] =
selection.apply(
417 std::span<const float>(taps.data(), tap_count_), fraction);
419 if (!advance(center, fraction, source_frames_per_output))
423 append_history(input);
424 accepted_frames_ += input.num_samples();
426 center_fraction_ = fraction;
427 if (variable_ratio_) {
428 for (std::size_t frame = 0; frame < output.num_samples(); ++frame) {
429 if (!advance(acquisition_index_, acquisition_fraction_,
430 source_frames_per_output))
435 active_ratio_ = source_frames_per_output;
439 void initial_position(
double ratio, std::int64_t& center,
440 double& fraction)
const noexcept {
441 if (!variable_ratio_ || started_)
return;
442 const auto position = -fixed_latency_output_frames_ *
ratio;
443 const auto integer = std::floor(position);
444 center =
static_cast<std::int64_t
>(integer);
445 fraction = position - integer;
448 bool adjust_position_for_ratio(
double ratio, std::int64_t& center,
449 double& fraction)
const noexcept {
450 if (!variable_ratio_ || !started_ ||
ratio == active_ratio_)
return true;
451 const auto position =
static_cast<long double>(acquisition_index_) +
452 acquisition_fraction_ -
453 static_cast<long double>(fixed_latency_output_frames_) *
ratio;
454 const auto integer = std::floor(position);
455 if (integer <
static_cast<long double>(
456 std::numeric_limits<std::int64_t>::min()) ||
457 integer >
static_cast<long double>(
458 std::numeric_limits<std::int64_t>::max()))
460 center =
static_cast<std::int64_t
>(integer);
461 fraction =
static_cast<double>(position - integer);
465 bool advance(std::int64_t& center,
double& fraction,
466 double ratio)
const noexcept {
467 const auto integer_part = std::floor(
ratio);
469 static_cast<double>(std::numeric_limits<std::int64_t>::max()))
471 const auto step_integer =
static_cast<std::int64_t
>(integer_part);
472 const auto step_fraction =
ratio - integer_part;
473 auto next_fraction = fraction + step_fraction;
474 std::int64_t carry = 0;
475 if (next_fraction >= 1.0) {
476 next_fraction -= 1.0;
479 if (step_integer > std::numeric_limits<std::int64_t>::max() - carry ||
480 center > std::numeric_limits<std::int64_t>::max() -
481 (step_integer + carry)) {
484 center += step_integer + carry;
485 fraction = next_fraction;
489 float source_sample(std::size_t channel,
490 std::int64_t source_index,
491 const BufferView<const float>& input,
492 std::uint64_t new_input_start)
const noexcept {
493 if (source_index < 0)
return 0.0f;
494 const auto absolute =
static_cast<std::uint64_t
>(source_index);
495 if (absolute >= new_input_start) {
496 const auto offset = absolute - new_input_start;
497 if (offset < input.num_samples())
498 return input.channel(channel)[
static_cast<std::size_t
>(offset)];
501 if (absolute < history_start_ ||
502 absolute - history_start_ >= history_count_) {
505 const auto offset =
static_cast<std::size_t
>(absolute - history_start_);
506 const auto slot = (history_head_ + offset) % history_capacity_;
507 return history_[channel * history_capacity_ + slot];
510 void append_history(
const BufferView<const float>& input)
noexcept {
511 for (std::size_t frame = 0; frame < input.num_samples(); ++frame) {
512 std::size_t slot = 0;
513 if (history_count_ < history_capacity_) {
514 slot = (history_head_ + history_count_) % history_capacity_;
517 slot = history_head_;
518 history_head_ = (history_head_ + 1) % history_capacity_;
521 for (std::size_t channel = 0; channel < channels_; ++channel)
522 history_[channel * history_capacity_ + slot] = input.channel(channel)[frame];
526 std::vector<float> history_;
527 SampleSincKernelSelection selection_{};
528 SampleSincKernelBankView variable_bank_{};
530 double maximum_ratio_ = 0.0;
531 double minimum_ratio_ = 0.0;
532 double fixed_latency_output_frames_ = 0.0;
533 double step_fraction_ = 0.0;
534 std::int64_t step_integer_ = 0;
535 std::size_t channels_ = 0;
536 std::size_t tap_count_ = 0;
537 std::size_t history_capacity_ = 0;
538 std::uint32_t half_width_ = 0;
539 bool prepared_ =
false;
540 bool identity_ =
false;
541 bool variable_ratio_ =
false;
542 bool started_ =
false;
543 std::uint64_t accepted_frames_ = 0;
544 std::int64_t center_index_ = 0;
545 double center_fraction_ = 0.0;
546 std::size_t history_head_ = 0;
547 std::size_t history_count_ = 0;
548 std::uint64_t history_start_ = 0;
549 std::int64_t acquisition_index_ = 0;
550 double acquisition_fraction_ = 0.0;
551 double active_ratio_ = 0.0;
552 std::uint64_t source_end_frame_ = 0;
553 std::size_t last_valid_output_frames_ = 0;
554 bool source_ended_ =
false;