3#include "detail/audio_range.hpp"
26template <
typename SampleType = float, std::size_t MaxPaths = 16, std::size_t MaxChannels = 8,
27 typename Allocator = std::allocator<SampleType>>
30 static_assert(MaxPaths > 0 && MaxChannels > 0);
31 static_assert(std::is_floating_point_v<SampleType>);
37 bool prepare(std::size_t paths, std::size_t channels, std::size_t max_latency_samples,
38 std::size_t max_block_size) {
39 if (paths == 0 || paths > MaxPaths || channels == 0 || channels > MaxChannels ||
40 max_block_size == 0 || max_latency_samples == std::numeric_limits<std::size_t>::max())
42 const auto stride = max_latency_samples + 1;
43 if (paths > std::numeric_limits<std::size_t>::max() / channels)
45 const auto streams = paths * channels;
46 if (streams > std::numeric_limits<std::size_t>::max() / stride)
48 const auto retained = streams * stride;
49 if (retained > rings_.max_size())
51 std::vector<SampleType, Allocator> replacement(rings_.get_allocator());
52#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
55 replacement.assign(retained, SampleType{0});
56#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
57 }
catch (
const std::bad_alloc&) {
61 rings_.swap(replacement);
64 max_latency_ = max_latency_samples;
65 max_block_size_ = max_block_size;
68 write_positions_.fill(0);
69 reported_latency_ = 0;
74 if (latencies.size() != paths_ || rings_.empty())
76 for (
const auto latency : latencies)
77 if (latency > max_latency_)
79 reported_latency_ = 0;
80 for (std::size_t path = 0; path < paths_; ++path) {
81 latencies_[path] = latencies[path];
82 reported_latency_ = std::max(reported_latency_, latencies[path]);
89 std::fill(rings_.begin(), rings_.end(), SampleType{0});
90 write_positions_.fill(0);
94 return reported_latency_;
97 return path < paths_ ? latencies_[path] : 0;
100 return path < paths_ ? reported_latency_ - latencies_[path] : 0;
109 return rings_.size();
112 bool process(
const SampleType*
const* inputs, std::size_t input_count,
113 SampleType*
const* outputs, std::size_t output_count,
114 std::size_t frames)
noexcept {
115 const auto stream_count = paths_ * channels_;
116 if (inputs ==
nullptr || outputs ==
nullptr || input_count != stream_count ||
117 output_count != stream_count || frames > max_block_size_ || rings_.empty())
119 for (std::size_t stream = 0; stream < stream_count; ++stream) {
120 if (inputs[stream] ==
nullptr || outputs[stream] ==
nullptr)
122 for (std::size_t other = 0; other < stream_count; ++other) {
123 if (other == stream) {
124 if (outputs[stream] != inputs[stream] &&
125 detail::audio_ranges_overlap(outputs[stream], inputs[stream], frames))
127 }
else if (detail::audio_ranges_overlap(outputs[stream], inputs[other], frames)) {
130 if (other > stream &&
131 detail::audio_ranges_overlap(outputs[stream], outputs[other], frames))
136 for (std::size_t frame = 0; frame < frames; ++frame) {
137 for (std::size_t path = 0; path < paths_; ++path) {
139 const auto position = write_positions_[path];
140 for (std::size_t channel = 0; channel < channels_; ++channel) {
141 const auto stream = path * channels_ + channel;
142 const auto input = inputs[stream][frame];
144 outputs[stream][frame] = input;
146 auto* ring = rings_.data() + stream * stride_;
147 outputs[stream][frame] = ring[position];
148 ring[position] = input;
152 write_positions_[path] = (position + 1) %
delay;
159 std::size_t paths_ = 0;
160 std::size_t channels_ = 0;
161 std::size_t max_latency_ = 0;
162 std::size_t max_block_size_ = 0;
163 std::size_t stride_ = 0;
164 std::size_t reported_latency_ = 0;
165 std::array<std::size_t, MaxPaths> latencies_{};
166 std::array<std::size_t, MaxPaths> write_positions_{};
167 std::vector<SampleType, Allocator> rings_;
Aligns N already-processed paths to the largest declared intrinsic latency.
Definition path_latency_aligner.hpp:28
std::size_t channel_count() const noexcept
Definition path_latency_aligner.hpp:105
std::size_t retained_samples() const noexcept
Definition path_latency_aligner.hpp:108
std::size_t reported_latency_samples() const noexcept
Definition path_latency_aligner.hpp:93
void reset() noexcept
Definition path_latency_aligner.hpp:88
PathLatencyAlignerT(const Allocator &allocator=Allocator{})
Definition path_latency_aligner.hpp:35
bool process(const SampleType *const *inputs, std::size_t input_count, SampleType *const *outputs, std::size_t output_count, std::size_t frames) noexcept
Definition path_latency_aligner.hpp:112
bool prepare(std::size_t paths, std::size_t channels, std::size_t max_latency_samples, std::size_t max_block_size)
Definition path_latency_aligner.hpp:37
std::size_t path_count() const noexcept
Definition path_latency_aligner.hpp:102
std::size_t compensation_delay_samples(std::size_t path) const noexcept
Definition path_latency_aligner.hpp:99
static constexpr std::size_t max_paths
Definition path_latency_aligner.hpp:32
bool configure_latencies(std::span< const std::size_t > latencies) noexcept
Definition path_latency_aligner.hpp:73
static constexpr std::size_t max_channels
Definition path_latency_aligner.hpp:33
std::size_t path_latency_samples(std::size_t path) const noexcept
Definition path_latency_aligner.hpp:96
Definition additive_bank.hpp:218
@ delay
Definition envelope.hpp:57
PathLatencyAlignerT< double > PathLatencyAligner64
Definition path_latency_aligner.hpp:171
PathLatencyAlignerT< float > PathLatencyAligner
Definition path_latency_aligner.hpp:170