1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LB2_AUDIO_BUFFER_H_ 18 #define LB2_AUDIO_BUFFER_H_ 19 20 #include <algorithm> 21 #include <functional> 22 #include <memory> 23 #include <string.h> 24 25 #include <android/log.h> 26 27 #include "lb2/sample.h" 28 #include "lb2/util.h" 29 30 // Implements sample / frame / byte count conversions. Not to be used directly. 31 template<class T> 32 class CountsConverter { 33 public: 34 size_t getDataSize() const { return getSampleCount() * sizeof(T); } 35 size_t getFrameCount() const { return mFrameCount; } 36 size_t getFrameSize() const { return mChannelCount * sizeof(T); } 37 size_t getSampleCount() const { return mFrameCount * mChannelCount; } 38 int getChannelCount() const { return mChannelCount; } 39 40 protected: 41 CountsConverter(size_t frameCount, int channelCount) : 42 mFrameCount(frameCount), mChannelCount(channelCount) {} 43 CountsConverter(const CountsConverter<T>&) = default; 44 CountsConverter(CountsConverter<T>&&) = default; 45 CountsConverter<T>& operator=(const CountsConverter<T>&) = default; 46 CountsConverter<T>& operator=(CountsConverter<T>&&) = default; 47 48 private: 49 // Fields are logically const, but can be overwritten during an object assignment. 50 size_t mFrameCount; 51 int mChannelCount; 52 }; 53 54 // Implements the common parts of AudioBuffer and AudioBufferView. 55 // Not to be used directly. 56 // 57 // Although AudioBuffer could be considered as an extension of AudioBufferView, 58 // they have different copy/move semantics, and thus AudioBuffer 59 // doesn't satisfy Liskov Substitution Principle. That's why these classes are 60 // implemented as siblings instead, with an implicit conversion constructor of 61 // AudioBufferView from AudioBuffer. 62 template<class T> 63 class AudioBufferBase : public CountsConverter<T> { 64 public: 65 void clear() { memset(mData, 0, CountsConverter<T>::getDataSize()); } 66 T* getData() const { return mData; } 67 T* getFrameAt(int offsetInFrames) const { 68 return mData + offsetInFrames * CountsConverter<T>::getChannelCount(); 69 } 70 71 protected: 72 static constexpr size_t npos = static_cast<size_t>(-1); 73 74 AudioBufferBase(T* const data, size_t frameCount, int channelCount) 75 : CountsConverter<T>(frameCount, channelCount), mData(data) {} 76 AudioBufferBase(const AudioBufferBase<T>&) = default; 77 AudioBufferBase(AudioBufferBase<T>&&) = default; 78 AudioBufferBase<T>& operator=(const AudioBufferBase<T>&) = default; 79 AudioBufferBase<T>& operator=(AudioBufferBase<T>&&) = default; 80 81 AudioBufferBase<T> getView(int offsetInFrames, size_t lengthInFrames) const { 82 if (offsetInFrames < 0) { 83 __android_log_assert("assert", "lb2", "Negative buffer offset %d", offsetInFrames); 84 } 85 if (lengthInFrames > CountsConverter<T>::getFrameCount() - offsetInFrames) { 86 lengthInFrames = CountsConverter<T>::getFrameCount() - offsetInFrames; 87 } 88 return AudioBufferBase<T>( 89 getFrameAt(offsetInFrames), lengthInFrames, CountsConverter<T>::getChannelCount()); 90 } 91 92 private: 93 // Fields are logically const, but can be overwritten during an object assignment. 94 T* mData; 95 }; 96 97 template<class T> class AudioBufferView; 98 99 // Container for PCM audio data, allocates the data buffer via 'new' and owns it. 100 // Allows modification of the data. Does not support copying, 101 // move only. For passing audio data around it's recommended 102 // to use instances of AudioBufferView class instead. 103 template<class T> 104 class AudioBuffer : public AudioBufferBase<T> { 105 public: 106 // Null AudioBuffer constructor. 107 constexpr AudioBuffer(): AudioBufferBase<T>(nullptr, 0, 1), mBuffer() {} 108 AudioBuffer(size_t frameCount, int channelCount) 109 : AudioBufferBase<T>(new T[frameCount * channelCount], frameCount, channelCount), 110 mBuffer(AudioBufferBase<T>::getData()) { 111 AudioBufferBase<T>::clear(); 112 } 113 AudioBuffer(const AudioBuffer<T>&) = delete; 114 AudioBuffer(AudioBuffer<T>&&) = default; 115 AudioBuffer<T>& operator=(const AudioBuffer<T>&) = delete; 116 AudioBuffer<T>& operator=(AudioBuffer<T>&&) = default; 117 118 AudioBufferView<T> getView( 119 int offsetInFrames = 0, size_t lengthInFrames = AudioBufferBase<T>::npos) const { 120 return AudioBufferBase<T>::getView(offsetInFrames, lengthInFrames); 121 } 122 123 private: 124 std::unique_ptr<T[]> mBuffer; 125 }; 126 127 // Lightweight view into the PCM audio data provided by AudioBuffer. 128 // AudioBufferView does *not* own buffer memory. Data can be modified 129 // via the view. Thanks to its small size, should be passed by value. 130 template<class T> 131 class AudioBufferView : public AudioBufferBase<T> { 132 public: 133 AudioBufferView(T* const data, size_t frameCount, int channelCount) 134 : AudioBufferBase<T>(data, frameCount, channelCount) {} 135 // Implicit conversion from AudioBufferBase. 136 AudioBufferView(const AudioBufferBase<T>& b) 137 : AudioBufferBase<T>(b.getData(), b.getFrameCount(), b.getChannelCount()) {} 138 AudioBufferView(const AudioBufferView<T>&) = default; 139 AudioBufferView(AudioBufferView<T>&&) = default; 140 AudioBufferView<T>& operator=(const AudioBufferView<T>&) = default; 141 AudioBufferView<T>& operator=(AudioBufferView<T>&&) = default; 142 143 AudioBufferView<T> getView( 144 int offsetInFrames = 0, size_t lengthInFrames = AudioBufferBase<T>::npos) const { 145 return AudioBufferBase<T>::getView(offsetInFrames, lengthInFrames); 146 } 147 }; 148 149 150 template<class S, class D> 151 inline void convertAudioBufferViewType(AudioBufferView<S> src, AudioBufferView<D> dst) { 152 if (src.getChannelCount() != dst.getChannelCount()) { 153 __android_log_assert("assert", "lb2", "Buffer channel counts differ: %d != %d", 154 src.getChannelCount(), dst.getChannelCount()); 155 } 156 if (src.getSampleCount() != dst.getSampleCount()) { 157 __android_log_assert("assert", "lb2", "Buffer sample counts differ: %lld != %lld", 158 (long long)src.getSampleCount(), (long long)dst.getChannelCount()); 159 } 160 for (size_t i = 0; i < src.getSampleCount(); ++i) { 161 dst.getData()[i] = convertSampleType(src.getData()[i]); 162 } 163 } 164 165 template<class T> 166 inline void forEachFrame(AudioBufferView<T> src, AudioBufferView<T> dst, 167 std::function<void(T* srcFrame, T* dstFrame)> op) { 168 T *srcData = src.getData(); 169 T *dstData = dst.getData(); 170 for (size_t i = 0; 171 i < std::min(src.getFrameCount(), dst.getFrameCount()); 172 ++i, srcData += src.getChannelCount(), dstData += dst.getChannelCount()) { 173 op(srcData, dstData); 174 } 175 } 176 177 // Copies audio buffers data frame by frame. Initially fills the 178 // destination buffer with zeroes. Ignores extra channels in the 179 // source buffer. 180 template<class T> 181 inline void strideCopyAudioBufferViewData(AudioBufferView<T> src, AudioBufferView<T> dst) { 182 dst.clear(); 183 forEachFrame<T>(src, dst, 184 [&](T* srcFrame, T* dstFrame) { 185 memcpy(dstFrame, srcFrame, std::min(src.getFrameSize(), dst.getFrameSize())); 186 }); 187 } 188 189 // Copies audio buffers data frame by frame. If there are more 190 // channels in the destination buffer than in the source buffer, the source 191 // buffer content is duplicated to the extra channels until the entire frame 192 // gets filled. E.g. if the source buffer has two channels, and the destination 193 // buffer has five, then each frame of the destination buffer will be filled 194 // as follows: 12121. 195 // If the destination buffer has more frames than the source, the extra frames 196 // a zeroed out. 197 template<class T> 198 inline void fillCopyAudioBufferViewData(AudioBufferView<T> src, AudioBufferView<T> dst) { 199 dst.clear(); 200 const int srcFrameCopies = wholeMultiplier(dst.getChannelCount(), src.getChannelCount()); 201 // A temporary buffer allowing to avoid dealing with copying a fraction of the source frame. 202 T srcFramePatch[srcFrameCopies * src.getChannelCount()]; 203 forEachFrame<T>(src, dst, 204 [&](T* srcFrame, T* dstFrame) { 205 // Fill the temporary buffer with copies of the source frame. 206 T* patch = srcFramePatch; 207 for (int j = 0; j < srcFrameCopies; ++j, patch += src.getChannelCount()) { 208 memcpy(patch, srcFrame, src.getFrameSize()); 209 } 210 memcpy(dstFrame, srcFramePatch, dst.getFrameSize()); 211 }); 212 } 213 214 215 // Copies audio data between the AudioBufferViews of the same type. 216 // Any missing audio data in the source buffer (not enough frames, or less 217 // channels) is filled with zeroes in the destination buffer. 218 template<class T> 219 inline void copyAudioBufferViewData(AudioBufferView<T> src, AudioBufferView<T> dst) { 220 if (src.getChannelCount() == dst.getChannelCount()) { 221 size_t framesToCopy = std::min(src.getFrameCount(), dst.getFrameCount()); 222 if (framesToCopy > 0) { 223 memcpy(dst.getData(), src.getData(), framesToCopy * dst.getFrameSize()); 224 } 225 if (dst.getFrameCount() > framesToCopy) { 226 dst.getView(framesToCopy).clear(); 227 } 228 } else { 229 fillCopyAudioBufferViewData(src, dst); 230 } 231 } 232 233 #endif // LB2_AUDIO_BUFFER_H_ 234