blob: 283c768bba19d836850294a857219b3485c20090 [file] [log] [blame]
Andy Hungc0e5ec82014-06-17 14:33:39 -07001/*
2 * Copyright (C) 2014 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 ANDROID_AUDIO_TEST_UTILS_H
18#define ANDROID_AUDIO_TEST_UTILS_H
19
20#include <audio_utils/sndfile.h>
21
22#ifndef ARRAY_SIZE
23#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
24#endif
25
26template<typename T, typename U>
27struct is_same
28{
29 static const bool value = false;
30};
31
32template<typename T>
33struct is_same<T, T> // partial specialization
34{
35 static const bool value = true;
36};
37
38template<typename T>
39static inline T convertValue(double val)
40{
41 if (is_same<T, int16_t>::value) {
42 return floor(val * 32767.0 + 0.5);
43 } else if (is_same<T, int32_t>::value) {
44 return floor(val * (1UL<<31) + 0.5);
45 }
46 return val; // assume float or double
47}
48
49// Convert a list of integers in CSV format to a Vector of those values.
50// Returns the number of elements in the list, or -1 on error.
51static inline int parseCSV(const char *string, std::vector<int>& values)
52{
53 // pass 1: count the number of values and do syntax check
54 size_t numValues = 0;
55 bool hadDigit = false;
56 for (const char *p = string; ; ) {
57 switch (*p++) {
58 case '0': case '1': case '2': case '3': case '4':
59 case '5': case '6': case '7': case '8': case '9':
60 hadDigit = true;
61 break;
62 case '\0':
63 if (hadDigit) {
64 // pass 2: allocate and initialize vector of values
65 values.resize(++numValues);
66 values[0] = atoi(p = string);
67 for (size_t i = 1; i < numValues; ) {
68 if (*p++ == ',') {
69 values[i++] = atoi(p);
70 }
71 }
72 return numValues;
73 }
74 // fall through
75 case ',':
76 if (hadDigit) {
77 hadDigit = false;
78 numValues++;
79 break;
80 }
81 // fall through
82 default:
83 return -1;
84 }
85 }
86}
87
88/* Creates a type-independent audio buffer provider from
89 * a buffer base address, size, framesize, and input increment array.
90 *
91 * No allocation or deallocation of the provided buffer is done.
92 */
93class TestProvider : public android::AudioBufferProvider {
94public:
95 TestProvider(void* addr, size_t frames, size_t frameSize,
96 const std::vector<int>& inputIncr)
97 : mAddr(addr),
98 mNumFrames(frames),
99 mFrameSize(frameSize),
100 mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0)
101 {
102 }
103
104 TestProvider()
105 : mAddr(NULL), mNumFrames(0), mFrameSize(0),
106 mNextFrame(0), mUnrel(0), mNextIdx(0)
107 {
108 }
109
110 void setIncr(const std::vector<int>& inputIncr) {
111 mInputIncr = inputIncr;
112 mNextIdx = 0;
113 }
114
Glenn Kastend79072e2016-01-06 08:41:20 -0800115 virtual android::status_t getNextBuffer(Buffer* buffer)
Andy Hungc0e5ec82014-06-17 14:33:39 -0700116 {
117 size_t requestedFrames = buffer->frameCount;
118 if (requestedFrames > mNumFrames - mNextFrame) {
119 buffer->frameCount = mNumFrames - mNextFrame;
120 }
121 if (!mInputIncr.empty()) {
122 size_t provided = mInputIncr[mNextIdx++];
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700123 ALOGV("getNextBuffer() mValue[%zu]=%zu not %zu",
Andy Hungc0e5ec82014-06-17 14:33:39 -0700124 mNextIdx-1, provided, buffer->frameCount);
125 if (provided < buffer->frameCount) {
126 buffer->frameCount = provided;
127 }
128 if (mNextIdx >= mInputIncr.size()) {
129 mNextIdx = 0;
130 }
131 }
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700132 ALOGV("getNextBuffer() requested %zu frames out of %zu frames available"
133 " and returned %zu frames",
Andy Hungc0e5ec82014-06-17 14:33:39 -0700134 requestedFrames, mNumFrames - mNextFrame, buffer->frameCount);
135 mUnrel = buffer->frameCount;
136 if (buffer->frameCount > 0) {
137 buffer->raw = (char *)mAddr + mFrameSize * mNextFrame;
138 return android::NO_ERROR;
139 } else {
140 buffer->raw = NULL;
141 return android::NOT_ENOUGH_DATA;
142 }
143 }
144
145 virtual void releaseBuffer(Buffer* buffer)
146 {
147 if (buffer->frameCount > mUnrel) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700148 ALOGE("releaseBuffer() released %zu frames but only %zu available "
149 "to release", buffer->frameCount, mUnrel);
Andy Hungc0e5ec82014-06-17 14:33:39 -0700150 mNextFrame += mUnrel;
151 mUnrel = 0;
152 } else {
153
Glenn Kastena4daf0b2014-07-28 16:34:45 -0700154 ALOGV("releaseBuffer() released %zu frames out of %zu frames available "
155 "to release", buffer->frameCount, mUnrel);
Andy Hungc0e5ec82014-06-17 14:33:39 -0700156 mNextFrame += buffer->frameCount;
157 mUnrel -= buffer->frameCount;
158 }
159 buffer->frameCount = 0;
160 buffer->raw = NULL;
161 }
162
163 void reset()
164 {
165 mNextFrame = 0;
166 }
167
168 size_t getNumFrames()
169 {
170 return mNumFrames;
171 }
172
173
174protected:
175 void* mAddr; // base address
176 size_t mNumFrames; // total frames
177 int mFrameSize; // frame size (# channels * bytes per sample)
178 size_t mNextFrame; // index of next frame to provide
179 size_t mUnrel; // number of frames not yet released
180 std::vector<int> mInputIncr; // number of frames provided per call
181 size_t mNextIdx; // index of next entry in mInputIncr to use
182};
183
184/* Creates a buffer filled with a sine wave.
185 */
186template<typename T>
187static void createSine(void *vbuffer, size_t frames,
188 size_t channels, double sampleRate, double freq)
189{
190 double tscale = 1. / sampleRate;
191 T* buffer = reinterpret_cast<T*>(vbuffer);
192 for (size_t i = 0; i < frames; ++i) {
193 double t = i * tscale;
194 double y = sin(2. * M_PI * freq * t);
195 T yt = convertValue<T>(y);
196
197 for (size_t j = 0; j < channels; ++j) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700198 buffer[i*channels + j] = yt / T(j + 1);
Andy Hungc0e5ec82014-06-17 14:33:39 -0700199 }
200 }
201}
202
203/* Creates a buffer filled with a chirp signal (a sine wave sweep).
204 *
205 * When creating the Chirp, note that the frequency is the true sinusoidal
206 * frequency not the sampling rate.
207 *
208 * http://en.wikipedia.org/wiki/Chirp
209 */
210template<typename T>
211static void createChirp(void *vbuffer, size_t frames,
212 size_t channels, double sampleRate, double minfreq, double maxfreq)
213{
214 double tscale = 1. / sampleRate;
215 T *buffer = reinterpret_cast<T*>(vbuffer);
216 // note the chirp constant k has a divide-by-two.
217 double k = (maxfreq - minfreq) / (2. * tscale * frames);
218 for (size_t i = 0; i < frames; ++i) {
219 double t = i * tscale;
220 double y = sin(2. * M_PI * (k * t + minfreq) * t);
221 T yt = convertValue<T>(y);
222
223 for (size_t j = 0; j < channels; ++j) {
Andy Hunge93b6b72014-07-17 21:30:53 -0700224 buffer[i*channels + j] = yt / T(j + 1);
Andy Hungc0e5ec82014-06-17 14:33:39 -0700225 }
226 }
227}
228
229/* This derived class creates a buffer provider of datatype T,
230 * consisting of an input signal, e.g. from createChirp().
231 * The number of frames can be obtained from the base class
232 * TestProvider::getNumFrames().
233 */
234
235class SignalProvider : public TestProvider {
236public:
237 SignalProvider()
238 : mSampleRate(0),
239 mChannels(0)
240 {
241 }
242
243 virtual ~SignalProvider()
244 {
245 free(mAddr);
246 mAddr = NULL;
247 }
248
249 template <typename T>
250 void setChirp(size_t channels, double minfreq, double maxfreq, double sampleRate, double time)
251 {
252 createBufferByFrames<T>(channels, sampleRate, sampleRate*time);
253 createChirp<T>(mAddr, mNumFrames, mChannels, mSampleRate, minfreq, maxfreq);
254 }
255
256 template <typename T>
257 void setSine(size_t channels,
258 double freq, double sampleRate, double time)
259 {
260 createBufferByFrames<T>(channels, sampleRate, sampleRate*time);
261 createSine<T>(mAddr, mNumFrames, mChannels, mSampleRate, freq);
262 }
263
264 template <typename T>
265 void setFile(const char *file_in)
266 {
267 SF_INFO info;
268 info.format = 0;
269 SNDFILE *sf = sf_open(file_in, SFM_READ, &info);
270 if (sf == NULL) {
271 perror(file_in);
272 return;
273 }
274 createBufferByFrames<T>(info.channels, info.samplerate, info.frames);
275 if (is_same<T, float>::value) {
276 (void) sf_readf_float(sf, (float *) mAddr, mNumFrames);
277 } else if (is_same<T, short>::value) {
278 (void) sf_readf_short(sf, (short *) mAddr, mNumFrames);
279 }
280 sf_close(sf);
281 }
282
283 template <typename T>
284 void createBufferByFrames(size_t channels, uint32_t sampleRate, size_t frames)
285 {
286 mNumFrames = frames;
287 mChannels = channels;
288 mFrameSize = mChannels * sizeof(T);
289 free(mAddr);
290 mAddr = malloc(mFrameSize * mNumFrames);
291 mSampleRate = sampleRate;
292 }
293
294 uint32_t getSampleRate() const {
295 return mSampleRate;
296 }
297
298 uint32_t getNumChannels() const {
299 return mChannels;
300 }
301
302protected:
303 uint32_t mSampleRate;
304 uint32_t mChannels;
305};
306
307#endif // ANDROID_AUDIO_TEST_UTILS_H