31 static_assert(std::is_floating_point_v<SampleType>);
48 std::array<std::vector<SampleType>, 2> replacement;
49#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
54#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
55 }
catch (
const std::bad_alloc&) {
57 }
catch (
const std::length_error&) {
62 buffers_ = std::move(replacement);
71 [[nodiscard]]
bool configure(Config replacement)
noexcept {
72 if (!valid_config(replacement) ||
73 (prepared_ && replacement.window_samples > maximum_window_samples_))
75 config_ = replacement;
87 return maximum_window_samples_;
90 return prepared_ ? 2u * maximum_window_samples_ *
sizeof(SampleType) : 0
u;
94 return prepared_ && !bypassed_ ?
static_cast<int>(config_.window_samples) : 0;
97 return prepared_ ?
static_cast<int>(config_.window_samples) : 0;
100 if (!prepared_ || bypassed_)
102 return static_cast<int>(2u * config_.window_samples - 1u);
135 playback_buffer_ = 1;
137 playback_ready_ =
false;
145 if (!std::isfinite(
static_cast<double>(input))) {
154 buffers_[capture_buffer_][position_] = input;
156 if (playback_ready_) {
157 const auto reverse_position = config_.window_samples - 1u - position_;
158 const auto gain =
static_cast<SampleType
>(boundary_gain(position_));
159 output = buffers_[playback_buffer_][reverse_position] * gain;
160 if (!std::isfinite(
static_cast<double>(output))) {
167 if (position_ == config_.window_samples) {
168 playback_buffer_ = capture_buffer_;
169 capture_buffer_ = 1u - capture_buffer_;
171 playback_ready_ =
true;
177 std::size_t sample_count)
noexcept {
178 if (input ==
nullptr || output ==
nullptr)
180 for (std::size_t
i = 0;
i < sample_count; ++
i) {
181 const auto sample = input[
i];
187 static bool valid_maximum(std::size_t samples)
noexcept {
191 static bool valid_config(Config
config)
noexcept {
198 double boundary_gain(std::size_t playback_position)
const noexcept {
202 const auto from_end = config_.
window_samples - 1u - playback_position;
203 const auto nearest_boundary = std::min(playback_position, from_end);
204 if (nearest_boundary >= fade)
206 const double phase =
static_cast<double>(nearest_boundary) /
static_cast<double>(fade);
207 constexpr double kPi = 3.14159265358979323846264338327950288;
208 return 0.5 * (1.0 - std::cos(kPi * phase));
212 std::array<std::vector<SampleType>, 2> buffers_{};
213 std::size_t maximum_window_samples_ = 0;
214 std::size_t capture_buffer_ = 0;
215 std::size_t playback_buffer_ = 1;
216 std::size_t position_ = 0;
217 bool playback_ready_ =
false;
218 bool prepared_ =
false;
219 bool bypassed_ =
false;
A mono streaming reverse-window processor.
Definition reverse_buffer.hpp:29
int latency_samples() const noexcept
Definition reverse_buffer.hpp:93
SampleType process_sample(SampleType input) noexcept
Definition reverse_buffer.hpp:144
static constexpr std::size_t kMinimumWindowSamples
Definition reverse_buffer.hpp:33
bool prepared() const noexcept
Definition reverse_buffer.hpp:83
bool configure(Config replacement) noexcept
Publishes the complete transport configuration.
Definition reverse_buffer.hpp:71
void process_block(const SampleType *input, SampleType *output, std::size_t sample_count) noexcept
Definition reverse_buffer.hpp:176
bool bypassed() const noexcept
Definition reverse_buffer.hpp:126
std::size_t maximum_window_samples() const noexcept
Definition reverse_buffer.hpp:86
ReverseBufferState state() const noexcept
Definition reverse_buffer.hpp:105
void reset() noexcept
Definition reverse_buffer.hpp:140
std::size_t position() const noexcept
Definition reverse_buffer.hpp:113
std::size_t retained_bytes() const noexcept
Definition reverse_buffer.hpp:89
Config config() const noexcept
Definition reverse_buffer.hpp:80
bool prepare(std::size_t maximum_window_samples)
Definition reverse_buffer.hpp:43
static constexpr std::size_t kMaximumWindowSamples
Definition reverse_buffer.hpp:34
void discard_history() noexcept
Discards capture/playback state in constant time without changing the prepared capacity,...
Definition reverse_buffer.hpp:133
void set_bypassed(bool bypassed) noexcept
Hard transport bypass.
Definition reverse_buffer.hpp:120
int startup_latency_samples() const noexcept
Definition reverse_buffer.hpp:96
int tail_samples() const noexcept
Definition reverse_buffer.hpp:99
Definition additive_bank.hpp:218
ReverseBufferT< float > ReverseBuffer
Definition reverse_buffer.hpp:222
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
ReverseBufferT< double > ReverseBuffer64
Definition reverse_buffer.hpp:223
ReverseBufferState
Definition reverse_buffer.hpp:19
@ bypassed
Definition reverse_buffer.hpp:19
@ unprepared
Definition reverse_buffer.hpp:19
@ running
Definition reverse_buffer.hpp:19
@ priming
Definition reverse_buffer.hpp:19
@ running
Maintain running sums as frames arrive; the latch only divides.
Definition freeze_hold.hpp:136
Definition reverse_buffer.hpp:36
std::size_t window_samples
Definition reverse_buffer.hpp:37
std::size_t boundary_fade_samples
Zero applies an exact rectangular window.
Definition reverse_buffer.hpp:40