// Copyright (c) 2019, Paul Ferrand // All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "AudioBuffer.h" #include "Buffer.h" #include "Config.h" #include "Debug.h" #include "LeakDetector.h" #include "SIMDHelpers.h" #include #include template class AudioSpan { public: using size_type = size_t; AudioSpan() { } AudioSpan(const std::array& spans, int numChannels, size_type offset, size_type size) : numFrames(size) , numChannels(numChannels) { ASSERT(static_cast(numChannels) <= MaxChannels); for (auto i = 0; i < numChannels; ++i) this->spans[i] = spans[i] + offset; } AudioSpan(std::initializer_list spans, size_type numFrames) : numFrames(numFrames) , numChannels(spans.size()) { ASSERT(spans.size() <= MaxChannels); auto newSpan = spans.begin(); auto thisSpan = this->spans.begin(); for (; newSpan < spans.end() && thisSpan < this->spans.end(); thisSpan++, newSpan++) { // This will not end well... ASSERT(*newSpan != nullptr); *thisSpan = *newSpan; } } AudioSpan(std::initializer_list> spans) : numChannels(spans.size()) { ASSERT(spans.size() <= MaxChannels); auto size = absl::Span::npos; auto newSpan = spans.begin(); auto thisSpan = this->spans.begin(); for (; newSpan < spans.end() && thisSpan < this->spans.end(); thisSpan++, newSpan++) { *thisSpan = newSpan->data(); size = std::min(size, newSpan->size()); } } template > AudioSpan(AudioBuffer& audioBuffer) : numFrames(audioBuffer.getNumFrames()) , numChannels(audioBuffer.getNumChannels()) { for (int i = 0; i < numChannels; i++) { if constexpr (std::is_const::value) this->spans[i] = audioBuffer.channelReader(i); else this->spans[i] = audioBuffer.channelWriter(i); } } template > AudioSpan(const AudioSpan& other) : numFrames(other.getNumFrames()) , numChannels(other.getNumChannels()) { for (int i = 0; i < numChannels; i++) { this->spans[i] = other.getChannel(i); } } Type* getChannel(int channelIndex) { ASSERT(channelIndex < numChannels); if (channelIndex < numChannels) return spans[channelIndex]; return {}; } absl::Span getSpan(int channelIndex) { ASSERT(channelIndex < numChannels); if (channelIndex < numChannels) return { spans[channelIndex], numFrames }; return {}; } absl::Span getConstSpan(int channelIndex) { ASSERT(channelIndex < numChannels); if (channelIndex < numChannels) return { spans[channelIndex], numFrames }; return {}; } Type meanSquared() noexcept { if (numChannels == 0) return 0.0; Type result = 0.0; for (int i = 0; i < numChannels; ++i) result += ::meanSquared(getConstSpan(i)); return result / numChannels; } void fill(Type value) noexcept { for (int i = 0; i < numChannels; ++i) ::fill(getSpan(i), value); } void applyGain(absl::Span gain) noexcept { for (int i = 0; i < numChannels; ++i) ::applyGain(gain, getSpan(i)); } void applyGain(Type gain) noexcept { for (int i = 0; i < numChannels; ++i) ::applyGain(gain, getSpan(i)); } template > void add(AudioSpan& other) { ASSERT(other.getNumChannels() == numChannels); if (other.getNumChannels() == numChannels) { for (int i = 0; i < numChannels; ++i) ::add(other.getConstSpan(i), getSpan(i)); } } template > void copy(AudioSpan& other) { ASSERT(other.getNumChannels() == numChannels); if (other.getNumChannels() == numChannels) { for (int i = 0; i < numChannels; ++i) ::copy(other.getConstSpan(i), getSpan(i)); } } size_type getNumFrames() { return numFrames; } int getNumChannels() { return numChannels; } AudioSpan first(size_type length) { ASSERT(length <= numFrames); return { spans, numChannels, 0, length }; } AudioSpan last(size_type length) { ASSERT(length <= numFrames); return { spans, numChannels, numFrames - length, length }; } AudioSpan subspan(size_type offset, size_type length) { ASSERT(length + offset <= numFrames); return { spans, numChannels, offset, length }; } private: std::array spans; size_type numFrames { 0 }; int numChannels { 0 }; };