19#include "ProcessorTraits.h"
21#include "AudioBuffer.h"
51template <
typename T,
typename... Processors>
54 static_assert(
sizeof...(Processors) > 0,
"ProcessorChain requires at least one processor.");
56 "Every ProcessorChain slot must satisfy the dspark::AudioProcessor concept "
57 "(prepare(AudioSpec), processBlock(AudioBufferView<T>) noexcept, reset() noexcept).");
66 std::apply([&spec](
auto&... procs) {
67 (procs.prepare(spec), ...);
77 processBlockImpl(buffer, std::index_sequence_for<Processors...>{});
85 std::apply([](
auto&... procs) {
96 template <std::
size_t Index>
97 [[nodiscard]]
auto&
get() noexcept
99 static_assert(Index <
sizeof...(Processors),
"Processor index out of bounds.");
100 return std::get<Index>(processors_);
109 template <std::
size_t Index>
110 [[nodiscard]]
const auto&
get() const noexcept
112 static_assert(Index <
sizeof...(Processors),
"Processor index out of bounds.");
113 return std::get<Index>(processors_);
119 [[nodiscard]]
static constexpr std::size_t
size() noexcept
121 return sizeof...(Processors);
139 return getLatencyImpl(std::index_sequence_for<Processors...>{});
156 template <std::
size_t Index>
159 static_assert(Index <
sizeof...(Processors),
"Index out of range");
160 bypassed_[Index].store(bypassed, std::memory_order_relaxed);
166 template <std::
size_t Index>
169 static_assert(Index <
sizeof...(Processors),
"Index out of range");
170 return bypassed_[Index].load(std::memory_order_relaxed);
174 template <std::size_t... Is>
175 [[nodiscard]]
int getLatencyImpl(std::index_sequence<Is...>)
const noexcept
177 return (getProcessorLatency<Is>() + ...);
180 template <std::
size_t I>
181 [[nodiscard]]
int getProcessorLatency() const noexcept
183 using P = std::tuple_element_t<I, std::tuple<Processors...>>;
184 if constexpr (
requires(
const P& p) { { p.getLatency() } -> std::convertible_to<int>; })
186 return static_cast<int>(std::get<I>(processors_).getLatency());
193 static_assert(!
requires(P& p) { p.getLatency(); },
194 "Processor getLatency() must be const and return a value convertible to int "
195 "to be summed by ProcessorChain::getLatency().");
200 template <std::size_t... Is>
201 void processBlockImpl(AudioBufferView<T> buffer, std::index_sequence<Is...>)
noexcept
204 ((!bypassed_[Is].load(std::memory_order_relaxed) ? std::get<Is>(processors_).processBlock(buffer) : (void)0), ...);
207 std::tuple<Processors...> processors_;
208 std::array<std::atomic<bool>,
sizeof...(Processors)> bypassed_ {};
Non-owning view over audio channel data.
Compile-time chain of audio processors.
void prepare(const AudioSpec &spec)
Prepares all processors in order.
auto & get() noexcept
Accesses the processor at the given index.
bool isBypassed() const noexcept
Reads the bypass state (lock-free readout, any thread).
void reset() noexcept
Resets the internal state of all processors (e.g., clearing delay lines).
void processBlock(AudioBufferView< T > buffer) noexcept
Processes a buffer through all non-bypassed processors in order.
void setBypassed(bool bypassed) noexcept
Toggles bypass for a processor (control thread; the relaxed atomic word is adopted by the next proces...
int getLatency() const noexcept
Returns the total latency in samples across all processors.
static constexpr std::size_t size() noexcept
Returns the number of processors in the chain.
const auto & get() const noexcept
Const access to the processor at the given index.
A type that can prepare, process audio blocks, and reset state.
Main namespace for the DSPark framework.
Describes the audio environment for a DSP processor.