/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_AUDIO_SPAN_HPP #define MPT_AUDIO_SPAN_HPP #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include #include namespace mpt { inline namespace MPT_INLINE_NS { // LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx template struct audio_span_planar_strided { public: using sample_type = SampleType; private: SampleType * const * m_buffers; std::ptrdiff_t m_frame_stride; std::size_t m_channels; std::size_t m_frames; public: constexpr audio_span_planar_strided(SampleType * const * buffers, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride) noexcept : m_buffers(buffers) , m_frame_stride(frame_stride) , m_channels(channels) , m_frames(frames) { return; } SampleType * const * data_planar() const noexcept { return m_buffers; } SampleType * data() const noexcept { return nullptr; } SampleType & operator()(std::size_t channel, std::size_t frame) const { return m_buffers[channel][static_cast(frame) * m_frame_stride]; } bool is_contiguous() const noexcept { return false; } bool channels_are_contiguous() const noexcept { return false; } bool frames_are_contiguous() const noexcept { return false; } std::size_t size_channels() const noexcept { return m_channels; } std::size_t size_frames() const noexcept { return m_frames; } std::size_t size_samples() const noexcept { return m_channels * m_frames; } std::ptrdiff_t frame_stride() const noexcept { return m_frame_stride; } }; // LLLLL RRRRR template struct audio_span_planar { public: using sample_type = SampleType; private: SampleType * const * m_buffers; std::size_t m_channels; std::size_t m_frames; public: constexpr audio_span_planar(SampleType * const * buffers, std::size_t channels, std::size_t frames) noexcept : m_buffers(buffers) , m_channels(channels) , m_frames(frames) { return; } SampleType * const * data_planar() const noexcept { return m_buffers; } SampleType * data() const noexcept { return nullptr; } SampleType & operator()(std::size_t channel, std::size_t frame) const { return m_buffers[channel][frame]; } bool is_contiguous() const noexcept { return false; } bool channels_are_contiguous() const noexcept { return false; } bool frames_are_contiguous() const noexcept { return false; } std::size_t size_channels() const noexcept { return m_channels; } std::size_t size_frames() const noexcept { return m_frames; } std::size_t size_samples() const noexcept { return m_channels * m_frames; } }; // LLLLLRRRRR template struct audio_span_contiguous { public: using sample_type = SampleType; private: SampleType * const m_buffer; std::size_t m_channels; std::size_t m_frames; public: constexpr audio_span_contiguous(SampleType * buffer, std::size_t channels, std::size_t frames) noexcept : m_buffer(buffer) , m_channels(channels) , m_frames(frames) { return; } SampleType * const * data_planar() const noexcept { return nullptr; } SampleType * data() const noexcept { return m_buffer; } SampleType & operator()(std::size_t channel, std::size_t frame) const { return m_buffer[(m_frames * channel) + frame]; } bool is_contiguous() const noexcept { return true; } bool channels_are_contiguous() const noexcept { return true; } bool frames_are_contiguous() const noexcept { return false; } std::size_t size_channels() const noexcept { return m_channels; } std::size_t size_frames() const noexcept { return m_frames; } std::size_t size_samples() const noexcept { return m_channels * m_frames; } }; // LRLRLRLRLR template struct audio_span_interleaved { public: using sample_type = SampleType; private: SampleType * const m_buffer; std::size_t m_channels; std::size_t m_frames; public: constexpr audio_span_interleaved(SampleType * buffer, std::size_t channels, std::size_t frames) noexcept : m_buffer(buffer) , m_channels(channels) , m_frames(frames) { return; } SampleType * const * data_planar() const noexcept { return nullptr; } SampleType * data() const noexcept { return m_buffer; } SampleType & operator()(std::size_t channel, std::size_t frame) const { return m_buffer[m_channels * frame + channel]; } bool is_contiguous() const noexcept { return true; } bool channels_are_contiguous() const noexcept { return false; } bool frames_are_contiguous() const noexcept { return true; } std::size_t size_channels() const noexcept { return m_channels; } std::size_t size_frames() const noexcept { return m_frames; } std::size_t size_samples() const noexcept { return m_channels * m_frames; } }; struct audio_span_frames_are_contiguous_t { }; struct audio_span_channels_are_contiguous_t { }; struct audio_span_channels_are_planar_t { }; struct audio_span_channels_are_planar_and_strided_t { }; // LRLRLRLRLR inline constexpr audio_span_frames_are_contiguous_t audio_span_frames_are_contiguous; // LLLLLRRRRR inline constexpr audio_span_channels_are_contiguous_t audio_span_channels_are_contiguous; // LLLLL RRRRR inline constexpr audio_span_channels_are_planar_t audio_span_channels_are_planar; // LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx inline constexpr audio_span_channels_are_planar_and_strided_t audio_span_channels_are_planar_and_strided; template struct audio_span { public: using sample_type = SampleType; private: union { SampleType * const contiguous; SampleType * const * const planes; } m_buffer; std::ptrdiff_t m_frame_stride; std::ptrdiff_t m_channel_stride; std::size_t m_channels; std::size_t m_frames; public: constexpr audio_span(audio_span_interleaved buffer) noexcept : m_frame_stride(static_cast(buffer.size_channels())) , m_channel_stride(1) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } constexpr audio_span(SampleType * buffer, std::size_t channels, std::size_t frames, audio_span_frames_are_contiguous_t) noexcept : m_frame_stride(static_cast(channels)) , m_channel_stride(1) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } constexpr audio_span(audio_span_contiguous buffer) noexcept : m_frame_stride(1) , m_channel_stride(buffer.size_frames()) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } constexpr audio_span(SampleType * buffer, std::size_t channels, std::size_t frames, audio_span_channels_are_contiguous_t) noexcept : m_frame_stride(1) , m_channel_stride(static_cast(frames)) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } constexpr audio_span(audio_span_planar buffer) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } constexpr audio_span(SampleType * const * planes, std::size_t channels, std::size_t frames, audio_span_channels_are_planar_t) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } constexpr audio_span(audio_span_planar_strided buffer) noexcept : m_frame_stride(static_cast(buffer.frame_stride())) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } constexpr audio_span(SampleType * const * planes, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride, audio_span_channels_are_planar_and_strided_t) noexcept : m_frame_stride(frame_stride) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } bool is_contiguous() const noexcept { return (m_channel_stride != 0); } SampleType * const * data_planar() const noexcept { return (!is_contiguous()) ? m_buffer.planes : nullptr; } SampleType * data() const noexcept { return is_contiguous() ? m_buffer.contiguous : nullptr; } SampleType & operator()(std::size_t channel, std::size_t frame) const { return is_contiguous() ? m_buffer.contiguous[(m_channel_stride * static_cast(channel)) + (m_frame_stride * static_cast(frame))] : m_buffer.planes[channel][frame * static_cast(m_frame_stride)]; } bool channels_are_contiguous() const noexcept { return (m_channel_stride == static_cast(m_frames)); } bool frames_are_contiguous() const noexcept { return (m_frame_stride == static_cast(m_channels)); } std::size_t size_channels() const noexcept { return m_channels; } std::size_t size_frames() const noexcept { return m_frames; } std::size_t size_samples() const noexcept { return m_channels * m_frames; } }; template struct audio_span_with_offset { public: using sample_type = typename Taudio_span::sample_type; private: Taudio_span m_buffer; std::size_t m_offset; public: constexpr audio_span_with_offset(Taudio_span buffer, std::size_t offsetFrames) noexcept : m_buffer(buffer) , m_offset(offsetFrames) { return; } sample_type * data() const noexcept { if (!is_contiguous()) { return nullptr; } return m_buffer.data() + (size_channels() * m_offset); } sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffer(channel, m_offset + frame); } bool is_contiguous() const noexcept { return m_buffer.is_contiguous() && m_buffer.frames_are_contiguous(); } bool channels_are_contiguous() const noexcept { return m_buffer.channels_are_contiguous(); } bool frames_are_contiguous() const noexcept { return m_buffer.frames_are_contiguous(); } std::size_t size_channels() const noexcept { return m_buffer.size_channels(); } std::size_t size_frames() const noexcept { return m_buffer.size_frames() - m_offset; } std::size_t size_samples() const noexcept { return size_channels() * size_frames(); } }; template inline audio_span_with_offset make_audio_span_with_offset(BufferType buf, std::size_t offsetFrames) noexcept { assert(offsetFrames <= buf.size_frames()); return audio_span_with_offset{buf, offsetFrames}; } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_AUDIO_SPAN_HPP