Home | History | Annotate | Download | only in lb2
      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