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