blob: 9e375db3605932b20bfe2749575568c49ac716e5 [file] [log] [blame]
Andy Hung546734b2014-04-01 18:31:42 -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//#define LOG_NDEBUG 0
18#define LOG_TAG "audioflinger_resampler_tests"
19
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <string.h>
25#include <sys/mman.h>
26#include <sys/stat.h>
27#include <errno.h>
28#include <time.h>
29#include <math.h>
30#include <vector>
31#include <utility>
Andy Hung42b01112014-07-20 14:04:19 -070032#include <iostream>
Andy Hung546734b2014-04-01 18:31:42 -070033#include <cutils/log.h>
34#include <gtest/gtest.h>
35#include <media/AudioBufferProvider.h>
36#include "AudioResampler.h"
Andy Hungc0e5ec82014-06-17 14:33:39 -070037#include "test_utils.h"
Andy Hung546734b2014-04-01 18:31:42 -070038
Andy Hung075abae2014-04-09 19:36:43 -070039void resample(int channels, void *output,
40 size_t outputFrames, const std::vector<size_t> &outputIncr,
Andy Hung546734b2014-04-01 18:31:42 -070041 android::AudioBufferProvider *provider, android::AudioResampler *resampler)
42{
43 for (size_t i = 0, j = 0; i < outputFrames; ) {
44 size_t thisFrames = outputIncr[j++];
45 if (j >= outputIncr.size()) {
46 j = 0;
47 }
48 if (thisFrames == 0 || thisFrames > outputFrames - i) {
49 thisFrames = outputFrames - i;
50 }
Andy Hung6b3b7e32015-03-29 00:49:22 -070051 size_t framesResampled = resampler->resample(
52 (int32_t*) output + channels*i, thisFrames, provider);
53 // we should have enough buffer space, so there is no short count.
54 ASSERT_EQ(thisFrames, framesResampled);
Andy Hung546734b2014-04-01 18:31:42 -070055 i += thisFrames;
56 }
57}
58
59void buffercmp(const void *reference, const void *test,
60 size_t outputFrameSize, size_t outputFrames)
61{
62 for (size_t i = 0; i < outputFrames; ++i) {
63 int check = memcmp((const char*)reference + i * outputFrameSize,
64 (const char*)test + i * outputFrameSize, outputFrameSize);
65 if (check) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -070066 ALOGE("Failure at frame %zu", i);
Andy Hung546734b2014-04-01 18:31:42 -070067 ASSERT_EQ(check, 0); /* fails */
68 }
69 }
70}
71
Andy Hung075abae2014-04-09 19:36:43 -070072void testBufferIncrement(size_t channels, bool useFloat,
73 unsigned inputFreq, unsigned outputFreq,
Andy Hung546734b2014-04-01 18:31:42 -070074 enum android::AudioResampler::src_quality quality)
75{
Andy Hung3348e362014-07-07 10:21:44 -070076 const audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
Andy Hung546734b2014-04-01 18:31:42 -070077 // create the provider
Andy Hungc0e5ec82014-06-17 14:33:39 -070078 std::vector<int> inputIncr;
79 SignalProvider provider;
Andy Hung075abae2014-04-09 19:36:43 -070080 if (useFloat) {
81 provider.setChirp<float>(channels,
82 0., outputFreq/2., outputFreq, outputFreq/2000.);
83 } else {
84 provider.setChirp<int16_t>(channels,
85 0., outputFreq/2., outputFreq, outputFreq/2000.);
86 }
Andy Hungc0e5ec82014-06-17 14:33:39 -070087 provider.setIncr(inputIncr);
Andy Hung546734b2014-04-01 18:31:42 -070088
89 // calculate the output size
90 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
Andy Hung075abae2014-04-09 19:36:43 -070091 size_t outputFrameSize = channels * (useFloat ? sizeof(float) : sizeof(int32_t));
Andy Hung546734b2014-04-01 18:31:42 -070092 size_t outputSize = outputFrameSize * outputFrames;
93 outputSize &= ~7;
94
95 // create the resampler
Andy Hung546734b2014-04-01 18:31:42 -070096 android::AudioResampler* resampler;
97
Andy Hung3348e362014-07-07 10:21:44 -070098 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -070099 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700100 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
101 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700102
103 // set up the reference run
104 std::vector<size_t> refIncr;
105 refIncr.push_back(outputFrames);
106 void* reference = malloc(outputSize);
Andy Hung075abae2014-04-09 19:36:43 -0700107 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700108
109 provider.reset();
110
111#if 0
112 /* this test will fail - API interface issue: reset() does not clear internal buffers */
113 resampler->reset();
114#else
115 delete resampler;
Andy Hung3348e362014-07-07 10:21:44 -0700116 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -0700117 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700118 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
119 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700120#endif
121
122 // set up the test run
123 std::vector<size_t> outIncr;
124 outIncr.push_back(1);
125 outIncr.push_back(2);
126 outIncr.push_back(3);
127 void* test = malloc(outputSize);
Andy Hung075abae2014-04-09 19:36:43 -0700128 inputIncr.push_back(1);
129 inputIncr.push_back(3);
130 provider.setIncr(inputIncr);
131 resample(channels, test, outputFrames, outIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700132
133 // check
134 buffercmp(reference, test, outputFrameSize, outputFrames);
135
136 free(reference);
137 free(test);
138 delete resampler;
139}
140
141template <typename T>
142inline double sqr(T v)
143{
144 double dv = static_cast<double>(v);
145 return dv * dv;
146}
147
148template <typename T>
149double signalEnergy(T *start, T *end, unsigned stride)
150{
151 double accum = 0;
152
153 for (T *p = start; p < end; p += stride) {
154 accum += sqr(*p);
155 }
156 unsigned count = (end - start + stride - 1) / stride;
157 return accum / count;
158}
159
Andy Hung42b01112014-07-20 14:04:19 -0700160// TI = resampler input type, int16_t or float
161// TO = resampler output type, int32_t or float
162template <typename TI, typename TO>
Andy Hung546734b2014-04-01 18:31:42 -0700163void testStopbandDownconversion(size_t channels,
164 unsigned inputFreq, unsigned outputFreq,
165 unsigned passband, unsigned stopband,
166 enum android::AudioResampler::src_quality quality)
167{
168 // create the provider
Andy Hungc0e5ec82014-06-17 14:33:39 -0700169 std::vector<int> inputIncr;
170 SignalProvider provider;
Andy Hung42b01112014-07-20 14:04:19 -0700171 provider.setChirp<TI>(channels,
Andy Hungc0e5ec82014-06-17 14:33:39 -0700172 0., inputFreq/2., inputFreq, inputFreq/2000.);
173 provider.setIncr(inputIncr);
Andy Hung546734b2014-04-01 18:31:42 -0700174
175 // calculate the output size
176 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
Andy Hung42b01112014-07-20 14:04:19 -0700177 size_t outputFrameSize = channels * sizeof(TO);
Andy Hung546734b2014-04-01 18:31:42 -0700178 size_t outputSize = outputFrameSize * outputFrames;
179 outputSize &= ~7;
180
181 // create the resampler
Andy Hung546734b2014-04-01 18:31:42 -0700182 android::AudioResampler* resampler;
183
Andy Hung42b01112014-07-20 14:04:19 -0700184 resampler = android::AudioResampler::create(
185 is_same<TI, int16_t>::value ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT,
Andy Hung3348e362014-07-07 10:21:44 -0700186 channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -0700187 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700188 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
189 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700190
191 // set up the reference run
192 std::vector<size_t> refIncr;
193 refIncr.push_back(outputFrames);
194 void* reference = malloc(outputSize);
Andy Hung075abae2014-04-09 19:36:43 -0700195 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700196
Andy Hung42b01112014-07-20 14:04:19 -0700197 TO *out = reinterpret_cast<TO *>(reference);
Andy Hung546734b2014-04-01 18:31:42 -0700198
199 // check signal energy in passband
200 const unsigned passbandFrame = passband * outputFreq / 1000.;
201 const unsigned stopbandFrame = stopband * outputFreq / 1000.;
202
203 // check each channel separately
204 for (size_t i = 0; i < channels; ++i) {
205 double passbandEnergy = signalEnergy(out, out + passbandFrame * channels, channels);
206 double stopbandEnergy = signalEnergy(out + stopbandFrame * channels,
207 out + outputFrames * channels, channels);
208 double dbAtten = -10. * log10(stopbandEnergy / passbandEnergy);
209 ASSERT_GT(dbAtten, 60.);
210
211#if 0
212 // internal verification
213 printf("if:%d of:%d pbf:%d sbf:%d sbe: %f pbe: %f db: %.2f\n",
214 provider.getNumFrames(), outputFrames,
215 passbandFrame, stopbandFrame, stopbandEnergy, passbandEnergy, dbAtten);
216 for (size_t i = 0; i < 10; ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700217 std::cout << out[i+passbandFrame*channels] << std::endl;
Andy Hung546734b2014-04-01 18:31:42 -0700218 }
219 for (size_t i = 0; i < 10; ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700220 std::cout << out[i+stopbandFrame*channels] << std::endl;
Andy Hung546734b2014-04-01 18:31:42 -0700221 }
222#endif
223 }
224
225 free(reference);
226 delete resampler;
227}
228
229/* Buffer increment test
230 *
231 * We compare a reference output, where we consume and process the entire
232 * buffer at a time, and a test output, where we provide small chunks of input
233 * data and process small chunks of output (which may not be equivalent in size).
234 *
235 * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
236 */
237TEST(audioflinger_resampler, bufferincrement_fixedphase) {
238 // all of these work
239 static const enum android::AudioResampler::src_quality kQualityArray[] = {
240 android::AudioResampler::LOW_QUALITY,
241 android::AudioResampler::MED_QUALITY,
242 android::AudioResampler::HIGH_QUALITY,
243 android::AudioResampler::VERY_HIGH_QUALITY,
244 android::AudioResampler::DYN_LOW_QUALITY,
245 android::AudioResampler::DYN_MED_QUALITY,
246 android::AudioResampler::DYN_HIGH_QUALITY,
247 };
248
249 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung075abae2014-04-09 19:36:43 -0700250 testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700251 }
252}
253
254TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
255 // all of these work except low quality
256 static const enum android::AudioResampler::src_quality kQualityArray[] = {
257// android::AudioResampler::LOW_QUALITY,
258 android::AudioResampler::MED_QUALITY,
259 android::AudioResampler::HIGH_QUALITY,
260 android::AudioResampler::VERY_HIGH_QUALITY,
261 android::AudioResampler::DYN_LOW_QUALITY,
262 android::AudioResampler::DYN_MED_QUALITY,
263 android::AudioResampler::DYN_HIGH_QUALITY,
264 };
265
266 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung075abae2014-04-09 19:36:43 -0700267 testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
268 }
269}
270
271TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
272 // only dynamic quality
273 static const enum android::AudioResampler::src_quality kQualityArray[] = {
274 android::AudioResampler::DYN_LOW_QUALITY,
275 android::AudioResampler::DYN_MED_QUALITY,
276 android::AudioResampler::DYN_HIGH_QUALITY,
277 };
278
279 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
280 testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
281 }
282}
283
284TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
285 // only dynamic quality
286 static const enum android::AudioResampler::src_quality kQualityArray[] = {
287 android::AudioResampler::DYN_LOW_QUALITY,
288 android::AudioResampler::DYN_MED_QUALITY,
289 android::AudioResampler::DYN_HIGH_QUALITY,
290 };
291
292 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
293 testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700294 }
295}
296
297/* Simple aliasing test
298 *
299 * This checks stopband response of the chirp signal to make sure frequencies
300 * are properly suppressed. It uses downsampling because the stopband can be
301 * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
302 */
Andy Hung42b01112014-07-20 14:04:19 -0700303TEST(audioflinger_resampler, stopbandresponse_integer) {
Andy Hung546734b2014-04-01 18:31:42 -0700304 // not all of these may work (old resamplers fail on downsampling)
305 static const enum android::AudioResampler::src_quality kQualityArray[] = {
306 //android::AudioResampler::LOW_QUALITY,
307 //android::AudioResampler::MED_QUALITY,
308 //android::AudioResampler::HIGH_QUALITY,
309 //android::AudioResampler::VERY_HIGH_QUALITY,
310 android::AudioResampler::DYN_LOW_QUALITY,
311 android::AudioResampler::DYN_MED_QUALITY,
312 android::AudioResampler::DYN_HIGH_QUALITY,
313 };
314
315 // in this test we assume a maximum transition band between 12kHz and 20kHz.
316 // there must be at least 60dB relative attenuation between stopband and passband.
317 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700318 testStopbandDownconversion<int16_t, int32_t>(
319 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700320 }
321
322 // in this test we assume a maximum transition band between 7kHz and 15kHz.
323 // there must be at least 60dB relative attenuation between stopband and passband.
324 // (the weird ratio triggers interpolative resampling)
325 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700326 testStopbandDownconversion<int16_t, int32_t>(
327 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700328 }
329}
Andy Hung42b01112014-07-20 14:04:19 -0700330
331TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
332 // not all of these may work (old resamplers fail on downsampling)
333 static const enum android::AudioResampler::src_quality kQualityArray[] = {
334 //android::AudioResampler::LOW_QUALITY,
335 //android::AudioResampler::MED_QUALITY,
336 //android::AudioResampler::HIGH_QUALITY,
337 //android::AudioResampler::VERY_HIGH_QUALITY,
338 android::AudioResampler::DYN_LOW_QUALITY,
339 android::AudioResampler::DYN_MED_QUALITY,
340 android::AudioResampler::DYN_HIGH_QUALITY,
341 };
342
343 // in this test we assume a maximum transition band between 12kHz and 20kHz.
344 // there must be at least 60dB relative attenuation between stopband and passband.
345 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
346 testStopbandDownconversion<int16_t, int32_t>(
347 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
348 }
349
350 // in this test we assume a maximum transition band between 7kHz and 15kHz.
351 // there must be at least 60dB relative attenuation between stopband and passband.
352 // (the weird ratio triggers interpolative resampling)
353 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
354 testStopbandDownconversion<int16_t, int32_t>(
355 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
356 }
357}
358
359TEST(audioflinger_resampler, stopbandresponse_float) {
360 // not all of these may work (old resamplers fail on downsampling)
361 static const enum android::AudioResampler::src_quality kQualityArray[] = {
362 //android::AudioResampler::LOW_QUALITY,
363 //android::AudioResampler::MED_QUALITY,
364 //android::AudioResampler::HIGH_QUALITY,
365 //android::AudioResampler::VERY_HIGH_QUALITY,
366 android::AudioResampler::DYN_LOW_QUALITY,
367 android::AudioResampler::DYN_MED_QUALITY,
368 android::AudioResampler::DYN_HIGH_QUALITY,
369 };
370
371 // in this test we assume a maximum transition band between 12kHz and 20kHz.
372 // there must be at least 60dB relative attenuation between stopband and passband.
373 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
374 testStopbandDownconversion<float, float>(
375 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
376 }
377
378 // in this test we assume a maximum transition band between 7kHz and 15kHz.
379 // there must be at least 60dB relative attenuation between stopband and passband.
380 // (the weird ratio triggers interpolative resampling)
381 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
382 testStopbandDownconversion<float, float>(
383 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
384 }
385}
386
387TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
388 // not all of these may work (old resamplers fail on downsampling)
389 static const enum android::AudioResampler::src_quality kQualityArray[] = {
390 //android::AudioResampler::LOW_QUALITY,
391 //android::AudioResampler::MED_QUALITY,
392 //android::AudioResampler::HIGH_QUALITY,
393 //android::AudioResampler::VERY_HIGH_QUALITY,
394 android::AudioResampler::DYN_LOW_QUALITY,
395 android::AudioResampler::DYN_MED_QUALITY,
396 android::AudioResampler::DYN_HIGH_QUALITY,
397 };
398
399 // in this test we assume a maximum transition band between 12kHz and 20kHz.
400 // there must be at least 60dB relative attenuation between stopband and passband.
401 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
402 testStopbandDownconversion<float, float>(
403 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
404 }
405
406 // in this test we assume a maximum transition band between 7kHz and 15kHz.
407 // there must be at least 60dB relative attenuation between stopband and passband.
408 // (the weird ratio triggers interpolative resampling)
409 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
410 testStopbandDownconversion<float, float>(
411 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
412 }
413}
414