• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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