RAVENNAKIT
Loading...
Searching...
No Matches
audio_buffer_view.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2/*
3 * Project: RAVENNAKIT (RAVENNA / AES67 / ST2110-30 SDK)
4 * Copyright (c) 2024-2025 Sound on Digital
5 *
6 * This file is part of RAVENNAKIT.
7 *
8 * RAVENNAKIT is dual-licensed:
9 * 1) Under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version (the "AGPL License"); and
12 * 2) Under a commercial license from Sound on Digital, for customers who
13 * cannot (or do not wish to) comply with the AGPL License terms.
14 *
15 * If you obtained this file under the AGPL License, you may redistribute it
16 * and/or modify it under the terms of the AGPL License. See the LICENSE
17 * file in the project root for details.
18 *
19 * For commercial licensing, support, and other inquiries, please visit:
20 *
21 * https://ravennakit.com
22 *
23 */
24
25#pragma once
27
28namespace rav {
29
34template<class T>
36 public:
44 AudioBufferView(T* const* channels, const size_t num_channels, const size_t num_frames) :
45 channels_(channels), num_channels_(num_channels), num_frames_(num_frames) {}
46
54 friend bool operator==(const AudioBufferView& lhs, const AudioBufferView& rhs) {
55 if (lhs.num_channels_ != rhs.num_channels_ || lhs.num_frames_ != rhs.num_frames_) {
56 return false;
57 }
58 for (size_t ch = 0; ch < lhs.num_channels_; ++ch) {
59 if (!std::equal(lhs.channels_[ch], lhs.channels_[ch] + lhs.num_frames_, rhs.channels_[ch])) {
60 return false;
61 }
62 }
63 return true;
64 }
65
73 friend bool operator!=(const AudioBufferView& lhs, const AudioBufferView& rhs) {
74 return !(lhs == rhs);
75 }
76
80 [[nodiscard]] size_t num_channels() const {
81 return num_channels_;
82 }
83
87 [[nodiscard]] size_t num_frames() const {
88 return num_frames_;
89 }
90
97 const T* operator[](size_t channel_index) const {
98 RAV_ASSERT_DEBUG(channel_index < AudioBufferView<T>::num_channels(), "Channel index out of bounds");
99 return channels_[channel_index];
100 }
101
108 T* operator[](size_t channel_index) {
109 RAV_ASSERT_DEBUG(channel_index < num_channels_, "Channel index out of bounds");
110 return channels_[channel_index];
111 }
112
116 const T* const* data() const {
117 return channels_;
118 }
119
124 T* const* data() {
125 return channels_;
126 }
127
135 void set_sample(size_t channel_index, size_t frame_index, T value) {
136 RAV_ASSERT_DEBUG(channel_index < num_channels_, "Channel index out of bounds");
137 RAV_ASSERT_DEBUG(frame_index < num_frames_, "Frame index out of bounds");
138 channels_[channel_index][frame_index] = value;
139 }
140
144 void clear() const {
145 for (size_t i = 0; i < num_channels_; ++i) {
146 clear_audio_data(channels_[i], channels_[i] + num_frames_);
147 }
148 }
149
154 void clear(T value) const {
155 if (channels_ == nullptr) {
156 return;
157 }
158 for (size_t i = 0; i < num_channels_; ++i) {
159 std::fill(channels_[i], channels_[i] + num_frames_, value);
160 }
161 }
162
169 void clear(const size_t channel_index, const size_t start_sample, const size_t num_samples_to_clear) {
170 RAV_ASSERT_DEBUG(channel_index < num_channels(), "Channel index out of bounds");
171 RAV_ASSERT_DEBUG(start_sample + num_samples_to_clear <= num_frames(), "Sample index out of bounds");
172 clear_audio_data(channels_[channel_index] + start_sample, channels_[channel_index] + start_sample + num_samples_to_clear);
173 }
174
185 const size_t dst_start_frame, const size_t num_frames_to_copy, const T* const* src, const size_t src_num_channels,
186 const size_t src_start_frame = 0
187 ) {
188 RAV_ASSERT_DEBUG(src_num_channels == num_channels(), "Number of channels mismatch");
189 for (size_t i = 0; i < std::min(src_num_channels, num_channels()); ++i) {
190 copy_from(i, dst_start_frame, num_frames_to_copy, src[i] + src_start_frame);
191 }
192 }
193
201 void copy_from(const size_t dst_channel_index, const size_t dst_start_sample, const size_t num_samples_to_copy, const T* src) {
202 RAV_ASSERT_DEBUG(dst_channel_index < num_channels(), "Channel index out of bounds");
203 RAV_ASSERT_DEBUG(dst_start_sample + num_samples_to_copy <= num_frames(), "Sample index out of bounds");
204
205 if (num_samples_to_copy == 0) {
206 return;
207 }
208
209 std::memcpy(channels_[dst_channel_index] + dst_start_sample, src, num_samples_to_copy * sizeof(T));
210 }
211
221 const size_t src_start_frame, const size_t num_frames, T* const* dst, const size_t dst_num_channels,
222 const size_t dst_start_frame = 0
223 ) {
224 RAV_ASSERT_DEBUG(dst_num_channels == num_channels(), "Number of channels mismatch");
225 for (size_t i = 0; i < std::min(num_channels(), dst_num_channels); ++i) {
226 copy_to(i, src_start_frame, num_frames, dst[i] + dst_start_frame);
227 }
228 }
229
237 void copy_to(const size_t src_channel_index, const size_t src_start_sample, const size_t num_samples_to_copy, T* dst) {
238 RAV_ASSERT_DEBUG(src_channel_index < num_channels(), "Channel index out of bounds");
239 RAV_ASSERT_DEBUG(src_start_sample + num_samples_to_copy <= num_frames(), "Sample index out of bounds");
240
241 if (num_samples_to_copy == 0) {
242 return;
243 }
244
245 std::memcpy(dst, channels_[src_channel_index] + src_start_sample, num_samples_to_copy * sizeof(T));
246 }
247
253 [[nodiscard]] bool add(const AudioBufferView& other) {
254 static_assert(std::is_floating_point_v<T>, "Not supported for integer types");
255
256 if (num_channels_ != other.num_channels_ || num_frames_ != other.num_frames_) {
257 return false;
258 }
259
260 for (size_t ch = 0; ch < num_channels_; ++ch) {
261 for (size_t frame = 0; frame < num_frames_; ++frame) {
262 channels_[ch][frame] += other.channels_[ch][frame];
263 }
264 }
265
266 return true;
267 }
268
273 [[nodiscard]] bool is_valid() const {
274 return channels_ != nullptr && num_channels_ > 0 && num_frames_ > 0;
275 }
276
280 T find_max_abs() const {
281 std::remove_const_t<T> max_value = channels_[0][0];
282 for (size_t ch = 0; ch < num_channels_; ++ch) {
283 for (size_t frame = 0; frame < num_frames_; ++frame) {
284 max_value = std::max(max_value, std::fabs(channels_[ch][frame]));
285 }
286 }
287 return max_value;
288 }
289
294 T find_max_abs(const size_t channel_index) const {
295 if (channel_index >= num_channels_) {
296 return {};
297 }
298 std::remove_const_t<T> max_value = channels_[channel_index][0];
299 for (size_t frame = 0; frame < num_frames_; ++frame) {
300 max_value = std::max(max_value, std::fabs(channels_[channel_index][frame]));
301 }
302 return max_value;
303 }
304
311 return AudioBufferView(channels_, std::min(num_channels, num_channels_), num_frames_);
312 }
313
320 return AudioBufferView(channels_, num_channels_, std::min(num_frames, num_frames_));
321 }
322
327 return AudioBufferView<std::add_const_t<T>>(channels_, num_channels_, num_frames_);
328 }
329
330 protected:
337 void update(T* const* channels, const size_t num_channels, const size_t num_frames) {
338 channels_ = num_channels > 0 && num_frames > 0 ? channels : nullptr;
339 num_channels_ = num_channels;
340 num_frames_ = num_frames;
341 }
342
343 private:
344 T* const* channels_ {};
345 size_t num_channels_ {};
346 size_t num_frames_ {};
347
348 template<class First, class Last>
349 void clear_audio_data(First first, Last last) const {
350 if constexpr (std::is_unsigned_v<T>) {
351 std::fill(first, last, std::numeric_limits<T>::max() / 2 + 1);
352 } else {
353 std::fill(first, last, T {});
354 }
355 }
356};
357
358} // namespace rav
#define RAV_ASSERT_DEBUG(condition, message)
If RAV_DEBUG is enabled, asserts condition to be true, otherwise:
Definition assert.hpp:119
friend bool operator!=(const AudioBufferView &lhs, const AudioBufferView &rhs)
Compares two audio buffers for inequality.
void clear() const
Clears the buffer by setting all samples to zero.
void clear(const size_t channel_index, const size_t start_sample, const size_t num_samples_to_clear)
Clear a range of samples in a channel, without bounds checking.
AudioBufferView(T *const *channels, const size_t num_channels, const size_t num_frames)
Constructs an audio buffer view with the given channels, number of channels, and number of frames.
void copy_to(const size_t src_start_frame, const size_t num_frames, T *const *dst, const size_t dst_num_channels, const size_t dst_start_frame=0)
Copies data from all channels of this buffer into dst.
T * operator[](size_t channel_index)
Accesses the channel at the given index Does not perform bounds checking.
void update(T *const *channels, const size_t num_channels, const size_t num_frames)
Updates the channel pointers, number of channels and number of frames.
AudioBufferView with_num_frames(const size_t num_frames)
Returns a copy of this view with given number of frames.
AudioBufferView< std::add_const_t< T > > const_view() const
const T * operator[](size_t channel_index) const
Accesses the channel at the given index.
friend bool operator==(const AudioBufferView &lhs, const AudioBufferView &rhs)
Compares two audio buffers for equality.
bool add(const AudioBufferView &other)
Adds the samples of another audio buffer view to this audio buffer view.
void copy_from(const size_t dst_start_frame, const size_t num_frames_to_copy, const T *const *src, const size_t src_num_channels, const size_t src_start_frame=0)
Copies data from all channels of src into all channels of this buffer.
void set_sample(size_t channel_index, size_t frame_index, T value)
Sets the value of an individual sample.
void copy_from(const size_t dst_channel_index, const size_t dst_start_sample, const size_t num_samples_to_copy, const T *src)
Copies data from src into this buffer, without bounds checking.
void clear(T value) const
Clears the buffer by setting all samples to the given value.
void copy_to(const size_t src_channel_index, const size_t src_start_sample, const size_t num_samples_to_copy, T *dst)
Copies data from this buffer into dst.
AudioBufferView with_num_channels(const size_t num_channels)
Returns a copy of this view with given number of channels.
T find_max_abs(const size_t channel_index) const
@channel_index The index of the channel to find the maximum value for.
const T *const * data() const