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