audio_view.h (11302B)
1 /* 2 * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_AUDIO_AUDIO_VIEW_H_ 12 #define API_AUDIO_AUDIO_VIEW_H_ 13 14 #include <cstddef> 15 #include <iterator> 16 #include <variant> 17 #include <vector> 18 19 #include "api/array_view.h" 20 #include "rtc_base/checks.h" 21 22 namespace webrtc { 23 24 // This file contains 3 types of view classes: 25 // 26 // * MonoView<>: A single channel contiguous buffer of samples. 27 // 28 // * InterleavedView<>: Channel samples are interleaved (side-by-side) in 29 // the buffer. A single channel InterleavedView<> is the same thing as a 30 // MonoView<> 31 // 32 // * DeinterleavedView<>: Each channel's samples are contiguous within the 33 // buffer. Channels can be enumerated and accessing the individual channel 34 // data is done via MonoView<>. 35 // 36 // The views are comparable to and built on ArrayView<> but add 37 // audio specific properties for the dimensions of the buffer and the above 38 // specialized [de]interleaved support. 39 // 40 // There are also a few generic utility functions that can simplify 41 // generic code for supporting more than one type of view. 42 43 // MonoView<> represents a view over a single contiguous, audio buffer. This 44 // can be either an single channel (mono) interleaved buffer (e.g. AudioFrame), 45 // or a de-interleaved channel (e.g. from AudioBuffer). 46 template <typename T> 47 using MonoView = ArrayView<T>; 48 49 // The maximum number of audio channels supported by WebRTC encoders, decoders 50 // and the AudioFrame class. 51 // TODO(peah, tommi): Should kMaxNumberOfAudioChannels be 16 rather than 24? 52 // The reason is that AudioFrame's max number of samples is 7680, which can 53 // hold 16 10ms 16bit channels at 48 kHz (and not 24 channels). 54 static constexpr size_t kMaxNumberOfAudioChannels = 24; 55 56 // InterleavedView<> is a view over an interleaved audio buffer (e.g. from 57 // AudioFrame). 58 template <typename T> 59 class InterleavedView { 60 public: 61 using value_type = T; 62 63 InterleavedView() = default; 64 65 template <typename U> 66 InterleavedView(U* data, size_t samples_per_channel, size_t num_channels) 67 : num_channels_(num_channels), 68 samples_per_channel_(samples_per_channel), 69 data_(data, num_channels * samples_per_channel) { 70 RTC_DCHECK_LE(num_channels_, kMaxNumberOfAudioChannels); 71 RTC_DCHECK(num_channels_ == 0u || samples_per_channel_ != 0u); 72 } 73 74 // Construct an InterleavedView from a C-style array. Samples per channels 75 // is calculated based on the array size / num_channels. 76 template <typename U, size_t N> 77 InterleavedView(U (&array)[N], // NOLINT 78 size_t num_channels) 79 : InterleavedView(array, N / num_channels, num_channels) { 80 RTC_DCHECK_EQ(N % num_channels, 0u); 81 } 82 83 template <typename U> 84 InterleavedView(const InterleavedView<U>& other) 85 : num_channels_(other.num_channels()), 86 samples_per_channel_(other.samples_per_channel()), 87 data_(other.data()) {} 88 89 size_t num_channels() const { return num_channels_; } 90 size_t samples_per_channel() const { return samples_per_channel_; } 91 ArrayView<T> data() const { return data_; } 92 bool empty() const { return data_.empty(); } 93 size_t size() const { return data_.size(); } 94 95 MonoView<T> AsMono() const { 96 RTC_DCHECK_EQ(num_channels(), 1u); 97 RTC_DCHECK_EQ(data_.size(), samples_per_channel_); 98 return data_; 99 } 100 101 // A simple wrapper around memcpy that includes checks for properties. 102 // TODO(tommi): Consider if this can be utility function for both interleaved 103 // and deinterleaved views. 104 template <typename U> 105 void CopyFrom(const InterleavedView<U>& source) { 106 static_assert(sizeof(T) == sizeof(U), ""); 107 RTC_DCHECK_EQ(num_channels(), source.num_channels()); 108 RTC_DCHECK_EQ(samples_per_channel(), source.samples_per_channel()); 109 RTC_DCHECK_GE(data_.size(), source.data().size()); 110 const auto data = source.data(); 111 memcpy(&data_[0], &data[0], data.size() * sizeof(U)); 112 } 113 114 T& operator[](size_t idx) const { return data_[idx]; } 115 T* begin() const { return data_.begin(); } 116 T* end() const { return data_.end(); } 117 const T* cbegin() const { return data_.cbegin(); } 118 const T* cend() const { return data_.cend(); } 119 std::reverse_iterator<T*> rbegin() const { return data_.rbegin(); } 120 std::reverse_iterator<T*> rend() const { return data_.rend(); } 121 std::reverse_iterator<const T*> crbegin() const { return data_.crbegin(); } 122 std::reverse_iterator<const T*> crend() const { return data_.crend(); } 123 124 private: 125 // TODO(tommi): Consider having these both be stored as uint16_t to 126 // save a few bytes per view. Use `dchecked_cast` to support size_t during 127 // construction. 128 size_t num_channels_ = 0u; 129 size_t samples_per_channel_ = 0u; 130 ArrayView<T> data_; 131 }; 132 133 template <typename T> 134 class DeinterleavedView { 135 public: 136 using value_type = T; 137 138 DeinterleavedView() = default; 139 140 // Construct a view where all the channels are coallocated in a single buffer. 141 template <typename U> 142 DeinterleavedView(U* data, size_t samples_per_channel, size_t num_channels) 143 : num_channels_(num_channels), 144 samples_per_channel_(samples_per_channel), 145 data_(data) {} 146 147 // Construct a view from an array of channel pointers where the channels 148 // may all be allocated seperately. 149 template <typename U> 150 DeinterleavedView(U* const* channels, 151 size_t samples_per_channel, 152 size_t num_channels) 153 : num_channels_(num_channels), 154 samples_per_channel_(samples_per_channel), 155 data_(channels) {} 156 157 // Construct a view from an array of channel pointers where the pointers are 158 // helt in a `std::vector<>`. 159 template <typename U> 160 DeinterleavedView(const std::vector<U*>& channels, size_t samples_per_channel) 161 : num_channels_(channels.size()), 162 samples_per_channel_(samples_per_channel), 163 data_(channels.data()) {} 164 165 // Construct a view from another view. Note that the type of 166 // the other view may be different from the current type and 167 // therefore the internal data types may not be exactly the 168 // same, but still compatible. 169 // E.g.: 170 // DeinterleavedView<float> mutable_view; 171 // DeinterleavedView<const float> const_view(mutable_view); 172 template <typename U> 173 DeinterleavedView(const DeinterleavedView<U>& other) 174 : num_channels_(other.num_channels_), 175 samples_per_channel_(other.samples_per_channel()) { 176 if (other.is_ptr_array()) { 177 data_ = std::get<U* const*>(other.data_); 178 } else { 179 data_ = std::get<U*>(other.data_); 180 } 181 } 182 183 // Returns a deinterleaved channel where `idx` is the zero based index, 184 // in the range [0 .. num_channels()-1]. 185 MonoView<T> operator[](size_t idx) const { 186 RTC_DCHECK_LT(idx, num_channels()); 187 if (is_ptr_array()) 188 return MonoView<T>(std::get<T* const*>(data_)[idx], samples_per_channel_); 189 return MonoView<T>(&std::get<T*>(data_)[idx * samples_per_channel_], 190 samples_per_channel_); 191 } 192 193 size_t num_channels() const { return num_channels_; } 194 size_t samples_per_channel() const { return samples_per_channel_; } 195 bool empty() const { 196 return num_channels_ == 0u || samples_per_channel_ == 0u; 197 } 198 size_t size() const { return num_channels_ * samples_per_channel_; } 199 200 // Returns the first (and possibly only) channel. 201 MonoView<T> AsMono() const { 202 RTC_DCHECK_GE(num_channels(), 1u); 203 return (*this)[0]; 204 } 205 206 // Zeros out all samples in channels represented by the view. 207 void Clear() { 208 for (size_t i = 0u; i < num_channels_; ++i) { 209 MonoView<T> view = (*this)[i]; 210 ClearSamples(view); 211 } 212 } 213 214 private: 215 bool is_ptr_array() const { return std::holds_alternative<T* const*>(data_); } 216 217 template <typename U> 218 friend class DeinterleavedView; 219 220 size_t num_channels_ = 0u; 221 size_t samples_per_channel_ = 0u; 222 std::variant<T* const*, T*> data_; 223 }; 224 225 template <typename T> 226 constexpr size_t NumChannels(const MonoView<T>& /* view */) { 227 return 1u; 228 } 229 230 template <typename T> 231 size_t NumChannels(const InterleavedView<T>& view) { 232 return view.num_channels(); 233 } 234 235 template <typename T> 236 size_t NumChannels(const DeinterleavedView<T>& view) { 237 return view.num_channels(); 238 } 239 240 template <typename T> 241 constexpr bool IsMono(const MonoView<T>& /* view */) { 242 return true; 243 } 244 245 template <typename T> 246 constexpr bool IsInterleavedView(const MonoView<T>& /* view */) { 247 return true; 248 } 249 250 template <typename T> 251 constexpr bool IsInterleavedView(const InterleavedView<T>& /* view */) { 252 return true; 253 } 254 255 template <typename T> 256 constexpr bool IsInterleavedView(const DeinterleavedView<const T>& /* view */) { 257 return false; 258 } 259 260 template <typename T> 261 bool IsMono(const InterleavedView<T>& view) { 262 return NumChannels(view) == 1u; 263 } 264 265 template <typename T> 266 bool IsMono(const DeinterleavedView<T>& view) { 267 return NumChannels(view) == 1u; 268 } 269 270 template <typename T> 271 size_t SamplesPerChannel(const MonoView<T>& view) { 272 return view.size(); 273 } 274 275 template <typename T> 276 size_t SamplesPerChannel(const InterleavedView<T>& view) { 277 return view.samples_per_channel(); 278 } 279 280 template <typename T> 281 size_t SamplesPerChannel(const DeinterleavedView<T>& view) { 282 return view.samples_per_channel(); 283 } 284 // A simple wrapper around memcpy that includes checks for properties. 285 // The parameter order is the same as for memcpy(), first destination then 286 // source. 287 template <typename D, typename S> 288 void CopySamples(D& destination, const S& source) { 289 static_assert( 290 sizeof(typename D::value_type) == sizeof(typename S::value_type), ""); 291 // Here we'd really like to do 292 // static_assert(IsInterleavedView(destination) == IsInterleavedView(source), 293 // ""); 294 // but the compiler doesn't like it inside this template function for 295 // some reason. The following check is an approximation but unfortunately 296 // means that copying between a MonoView and single channel interleaved or 297 // deinterleaved views wouldn't work. 298 // static_assert(sizeof(destination) == sizeof(source), 299 // "Incompatible view types"); 300 RTC_DCHECK_EQ(NumChannels(destination), NumChannels(source)); 301 RTC_DCHECK_EQ(SamplesPerChannel(destination), SamplesPerChannel(source)); 302 RTC_DCHECK_GE(destination.size(), source.size()); 303 memcpy(&destination[0], &source[0], 304 source.size() * sizeof(typename S::value_type)); 305 } 306 307 // Sets all the samples in a view to 0. This template function is a simple 308 // wrapper around `memset()` but adds the benefit of automatically calculating 309 // the byte size from the number of samples and sample type. 310 template <typename T> 311 void ClearSamples(T& view) { 312 memset(&view[0], 0, view.size() * sizeof(typename T::value_type)); 313 } 314 315 // Same as `ClearSamples()` above but allows for clearing only the first 316 // `sample_count` number of samples. 317 template <typename T> 318 void ClearSamples(T& view, size_t sample_count) { 319 RTC_DCHECK_LE(sample_count, view.size()); 320 memset(&view[0], 0, sample_count * sizeof(typename T::value_type)); 321 } 322 323 } // namespace webrtc 324 325 #endif // API_AUDIO_AUDIO_VIEW_H_