1 /* 2 * Copyright 2015 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 NATIVEOBOE_MULTICHANNEL_RECORDING_H 18 #define NATIVEOBOE_MULTICHANNEL_RECORDING_H 19 20 #include <memory.h> 21 #include <unistd.h> 22 #include <sys/types.h> 23 24 /** 25 * Store multi-channel audio data in float format. 26 * The most recent data will be saved. 27 * Old data may be overwritten. 28 * 29 * Note that this is not thread safe. Do not read and write from separate threads. 30 */ 31 class MultiChannelRecording { 32 public: MultiChannelRecording(int32_t channelCount,int32_t maxFrames)33 MultiChannelRecording(int32_t channelCount, int32_t maxFrames) 34 : mChannelCount(channelCount) 35 , mMaxFrames(maxFrames) { 36 mData = new float[channelCount * maxFrames]; 37 } 38 ~MultiChannelRecording()39 ~MultiChannelRecording() { 40 delete[] mData; 41 } 42 rewind()43 void rewind() { 44 mReadCursorFrames = mWriteCursorFrames - getSizeInFrames(); 45 } 46 clear()47 void clear() { 48 mReadCursorFrames = 0; 49 mWriteCursorFrames = 0; 50 } 51 getChannelCount()52 int32_t getChannelCount() { 53 return mChannelCount; 54 } 55 getSizeInFrames()56 int32_t getSizeInFrames() { 57 return (int32_t) std::min(mWriteCursorFrames, static_cast<int64_t>(mMaxFrames)); 58 } 59 getReadIndex()60 int32_t getReadIndex() { 61 return mReadCursorFrames % mMaxFrames; 62 } getWriteIndex()63 int32_t getWriteIndex() { 64 return mWriteCursorFrames % mMaxFrames; 65 } 66 67 /** 68 * Write numFrames from the short buffer into the recording. 69 * Overwrite old data if necessary. 70 * Convert shorts to floats. 71 * 72 * @param buffer 73 * @param numFrames 74 * @return number of frames actually written. 75 */ write(int16_t * buffer,int32_t numFrames)76 int32_t write(int16_t *buffer, int32_t numFrames) { 77 int32_t framesLeft = numFrames; 78 while (framesLeft > 0) { 79 int32_t indexFrame = getWriteIndex(); 80 // contiguous writes 81 int32_t framesToEndOfBuffer = mMaxFrames - indexFrame; 82 int32_t framesNow = std::min(framesLeft, framesToEndOfBuffer); 83 int32_t numSamples = framesNow * mChannelCount; 84 int32_t sampleIndex = indexFrame * mChannelCount; 85 86 for (int i = 0; i < numSamples; i++) { 87 mData[sampleIndex++] = *buffer++ * (1.0f / 32768); 88 } 89 90 mWriteCursorFrames += framesNow; 91 framesLeft -= framesNow; 92 } 93 return numFrames - framesLeft; 94 } 95 96 /** 97 * Write all numFrames from the float buffer into the recording. 98 * Overwrite old data if full. 99 * @param buffer 100 * @param numFrames 101 * @return number of frames actually written. 102 */ write(float * buffer,int32_t numFrames)103 int32_t write(float *buffer, int32_t numFrames) { 104 int32_t framesLeft = numFrames; 105 while (framesLeft > 0) { 106 int32_t indexFrame = getWriteIndex(); 107 // contiguous writes 108 int32_t framesToEnd = mMaxFrames - indexFrame; 109 int32_t framesNow = std::min(framesLeft, framesToEnd); 110 int32_t numSamples = framesNow * mChannelCount; 111 int32_t sampleIndex = indexFrame * mChannelCount; 112 113 memcpy(&mData[sampleIndex], 114 buffer, 115 (numSamples * sizeof(float))); 116 buffer += numSamples; 117 mWriteCursorFrames += framesNow; 118 framesLeft -= framesNow; 119 } 120 return numFrames; 121 } 122 123 /** 124 * Read numFrames from the recording into the buffer, if there is enough data. 125 * Start at the cursor position, aligned up to the next frame. 126 * @param buffer 127 * @param numFrames 128 * @return number of frames actually read. 129 */ read(float * buffer,int32_t numFrames)130 int32_t read(float *buffer, int32_t numFrames) { 131 int32_t framesRead = 0; 132 int32_t framesLeft = std::min(numFrames, 133 std::min(mMaxFrames, (int32_t)(mWriteCursorFrames - mReadCursorFrames))); 134 while (framesLeft > 0) { 135 int32_t indexFrame = getReadIndex(); 136 // contiguous reads 137 int32_t framesToEnd = mMaxFrames - indexFrame; 138 int32_t framesNow = std::min(framesLeft, framesToEnd); 139 int32_t numSamples = framesNow * mChannelCount; 140 int32_t sampleIndex = indexFrame * mChannelCount; 141 142 memcpy(buffer, 143 &mData[sampleIndex], 144 (numSamples * sizeof(float))); 145 146 mReadCursorFrames += framesNow; 147 framesLeft -= framesNow; 148 framesRead += framesNow; 149 } 150 return framesRead; 151 } 152 153 private: 154 float *mData = nullptr; 155 int64_t mReadCursorFrames = 0; 156 int64_t mWriteCursorFrames = 0; // monotonically increasing 157 const int32_t mChannelCount; 158 const int32_t mMaxFrames; 159 }; 160 161 #endif //NATIVEOBOE_MULTICHANNEL_RECORDING_H 162