winamp/Src/external_dependencies/openmpt-trunk/src/mpt/audio/span.hpp
2024-09-24 14:54:57 +02:00

403 lines
10 KiB
C++

/* 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 <cassert>
#include <cstddef>
namespace mpt {
inline namespace MPT_INLINE_NS {
// LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx
template <typename SampleType>
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<std::ptrdiff_t>(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 <typename SampleType>
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 <typename SampleType>
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 <typename SampleType>
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 <typename SampleType>
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<SampleType> buffer) noexcept
: m_frame_stride(static_cast<std::ptrdiff_t>(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<std::ptrdiff_t>(channels))
, m_channel_stride(1)
, m_channels(channels)
, m_frames(frames) {
m_buffer.contiguous = buffer;
}
constexpr audio_span(audio_span_contiguous<SampleType> 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<std::ptrdiff_t>(frames))
, m_channels(channels)
, m_frames(frames) {
m_buffer.contiguous = buffer;
}
constexpr audio_span(audio_span_planar<SampleType> 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<SampleType> buffer) noexcept
: m_frame_stride(static_cast<std::ptrdiff_t>(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<std::ptrdiff_t>(channel)) + (m_frame_stride * static_cast<std::ptrdiff_t>(frame))] : m_buffer.planes[channel][frame * static_cast<std::ptrdiff_t>(m_frame_stride)];
}
bool channels_are_contiguous() const noexcept {
return (m_channel_stride == static_cast<std::ptrdiff_t>(m_frames));
}
bool frames_are_contiguous() const noexcept {
return (m_frame_stride == static_cast<std::ptrdiff_t>(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 <typename Taudio_span>
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 <typename BufferType>
inline audio_span_with_offset<BufferType> make_audio_span_with_offset(BufferType buf, std::size_t offsetFrames) noexcept {
assert(offsetFrames <= buf.size_frames());
return audio_span_with_offset<BufferType>{buf, offsetFrames};
}
} // namespace MPT_INLINE_NS
} // namespace mpt
#endif // MPT_AUDIO_SPAN_HPP