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