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:
getDataSize()34 size_t getDataSize() const { return getSampleCount() * sizeof(T); }
getFrameCount()35 size_t getFrameCount() const { return mFrameCount; }
getFrameSize()36 size_t getFrameSize() const { return mChannelCount * sizeof(T); }
getSampleCount()37 size_t getSampleCount() const { return mFrameCount * mChannelCount; }
getChannelCount()38 int getChannelCount() const { return mChannelCount; }
39
40 protected:
CountsConverter(size_t frameCount,int channelCount)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:
clear()65 void clear() { memset(mData, 0, CountsConverter<T>::getDataSize()); }
getData()66 T* getData() const { return mData; }
getFrameAt(int offsetInFrames)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
AudioBufferBase(T * const data,size_t frameCount,int channelCount)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
getView(int offsetInFrames,size_t lengthInFrames)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.
AudioBuffer()107 constexpr AudioBuffer(): AudioBufferBase<T>(nullptr, 0, 1), mBuffer() {}
AudioBuffer(size_t frameCount,int channelCount)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:
AudioBufferView(T * const data,size_t frameCount,int channelCount)133 AudioBufferView(T* const data, size_t frameCount, int channelCount)
134 : AudioBufferBase<T>(data, frameCount, channelCount) {}
135 // Implicit conversion from AudioBufferBase.
AudioBufferView(const AudioBufferBase<T> & b)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>
convertAudioBufferViewType(AudioBufferView<S> src,AudioBufferView<D> dst)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>
forEachFrame(AudioBufferView<T> src,AudioBufferView<T> dst,std::function<void (T * srcFrame,T * dstFrame)> op)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>
strideCopyAudioBufferViewData(AudioBufferView<T> src,AudioBufferView<T> dst)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>
fillCopyAudioBufferViewData(AudioBufferView<T> src,AudioBufferView<T> dst)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>
copyAudioBufferViewData(AudioBufferView<T> src,AudioBufferView<T> dst)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