1 /*
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 <errno.h>
21 #include <fcntl.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <time.h>
29 #include <unistd.h>
30
31 #include <iostream>
32 #include <memory>
33 #include <utility>
34 #include <vector>
35
36 #include <gtest/gtest.h>
37 #include <log/log.h>
38 #include <media/AudioBufferProvider.h>
39
40 #include <media/AudioResampler.h>
41 #include "../AudioResamplerDyn.h"
42 #include "../AudioResamplerFirGen.h"
43 #include "test_utils.h"
44
45 template <typename T>
printData(T * data,size_t size)46 static void printData(T *data, size_t size) {
47 const size_t stride = 8;
48 for (size_t i = 0; i < size; ) {
49 for (size_t j = 0; j < stride && i < size; ++j) {
50 std::cout << data[i++] << ' '; // extra space before newline
51 }
52 std::cout << '\n'; // or endl
53 }
54 }
55
resample(int channels,void * output,size_t outputFrames,const std::vector<size_t> & outputIncr,android::AudioBufferProvider * provider,android::AudioResampler * resampler)56 void resample(int channels, void *output,
57 size_t outputFrames, const std::vector<size_t> &outputIncr,
58 android::AudioBufferProvider *provider, android::AudioResampler *resampler)
59 {
60 for (size_t i = 0, j = 0; i < outputFrames; ) {
61 size_t thisFrames = outputIncr[j++];
62 if (j >= outputIncr.size()) {
63 j = 0;
64 }
65 if (thisFrames == 0 || thisFrames > outputFrames - i) {
66 thisFrames = outputFrames - i;
67 }
68 size_t framesResampled = resampler->resample(
69 (int32_t*) output + channels*i, thisFrames, provider);
70 // we should have enough buffer space, so there is no short count.
71 ASSERT_EQ(thisFrames, framesResampled);
72 i += thisFrames;
73 }
74 }
75
buffercmp(const void * reference,const void * test,size_t outputFrameSize,size_t outputFrames)76 void buffercmp(const void *reference, const void *test,
77 size_t outputFrameSize, size_t outputFrames)
78 {
79 for (size_t i = 0; i < outputFrames; ++i) {
80 int check = memcmp((const char*)reference + i * outputFrameSize,
81 (const char*)test + i * outputFrameSize, outputFrameSize);
82 if (check) {
83 ALOGE("Failure at frame %zu", i);
84 ASSERT_EQ(check, 0); /* fails */
85 }
86 }
87 }
88
testBufferIncrement(size_t channels,bool useFloat,unsigned inputFreq,unsigned outputFreq,enum android::AudioResampler::src_quality quality)89 void testBufferIncrement(size_t channels, bool useFloat,
90 unsigned inputFreq, unsigned outputFreq,
91 enum android::AudioResampler::src_quality quality)
92 {
93 const audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
94 // create the provider
95 std::vector<int> inputIncr;
96 SignalProvider provider;
97 if (useFloat) {
98 provider.setChirp<float>(channels,
99 0., outputFreq/2., outputFreq, outputFreq/2000.);
100 } else {
101 provider.setChirp<int16_t>(channels,
102 0., outputFreq/2., outputFreq, outputFreq/2000.);
103 }
104 provider.setIncr(inputIncr);
105
106 // calculate the output size
107 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
108 size_t outputFrameSize = (channels == 1 ? 2 : channels) * (useFloat ? sizeof(float) : sizeof(int32_t));
109 size_t outputSize = outputFrameSize * outputFrames;
110 outputSize &= ~7;
111
112 // create the resampler
113 android::AudioResampler* resampler;
114
115 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
116 resampler->setSampleRate(inputFreq);
117 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
118 android::AudioResampler::UNITY_GAIN_FLOAT);
119
120 // set up the reference run
121 std::vector<size_t> refIncr;
122 refIncr.push_back(outputFrames);
123 void* reference = calloc(outputFrames, outputFrameSize);
124 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
125
126 provider.reset();
127
128 #if 0
129 /* this test will fail - API interface issue: reset() does not clear internal buffers */
130 resampler->reset();
131 #else
132 delete resampler;
133 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
134 resampler->setSampleRate(inputFreq);
135 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
136 android::AudioResampler::UNITY_GAIN_FLOAT);
137 #endif
138
139 // set up the test run
140 std::vector<size_t> outIncr;
141 outIncr.push_back(1);
142 outIncr.push_back(2);
143 outIncr.push_back(3);
144 void* test = calloc(outputFrames, outputFrameSize);
145 inputIncr.push_back(1);
146 inputIncr.push_back(3);
147 provider.setIncr(inputIncr);
148 resample(channels, test, outputFrames, outIncr, &provider, resampler);
149
150 // check
151 buffercmp(reference, test, outputFrameSize, outputFrames);
152
153 free(reference);
154 free(test);
155 delete resampler;
156 }
157
158 template <typename T>
sqr(T v)159 inline double sqr(T v)
160 {
161 double dv = static_cast<double>(v);
162 return dv * dv;
163 }
164
165 template <typename T>
signalEnergy(T * start,T * end,unsigned stride)166 double signalEnergy(T *start, T *end, unsigned stride)
167 {
168 double accum = 0;
169
170 for (T *p = start; p < end; p += stride) {
171 accum += sqr(*p);
172 }
173 unsigned count = (end - start + stride - 1) / stride;
174 return accum / count;
175 }
176
177 // TI = resampler input type, int16_t or float
178 // TO = resampler output type, int32_t or float
179 template <typename TI, typename TO>
testStopbandDownconversion(size_t channels,unsigned inputFreq,unsigned outputFreq,unsigned passband,unsigned stopband,enum android::AudioResampler::src_quality quality)180 void testStopbandDownconversion(size_t channels,
181 unsigned inputFreq, unsigned outputFreq,
182 unsigned passband, unsigned stopband,
183 enum android::AudioResampler::src_quality quality)
184 {
185 // create the provider
186 std::vector<int> inputIncr;
187 SignalProvider provider;
188 provider.setChirp<TI>(channels,
189 0., inputFreq/2., inputFreq, inputFreq/2000.);
190 provider.setIncr(inputIncr);
191
192 // calculate the output size
193 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
194 size_t outputFrameSize = (channels == 1 ? 2 : channels) * sizeof(TO);
195 size_t outputSize = outputFrameSize * outputFrames;
196 outputSize &= ~7;
197
198 // create the resampler
199 android::AudioResampler* resampler;
200
201 resampler = android::AudioResampler::create(
202 is_same<TI, int16_t>::value ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT,
203 channels, outputFreq, quality);
204 resampler->setSampleRate(inputFreq);
205 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
206 android::AudioResampler::UNITY_GAIN_FLOAT);
207
208 // set up the reference run
209 std::vector<size_t> refIncr;
210 refIncr.push_back(outputFrames);
211 void* reference = calloc(outputFrames, outputFrameSize);
212 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
213
214 TO *out = reinterpret_cast<TO *>(reference);
215
216 // check signal energy in passband
217 const unsigned passbandFrame = passband * outputFreq / 1000.;
218 const unsigned stopbandFrame = stopband * outputFreq / 1000.;
219
220 // check each channel separately
221 if (channels == 1) channels = 2; // workaround (mono duplicates output channel)
222
223 for (size_t i = 0; i < channels; ++i) {
224 double passbandEnergy = signalEnergy(out, out + passbandFrame * channels, channels);
225 double stopbandEnergy = signalEnergy(out + stopbandFrame * channels,
226 out + outputFrames * channels, channels);
227 double dbAtten = -10. * log10(stopbandEnergy / passbandEnergy);
228 ASSERT_GT(dbAtten, 60.);
229
230 #if 0
231 // internal verification
232 printf("if:%d of:%d pbf:%d sbf:%d sbe: %f pbe: %f db: %.2f\n",
233 provider.getNumFrames(), outputFrames,
234 passbandFrame, stopbandFrame, stopbandEnergy, passbandEnergy, dbAtten);
235 for (size_t i = 0; i < 10; ++i) {
236 std::cout << out[i+passbandFrame*channels] << std::endl;
237 }
238 for (size_t i = 0; i < 10; ++i) {
239 std::cout << out[i+stopbandFrame*channels] << std::endl;
240 }
241 #endif
242 }
243
244 free(reference);
245 delete resampler;
246 }
247
testFilterResponse(size_t channels,unsigned inputFreq,unsigned outputFreq)248 void testFilterResponse(
249 size_t channels, unsigned inputFreq, unsigned outputFreq)
250 {
251 // create resampler
252 using ResamplerType = android::AudioResamplerDyn<float, float, float>;
253 std::unique_ptr<ResamplerType> rdyn(
254 static_cast<ResamplerType *>(
255 android::AudioResampler::create(
256 AUDIO_FORMAT_PCM_FLOAT,
257 channels,
258 outputFreq,
259 android::AudioResampler::DYN_HIGH_QUALITY)));
260 rdyn->setSampleRate(inputFreq);
261
262 // get design parameters
263 const int phases = rdyn->getPhases();
264 const int halfLength = rdyn->getHalfLength();
265 const float *coefs = rdyn->getFilterCoefs();
266 const double fcr = rdyn->getNormalizedCutoffFrequency();
267 const double tbw = rdyn->getNormalizedTransitionBandwidth();
268 const double attenuation = rdyn->getFilterAttenuation();
269 const double stopbandDb = rdyn->getStopbandAttenuationDb();
270 const double passbandDb = rdyn->getPassbandRippleDb();
271 const double fp = fcr - tbw / 2;
272 const double fs = fcr + tbw / 2;
273
274 printf("inputFreq:%d outputFreq:%d design"
275 " phases:%d halfLength:%d"
276 " fcr:%lf fp:%lf fs:%lf tbw:%lf"
277 " attenuation:%lf stopRipple:%.lf passRipple:%lf"
278 "\n",
279 inputFreq, outputFreq,
280 phases, halfLength,
281 fcr, fp, fs, tbw,
282 attenuation, stopbandDb, passbandDb);
283
284 // verify design parameters
285 constexpr int32_t passSteps = 1000;
286 double passMin, passMax, passRipple, stopMax, stopRipple;
287 android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
288 passSteps, phases * passSteps /* stopSteps */,
289 passMin, passMax, passRipple,
290 stopMax, stopRipple);
291 printf("inputFreq:%d outputFreq:%d verify"
292 " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
293 "\n",
294 inputFreq, outputFreq,
295 passMin, passMax, passRipple, stopMax, stopRipple);
296
297 ASSERT_GT(stopRipple, 60.); // enough stopband attenuation
298 ASSERT_LT(passRipple, 0.2); // small passband ripple
299 ASSERT_GT(passMin, 0.99); // we do not attenuate the signal (ideally 1.)
300 }
301
302 /* Buffer increment test
303 *
304 * We compare a reference output, where we consume and process the entire
305 * buffer at a time, and a test output, where we provide small chunks of input
306 * data and process small chunks of output (which may not be equivalent in size).
307 *
308 * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
309 */
TEST(audioflinger_resampler,bufferincrement_fixedphase)310 TEST(audioflinger_resampler, bufferincrement_fixedphase) {
311 // all of these work
312 static const enum android::AudioResampler::src_quality kQualityArray[] = {
313 android::AudioResampler::LOW_QUALITY,
314 android::AudioResampler::MED_QUALITY,
315 android::AudioResampler::HIGH_QUALITY,
316 android::AudioResampler::VERY_HIGH_QUALITY,
317 android::AudioResampler::DYN_LOW_QUALITY,
318 android::AudioResampler::DYN_MED_QUALITY,
319 android::AudioResampler::DYN_HIGH_QUALITY,
320 };
321
322 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
323 testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
324 }
325 }
326
TEST(audioflinger_resampler,bufferincrement_interpolatedphase)327 TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
328 // all of these work except low quality
329 static const enum android::AudioResampler::src_quality kQualityArray[] = {
330 // android::AudioResampler::LOW_QUALITY,
331 android::AudioResampler::MED_QUALITY,
332 android::AudioResampler::HIGH_QUALITY,
333 android::AudioResampler::VERY_HIGH_QUALITY,
334 android::AudioResampler::DYN_LOW_QUALITY,
335 android::AudioResampler::DYN_MED_QUALITY,
336 android::AudioResampler::DYN_HIGH_QUALITY,
337 };
338
339 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
340 testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
341 }
342 }
343
TEST(audioflinger_resampler,bufferincrement_fixedphase_multi)344 TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
345 // only dynamic quality
346 static const enum android::AudioResampler::src_quality kQualityArray[] = {
347 android::AudioResampler::DYN_LOW_QUALITY,
348 android::AudioResampler::DYN_MED_QUALITY,
349 android::AudioResampler::DYN_HIGH_QUALITY,
350 };
351
352 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
353 testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
354 }
355 }
356
TEST(audioflinger_resampler,bufferincrement_interpolatedphase_multi_float)357 TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
358 // only dynamic quality
359 static const enum android::AudioResampler::src_quality kQualityArray[] = {
360 android::AudioResampler::DYN_LOW_QUALITY,
361 android::AudioResampler::DYN_MED_QUALITY,
362 android::AudioResampler::DYN_HIGH_QUALITY,
363 };
364
365 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
366 testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
367 }
368 }
369
370 /* Simple aliasing test
371 *
372 * This checks stopband response of the chirp signal to make sure frequencies
373 * are properly suppressed. It uses downsampling because the stopband can be
374 * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
375 */
TEST(audioflinger_resampler,stopbandresponse_integer)376 TEST(audioflinger_resampler, stopbandresponse_integer) {
377 // not all of these may work (old resamplers fail on downsampling)
378 static const enum android::AudioResampler::src_quality kQualityArray[] = {
379 //android::AudioResampler::LOW_QUALITY,
380 //android::AudioResampler::MED_QUALITY,
381 //android::AudioResampler::HIGH_QUALITY,
382 //android::AudioResampler::VERY_HIGH_QUALITY,
383 android::AudioResampler::DYN_LOW_QUALITY,
384 android::AudioResampler::DYN_MED_QUALITY,
385 android::AudioResampler::DYN_HIGH_QUALITY,
386 };
387
388 // in this test we assume a maximum transition band between 12kHz and 20kHz.
389 // there must be at least 60dB relative attenuation between stopband and passband.
390 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
391 testStopbandDownconversion<int16_t, int32_t>(
392 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
393 }
394
395 // in this test we assume a maximum transition band between 7kHz and 15kHz.
396 // there must be at least 60dB relative attenuation between stopband and passband.
397 // (the weird ratio triggers interpolative resampling)
398 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
399 testStopbandDownconversion<int16_t, int32_t>(
400 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
401 }
402 }
403
TEST(audioflinger_resampler,stopbandresponse_integer_mono)404 TEST(audioflinger_resampler, stopbandresponse_integer_mono) {
405 // not all of these may work (old resamplers fail on downsampling)
406 static const enum android::AudioResampler::src_quality kQualityArray[] = {
407 //android::AudioResampler::LOW_QUALITY,
408 //android::AudioResampler::MED_QUALITY,
409 //android::AudioResampler::HIGH_QUALITY,
410 //android::AudioResampler::VERY_HIGH_QUALITY,
411 android::AudioResampler::DYN_LOW_QUALITY,
412 android::AudioResampler::DYN_MED_QUALITY,
413 android::AudioResampler::DYN_HIGH_QUALITY,
414 };
415
416 // in this test we assume a maximum transition band between 12kHz and 20kHz.
417 // there must be at least 60dB relative attenuation between stopband and passband.
418 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
419 testStopbandDownconversion<int16_t, int32_t>(
420 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
421 }
422
423 // in this test we assume a maximum transition band between 7kHz and 15kHz.
424 // there must be at least 60dB relative attenuation between stopband and passband.
425 // (the weird ratio triggers interpolative resampling)
426 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
427 testStopbandDownconversion<int16_t, int32_t>(
428 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
429 }
430 }
431
TEST(audioflinger_resampler,stopbandresponse_integer_multichannel)432 TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
433 // not all of these may work (old resamplers fail on downsampling)
434 static const enum android::AudioResampler::src_quality kQualityArray[] = {
435 //android::AudioResampler::LOW_QUALITY,
436 //android::AudioResampler::MED_QUALITY,
437 //android::AudioResampler::HIGH_QUALITY,
438 //android::AudioResampler::VERY_HIGH_QUALITY,
439 android::AudioResampler::DYN_LOW_QUALITY,
440 android::AudioResampler::DYN_MED_QUALITY,
441 android::AudioResampler::DYN_HIGH_QUALITY,
442 };
443
444 // in this test we assume a maximum transition band between 12kHz and 20kHz.
445 // there must be at least 60dB relative attenuation between stopband and passband.
446 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
447 testStopbandDownconversion<int16_t, int32_t>(
448 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
449 }
450
451 // in this test we assume a maximum transition band between 7kHz and 15kHz.
452 // there must be at least 60dB relative attenuation between stopband and passband.
453 // (the weird ratio triggers interpolative resampling)
454 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
455 testStopbandDownconversion<int16_t, int32_t>(
456 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
457 }
458 }
459
TEST(audioflinger_resampler,stopbandresponse_float)460 TEST(audioflinger_resampler, stopbandresponse_float) {
461 // not all of these may work (old resamplers fail on downsampling)
462 static const enum android::AudioResampler::src_quality kQualityArray[] = {
463 //android::AudioResampler::LOW_QUALITY,
464 //android::AudioResampler::MED_QUALITY,
465 //android::AudioResampler::HIGH_QUALITY,
466 //android::AudioResampler::VERY_HIGH_QUALITY,
467 android::AudioResampler::DYN_LOW_QUALITY,
468 android::AudioResampler::DYN_MED_QUALITY,
469 android::AudioResampler::DYN_HIGH_QUALITY,
470 };
471
472 // in this test we assume a maximum transition band between 12kHz and 20kHz.
473 // there must be at least 60dB relative attenuation between stopband and passband.
474 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
475 testStopbandDownconversion<float, float>(
476 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
477 }
478
479 // in this test we assume a maximum transition band between 7kHz and 15kHz.
480 // there must be at least 60dB relative attenuation between stopband and passband.
481 // (the weird ratio triggers interpolative resampling)
482 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
483 testStopbandDownconversion<float, float>(
484 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
485 }
486 }
487
TEST(audioflinger_resampler,stopbandresponse_float_mono)488 TEST(audioflinger_resampler, stopbandresponse_float_mono) {
489 // not all of these may work (old resamplers fail on downsampling)
490 static const enum android::AudioResampler::src_quality kQualityArray[] = {
491 //android::AudioResampler::LOW_QUALITY,
492 //android::AudioResampler::MED_QUALITY,
493 //android::AudioResampler::HIGH_QUALITY,
494 //android::AudioResampler::VERY_HIGH_QUALITY,
495 android::AudioResampler::DYN_LOW_QUALITY,
496 android::AudioResampler::DYN_MED_QUALITY,
497 android::AudioResampler::DYN_HIGH_QUALITY,
498 };
499
500 // in this test we assume a maximum transition band between 12kHz and 20kHz.
501 // there must be at least 60dB relative attenuation between stopband and passband.
502 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
503 testStopbandDownconversion<float, float>(
504 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
505 }
506
507 // in this test we assume a maximum transition band between 7kHz and 15kHz.
508 // there must be at least 60dB relative attenuation between stopband and passband.
509 // (the weird ratio triggers interpolative resampling)
510 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
511 testStopbandDownconversion<float, float>(
512 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
513 }
514 }
515
TEST(audioflinger_resampler,stopbandresponse_float_multichannel)516 TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
517 // not all of these may work (old resamplers fail on downsampling)
518 static const enum android::AudioResampler::src_quality kQualityArray[] = {
519 //android::AudioResampler::LOW_QUALITY,
520 //android::AudioResampler::MED_QUALITY,
521 //android::AudioResampler::HIGH_QUALITY,
522 //android::AudioResampler::VERY_HIGH_QUALITY,
523 android::AudioResampler::DYN_LOW_QUALITY,
524 android::AudioResampler::DYN_MED_QUALITY,
525 android::AudioResampler::DYN_HIGH_QUALITY,
526 };
527
528 // in this test we assume a maximum transition band between 12kHz and 20kHz.
529 // there must be at least 60dB relative attenuation between stopband and passband.
530 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
531 testStopbandDownconversion<float, float>(
532 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
533 }
534
535 // in this test we assume a maximum transition band between 7kHz and 15kHz.
536 // there must be at least 60dB relative attenuation between stopband and passband.
537 // (the weird ratio triggers interpolative resampling)
538 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
539 testStopbandDownconversion<float, float>(
540 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
541 }
542 }
543
TEST(audioflinger_resampler,filterresponse)544 TEST(audioflinger_resampler, filterresponse) {
545 std::vector<int> inSampleRates{
546 8000,
547 11025,
548 12000,
549 16000,
550 22050,
551 24000,
552 32000,
553 44100,
554 48000,
555 88200,
556 96000,
557 176400,
558 192000,
559 };
560 std::vector<int> outSampleRates{
561 48000,
562 96000,
563 };
564
565 for (int outSampleRate : outSampleRates) {
566 for (int inSampleRate : inSampleRates) {
567 testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
568 }
569 }
570 }
571