Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
buffer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cstddef>
5#include <cstdlib>
6#include <limits>
7#include <span>
8#include <stdexcept>
9#include <vector>
10
11namespace pulp::audio {
12
29template<typename SampleType = float>
31public:
32 BufferView() = default;
33
38 BufferView(SampleType* const* channel_ptrs, std::size_t num_channels, std::size_t num_samples)
39 : channels_(channel_ptrs)
40 , num_channels_(num_channels)
41 , num_samples_(num_samples)
42 {}
43
49 BufferView slice(std::size_t start, std::size_t length) const {
50 if (start > num_samples_) start = num_samples_;
51 const auto available = num_samples_ - start;
52 if (length > available) length = available;
53 return BufferView(channels_, num_channels_, length, sample_offset_ + start);
54 }
55
58 std::span<SampleType> channel(std::size_t index) {
59 return {channels_[index] + sample_offset_, num_samples_};
60 }
61
63 std::span<const SampleType> channel(std::size_t index) const {
64 return {channels_[index] + sample_offset_, num_samples_};
65 }
66
68 SampleType* channel_ptr(std::size_t index) { return channels_[index] + sample_offset_; }
70 const SampleType* channel_ptr(std::size_t index) const { return channels_[index] + sample_offset_; }
71
74 bool has_valid_channels() const noexcept {
75 if (num_channels_ != 0 && channels_ == nullptr)
76 return false;
77 for (std::size_t channel = 0; channel < num_channels_; ++channel)
78 if (channels_[channel] == nullptr)
79 return false;
80 return true;
81 }
82
83 std::size_t num_channels() const { return num_channels_; }
84 std::size_t num_samples() const { return num_samples_; }
85
87 bool empty() const { return num_channels_ == 0 || num_samples_ == 0; }
88
90 void clear() {
91 for (std::size_t ch = 0; ch < num_channels_; ++ch) {
92 std::fill_n(channels_[ch] + sample_offset_, num_samples_, SampleType{0});
93 }
94 }
95
96private:
97 BufferView(SampleType* const* channel_ptrs, std::size_t num_channels,
98 std::size_t num_samples, std::size_t sample_offset)
99 : channels_(channel_ptrs)
100 , num_channels_(num_channels)
101 , num_samples_(num_samples)
102 , sample_offset_(sample_offset)
103 {}
104
105 SampleType* const* channels_ = nullptr;
106 std::size_t num_channels_ = 0;
107 std::size_t num_samples_ = 0;
108 std::size_t sample_offset_ = 0;
109};
110
118template<typename SampleType = float>
119class Buffer {
120public:
121 Buffer() = default;
122
126 Buffer(std::size_t num_channels, std::size_t num_samples)
127 {
129 }
130
131 Buffer(const Buffer& other)
132 : data_(other.data_)
133 , num_channels_(other.num_channels_)
134 , num_samples_(other.num_samples_) {
135 refresh_channel_pointers();
136 }
137
138 Buffer& operator=(const Buffer& other) {
139 if (this != &other) {
140 data_ = other.data_;
141 num_channels_ = other.num_channels_;
142 num_samples_ = other.num_samples_;
143 refresh_channel_pointers();
144 }
145 return *this;
146 }
147
148 Buffer(Buffer&& other)
149 : data_(std::move(other.data_))
150 , num_channels_(other.num_channels_)
151 , num_samples_(other.num_samples_) {
152 refresh_channel_pointers();
153 other.num_channels_ = 0;
154 other.num_samples_ = 0;
155 other.ptrs_.clear();
156 }
157
159 if (this != &other) {
160 data_ = std::move(other.data_);
161 num_channels_ = other.num_channels_;
162 num_samples_ = other.num_samples_;
163 refresh_channel_pointers();
164 other.num_channels_ = 0;
165 other.num_samples_ = 0;
166 other.ptrs_.clear();
167 }
168 return *this;
169 }
170
172 void resize(std::size_t num_channels, std::size_t num_samples) {
173 const auto sample_count = checked_sample_count(num_channels, num_samples);
174 num_channels_ = num_channels;
175 num_samples_ = num_samples;
176 data_.resize(sample_count, SampleType{0});
177 refresh_channel_pointers();
178 }
179
183 return {ptrs_.data(), num_channels_, num_samples_};
184 }
185
191 return {ptrs_.data(), num_channels_, num_samples_};
192 }
193
195 std::span<SampleType> channel(std::size_t index) {
196 return {ptrs_[index], num_samples_};
197 }
198
200 std::span<const SampleType> channel(std::size_t index) const {
201 return {ptrs_[index], num_samples_};
202 }
203
204 std::size_t num_channels() const { return num_channels_; }
205 std::size_t num_samples() const { return num_samples_; }
208 std::size_t allocated_sample_capacity() const noexcept { return data_.capacity(); }
209
211 void release() noexcept {
212 std::vector<SampleType>().swap(data_);
213 std::vector<SampleType*>().swap(ptrs_);
214 num_channels_ = 0;
215 num_samples_ = 0;
216 }
217
219 void clear() {
220 std::fill(data_.begin(), data_.end(), SampleType{0});
221 }
222
223private:
224 static std::size_t checked_sample_count(std::size_t num_channels,
225 std::size_t num_samples) {
226 if (num_channels != 0 &&
227 num_samples > std::numeric_limits<std::size_t>::max() / num_channels) {
228#if defined(__cpp_exceptions) && __cpp_exceptions
229 throw std::length_error("audio buffer dimensions overflow");
230#else
231 // No C++ exception runtime (e.g. wasi-sdk libc++ built without EH).
232 // An overflow here is a programming error, not a recoverable input.
233 std::abort();
234#endif
235 }
236 return num_channels * num_samples;
237 }
238
239 void refresh_channel_pointers() {
240 ptrs_.resize(num_channels_);
241 for (std::size_t ch = 0; ch < num_channels_; ++ch) {
242 ptrs_[ch] = data_.data() + ch * num_samples_;
243 }
244 }
245
246 std::vector<SampleType> data_;
247 std::vector<SampleType*> ptrs_;
248 std::size_t num_channels_ = 0;
249 std::size_t num_samples_ = 0;
250};
251
252} // namespace pulp::audio
Non-owning view over multi-channel audio sample data.
Definition buffer.hpp:30
std::span< const SampleType > channel(std::size_t index) const
Get a span over all samples in one channel.
Definition buffer.hpp:63
bool empty() const
True if the buffer has zero channels or zero samples.
Definition buffer.hpp:87
std::size_t num_samples() const
Definition buffer.hpp:84
std::size_t num_channels() const
Definition buffer.hpp:83
BufferView slice(std::size_t start, std::size_t length) const
Create a non-owning slice over this view.
Definition buffer.hpp:49
BufferView(SampleType *const *channel_ptrs, std::size_t num_channels, std::size_t num_samples)
Construct from an array of per-channel pointers.
Definition buffer.hpp:38
std::span< SampleType > channel(std::size_t index)
Get a span over all samples in one channel.
Definition buffer.hpp:58
const SampleType * channel_ptr(std::size_t index) const
Raw pointer to one channel's sample data.
Definition buffer.hpp:70
void clear()
Zero-fill all channels.
Definition buffer.hpp:90
SampleType * channel_ptr(std::size_t index)
Raw pointer to one channel's sample data.
Definition buffer.hpp:68
bool has_valid_channels() const noexcept
Check channel storage before a caller dereferences a borrowed host view.
Definition buffer.hpp:74
Buffer & operator=(Buffer &&other)
Definition buffer.hpp:158
Buffer & operator=(const Buffer &other)
Definition buffer.hpp:138
Buffer(const Buffer &other)
Definition buffer.hpp:131
BufferView< const SampleType > view() const
Create a non-owning BufferView over this buffer's data.
Definition buffer.hpp:190
void resize(std::size_t num_channels, std::size_t num_samples)
Resize the buffer, reallocating if necessary. New samples are zero-filled.
Definition buffer.hpp:172
std::size_t num_channels() const
Definition buffer.hpp:204
std::span< SampleType > channel(std::size_t index)
Get a span over all samples in one channel.
Definition buffer.hpp:195
void release() noexcept
Release all owned sample and channel-pointer storage.
Definition buffer.hpp:211
std::size_t allocated_sample_capacity() const noexcept
Number of sample elements retained by the backing allocation.
Definition buffer.hpp:208
std::span< const SampleType > channel(std::size_t index) const
Get a span over all samples in one channel.
Definition buffer.hpp:200
BufferView< SampleType > view()
Create a non-owning BufferView over this buffer's data.
Definition buffer.hpp:182
std::size_t num_samples() const
Definition buffer.hpp:205
Buffer(std::size_t num_channels, std::size_t num_samples)
Allocate a buffer with the given dimensions, zero-filled.
Definition buffer.hpp:126
Buffer(Buffer &&other)
Definition buffer.hpp:148
void clear()
Zero-fill all channels.
Definition buffer.hpp:219
Definition analyzer_provider.hpp:12
STL namespace.