#pragma once #include "Helpers.h" #include "SIMDHelpers.h" #include "StereoBuffer.h" #include #include template class StereoSpan { public: using ValueType = std::remove_cv_t; template StereoSpan() = delete; StereoSpan(Type* leftBuffer, Type* rightBuffer, size_t numFrames) : numFrames(numFrames) , leftBuffer(leftBuffer, numFrames) , rightBuffer(rightBuffer, numFrames) { } StereoSpan(void* leftBuffer, void* rightBuffer, size_t numFrames) : numFrames(numFrames) , leftBuffer(static_cast(leftBuffer), numFrames) , rightBuffer(static_cast(rightBuffer), numFrames) { } StereoSpan(absl::Span leftBuffer, absl::Span rightBuffer) : numFrames(std::min(leftBuffer.size(), rightBuffer.size())) , leftBuffer(leftBuffer.first(numFrames)) , rightBuffer(rightBuffer.first(numFrames)) { // Buffer really should be the same size here ASSERT(leftBuffer.size() == rightBuffer.size()); } StereoSpan(StereoBuffer& buffer) : leftBuffer(buffer.getConstSpan(Channel::left)) , rightBuffer(buffer.getConstSpan(Channel::right)) , numFrames(buffer.getNumFrames()) { } StereoSpan(StereoBuffer& buffer) : numFrames(buffer.getNumFrames()) , leftBuffer(buffer.getSpan(Channel::left)) , rightBuffer(buffer.getSpan(Channel::right)) { } StereoSpan(StereoBuffer& buffer, size_t numFrames) : numFrames(numFrames) , leftBuffer(buffer.getSpan(Channel::left).first(numFrames)) , rightBuffer(buffer.getSpan(Channel::right).first(numFrames)) { } StereoSpan(const StereoBuffer& buffer, size_t numFrames) : numFrames(numFrames) , leftBuffer(buffer.getConstSpan(Channel::left).first(numFrames)) , rightBuffer(buffer.getConstSpan(Channel::right).first(numFrames)) { } StereoSpan(const StereoSpan& span) : numFrames(span.size()) , leftBuffer(span.left()) , rightBuffer(span.right()) { } StereoSpan(const StereoSpan& span) : numFrames(span.size()) , leftBuffer(span.left()) , rightBuffer(span.right()) { } void fill(Type value) noexcept { ::fill(leftBuffer, value); ::fill(rightBuffer, value); } void applyGain(absl::Span gain) noexcept { ::applyGain(gain, leftBuffer); ::applyGain(gain, rightBuffer); } void applyGain(Type gain) noexcept { ::applyGain(gain, leftBuffer); ::applyGain(gain, rightBuffer); } void readInterleaved(absl::Span input) noexcept { ASSERT(input.size() <= static_cast(numChannels * numFrames)); ::readInterleaved(input, absl::MakeSpan(leftBuffer), absl::MakeSpan(rightBuffer)); } void writeInterleaved(absl::Span output) noexcept { ASSERT(output.size() >= static_cast(numChannels * numFrames)); ::writeInterleaved(leftBuffer, rightBuffer, output); } void add(StereoSpan buffer) { ::add(buffer.left(), leftBuffer); ::add(buffer.right(), rightBuffer); } absl::Span left() const { return leftBuffer; } absl::Span right() const { return rightBuffer; } StereoSpan first(size_t length) const { return { leftBuffer.first(length), rightBuffer.first(length) }; } StereoSpan last(size_t length) const { return { leftBuffer.last(length), rightBuffer.last(length) }; } StereoSpan subspan(size_t pos, size_t length = absl::Span::npos) const { return { leftBuffer.subspan(pos, length), rightBuffer.subspan(pos, length) }; } size_t size() const { return numFrames; } private: static constexpr int numChannels { 2 }; size_t numFrames { 0 }; absl::Span leftBuffer; absl::Span rightBuffer; LEAK_DETECTOR(StereoSpan); };