blob: 829229128f00aa05ef14d6376466b78113e42acd [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
Mark Salyzyn60d02072016-09-29 08:48:48 -070020#include <errno.h>
21#include <fcntl.h>
22#include <math.h>
Andy Hung546734b2014-04-01 18:31:42 -070023#include <stdio.h>
24#include <stdlib.h>
Andy Hung546734b2014-04-01 18:31:42 -070025#include <string.h>
26#include <sys/mman.h>
27#include <sys/stat.h>
Andy Hung546734b2014-04-01 18:31:42 -070028#include <time.h>
Mark Salyzyn60d02072016-09-29 08:48:48 -070029#include <unistd.h>
30
Andy Hung42b01112014-07-20 14:04:19 -070031#include <iostream>
Andy Hung6bd378f2017-10-24 19:23:52 -070032#include <memory>
Mark Salyzyn60d02072016-09-29 08:48:48 -070033#include <utility>
34#include <vector>
35
Andy Hung546734b2014-04-01 18:31:42 -070036#include <gtest/gtest.h>
Mark Salyzyne74bbf12017-01-12 15:10:27 -080037#include <log/log.h>
Andy Hung546734b2014-04-01 18:31:42 -070038#include <media/AudioBufferProvider.h>
Mark Salyzyn60d02072016-09-29 08:48:48 -070039
Andy Hung068561c2017-01-03 17:09:32 -080040#include <media/AudioResampler.h>
Andy Hung6bd378f2017-10-24 19:23:52 -070041#include "../AudioResamplerDyn.h"
42#include "../AudioResamplerFirGen.h"
Andy Hungc0e5ec82014-06-17 14:33:39 -070043#include "test_utils.h"
Andy Hung546734b2014-04-01 18:31:42 -070044
Andy Hungadc5d9c2017-01-05 17:26:08 -080045template <typename T>
46static 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
Andy Hung075abae2014-04-09 19:36:43 -070056void resample(int channels, void *output,
57 size_t outputFrames, const std::vector<size_t> &outputIncr,
Andy Hung546734b2014-04-01 18:31:42 -070058 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 }
Andy Hung6b3b7e32015-03-29 00:49:22 -070068 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);
Andy Hung546734b2014-04-01 18:31:42 -070072 i += thisFrames;
73 }
74}
75
76void 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) {
Glenn Kastena4daf0b2014-07-28 16:34:45 -070083 ALOGE("Failure at frame %zu", i);
Andy Hung546734b2014-04-01 18:31:42 -070084 ASSERT_EQ(check, 0); /* fails */
85 }
86 }
87}
88
Andy Hung075abae2014-04-09 19:36:43 -070089void testBufferIncrement(size_t channels, bool useFloat,
90 unsigned inputFreq, unsigned outputFreq,
Andy Hung546734b2014-04-01 18:31:42 -070091 enum android::AudioResampler::src_quality quality)
92{
Andy Hung3348e362014-07-07 10:21:44 -070093 const audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
Andy Hung546734b2014-04-01 18:31:42 -070094 // create the provider
Andy Hungc0e5ec82014-06-17 14:33:39 -070095 std::vector<int> inputIncr;
96 SignalProvider provider;
Andy Hung075abae2014-04-09 19:36:43 -070097 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 }
Andy Hungc0e5ec82014-06-17 14:33:39 -0700104 provider.setIncr(inputIncr);
Andy Hung546734b2014-04-01 18:31:42 -0700105
106 // calculate the output size
107 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
Andy Hungadc5d9c2017-01-05 17:26:08 -0800108 size_t outputFrameSize = (channels == 1 ? 2 : channels) * (useFloat ? sizeof(float) : sizeof(int32_t));
Andy Hung546734b2014-04-01 18:31:42 -0700109 size_t outputSize = outputFrameSize * outputFrames;
110 outputSize &= ~7;
111
112 // create the resampler
Andy Hung546734b2014-04-01 18:31:42 -0700113 android::AudioResampler* resampler;
114
Andy Hung3348e362014-07-07 10:21:44 -0700115 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -0700116 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700117 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
118 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700119
120 // set up the reference run
121 std::vector<size_t> refIncr;
122 refIncr.push_back(outputFrames);
Andy Hungccbba6e2017-01-05 16:43:35 -0800123 void* reference = calloc(outputFrames, outputFrameSize);
Andy Hung075abae2014-04-09 19:36:43 -0700124 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700125
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;
Andy Hung3348e362014-07-07 10:21:44 -0700133 resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -0700134 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700135 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
136 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700137#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);
Andy Hungccbba6e2017-01-05 16:43:35 -0800144 void* test = calloc(outputFrames, outputFrameSize);
Andy Hung075abae2014-04-09 19:36:43 -0700145 inputIncr.push_back(1);
146 inputIncr.push_back(3);
147 provider.setIncr(inputIncr);
148 resample(channels, test, outputFrames, outIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700149
150 // check
151 buffercmp(reference, test, outputFrameSize, outputFrames);
152
153 free(reference);
154 free(test);
155 delete resampler;
156}
157
158template <typename T>
159inline double sqr(T v)
160{
161 double dv = static_cast<double>(v);
162 return dv * dv;
163}
164
165template <typename T>
166double 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
Andy Hung42b01112014-07-20 14:04:19 -0700177// TI = resampler input type, int16_t or float
178// TO = resampler output type, int32_t or float
179template <typename TI, typename TO>
Andy Hung546734b2014-04-01 18:31:42 -0700180void 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
Andy Hungc0e5ec82014-06-17 14:33:39 -0700186 std::vector<int> inputIncr;
187 SignalProvider provider;
Andy Hung42b01112014-07-20 14:04:19 -0700188 provider.setChirp<TI>(channels,
Andy Hungc0e5ec82014-06-17 14:33:39 -0700189 0., inputFreq/2., inputFreq, inputFreq/2000.);
190 provider.setIncr(inputIncr);
Andy Hung546734b2014-04-01 18:31:42 -0700191
192 // calculate the output size
193 size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
Andy Hungadc5d9c2017-01-05 17:26:08 -0800194 size_t outputFrameSize = (channels == 1 ? 2 : channels) * sizeof(TO);
Andy Hung546734b2014-04-01 18:31:42 -0700195 size_t outputSize = outputFrameSize * outputFrames;
196 outputSize &= ~7;
197
198 // create the resampler
Andy Hung546734b2014-04-01 18:31:42 -0700199 android::AudioResampler* resampler;
200
Andy Hung42b01112014-07-20 14:04:19 -0700201 resampler = android::AudioResampler::create(
202 is_same<TI, int16_t>::value ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT,
Andy Hung3348e362014-07-07 10:21:44 -0700203 channels, outputFreq, quality);
Andy Hung546734b2014-04-01 18:31:42 -0700204 resampler->setSampleRate(inputFreq);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700205 resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
206 android::AudioResampler::UNITY_GAIN_FLOAT);
Andy Hung546734b2014-04-01 18:31:42 -0700207
208 // set up the reference run
209 std::vector<size_t> refIncr;
210 refIncr.push_back(outputFrames);
Andy Hungccbba6e2017-01-05 16:43:35 -0800211 void* reference = calloc(outputFrames, outputFrameSize);
Andy Hung075abae2014-04-09 19:36:43 -0700212 resample(channels, reference, outputFrames, refIncr, &provider, resampler);
Andy Hung546734b2014-04-01 18:31:42 -0700213
Andy Hung42b01112014-07-20 14:04:19 -0700214 TO *out = reinterpret_cast<TO *>(reference);
Andy Hung546734b2014-04-01 18:31:42 -0700215
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
Andy Hungadc5d9c2017-01-05 17:26:08 -0800221 if (channels == 1) channels = 2; // workaround (mono duplicates output channel)
222
Andy Hung546734b2014-04-01 18:31:42 -0700223 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) {
Andy Hung42b01112014-07-20 14:04:19 -0700236 std::cout << out[i+passbandFrame*channels] << std::endl;
Andy Hung546734b2014-04-01 18:31:42 -0700237 }
238 for (size_t i = 0; i < 10; ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700239 std::cout << out[i+stopbandFrame*channels] << std::endl;
Andy Hung546734b2014-04-01 18:31:42 -0700240 }
241#endif
242 }
243
244 free(reference);
245 delete resampler;
246}
247
Andy Hung6bd378f2017-10-24 19:23:52 -0700248void testFilterResponse(
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700249 size_t channels, unsigned inputFreq, unsigned outputFreq,
250 android::AudioResampler::src_quality quality = android::AudioResampler::DYN_HIGH_QUALITY)
Andy Hung6bd378f2017-10-24 19:23:52 -0700251{
252 // create resampler
253 using ResamplerType = android::AudioResamplerDyn<float, float, float>;
254 std::unique_ptr<ResamplerType> rdyn(
255 static_cast<ResamplerType *>(
256 android::AudioResampler::create(
257 AUDIO_FORMAT_PCM_FLOAT,
258 channels,
259 outputFreq,
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700260 quality)));
Andy Hung6bd378f2017-10-24 19:23:52 -0700261 rdyn->setSampleRate(inputFreq);
262
263 // get design parameters
264 const int phases = rdyn->getPhases();
265 const int halfLength = rdyn->getHalfLength();
266 const float *coefs = rdyn->getFilterCoefs();
267 const double fcr = rdyn->getNormalizedCutoffFrequency();
268 const double tbw = rdyn->getNormalizedTransitionBandwidth();
269 const double attenuation = rdyn->getFilterAttenuation();
270 const double stopbandDb = rdyn->getStopbandAttenuationDb();
271 const double passbandDb = rdyn->getPassbandRippleDb();
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700272 const double fp = fcr - tbw * 0.5;
273 const double fs = fcr + tbw * 0.5;
274 const double idealfs = inputFreq <= outputFreq
275 ? 0.5 // upsample
276 : 0.5 * outputFreq / inputFreq; // downsample
Andy Hung6bd378f2017-10-24 19:23:52 -0700277
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700278 printf("inputFreq:%d outputFreq:%d design quality %d"
Andy Hung6bd378f2017-10-24 19:23:52 -0700279 " phases:%d halfLength:%d"
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700280 " fcr:%lf fp:%lf fs:%lf tbw:%lf fcrp:%lf"
Andy Hung6bd378f2017-10-24 19:23:52 -0700281 " attenuation:%lf stopRipple:%.lf passRipple:%lf"
282 "\n",
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700283 inputFreq, outputFreq, quality,
Andy Hung6bd378f2017-10-24 19:23:52 -0700284 phases, halfLength,
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700285 fcr, fp, fs, tbw, fcr * 100. / idealfs,
Andy Hung6bd378f2017-10-24 19:23:52 -0700286 attenuation, stopbandDb, passbandDb);
287
288 // verify design parameters
289 constexpr int32_t passSteps = 1000;
290 double passMin, passMax, passRipple, stopMax, stopRipple;
291 android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
292 passSteps, phases * passSteps /* stopSteps */,
293 passMin, passMax, passRipple,
294 stopMax, stopRipple);
295 printf("inputFreq:%d outputFreq:%d verify"
296 " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
297 "\n",
298 inputFreq, outputFreq,
299 passMin, passMax, passRipple, stopMax, stopRipple);
300
301 ASSERT_GT(stopRipple, 60.); // enough stopband attenuation
302 ASSERT_LT(passRipple, 0.2); // small passband ripple
303 ASSERT_GT(passMin, 0.99); // we do not attenuate the signal (ideally 1.)
304}
305
Andy Hung546734b2014-04-01 18:31:42 -0700306/* Buffer increment test
307 *
308 * We compare a reference output, where we consume and process the entire
309 * buffer at a time, and a test output, where we provide small chunks of input
310 * data and process small chunks of output (which may not be equivalent in size).
311 *
312 * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
313 */
314TEST(audioflinger_resampler, bufferincrement_fixedphase) {
315 // all of these work
316 static const enum android::AudioResampler::src_quality kQualityArray[] = {
317 android::AudioResampler::LOW_QUALITY,
318 android::AudioResampler::MED_QUALITY,
319 android::AudioResampler::HIGH_QUALITY,
320 android::AudioResampler::VERY_HIGH_QUALITY,
321 android::AudioResampler::DYN_LOW_QUALITY,
322 android::AudioResampler::DYN_MED_QUALITY,
323 android::AudioResampler::DYN_HIGH_QUALITY,
324 };
325
326 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung075abae2014-04-09 19:36:43 -0700327 testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700328 }
329}
330
331TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
332 // all of these work except low quality
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 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung075abae2014-04-09 19:36:43 -0700344 testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
345 }
346}
347
348TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
349 // only dynamic quality
350 static const enum android::AudioResampler::src_quality kQualityArray[] = {
351 android::AudioResampler::DYN_LOW_QUALITY,
352 android::AudioResampler::DYN_MED_QUALITY,
353 android::AudioResampler::DYN_HIGH_QUALITY,
354 };
355
356 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
357 testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
358 }
359}
360
361TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
362 // only dynamic quality
363 static const enum android::AudioResampler::src_quality kQualityArray[] = {
364 android::AudioResampler::DYN_LOW_QUALITY,
365 android::AudioResampler::DYN_MED_QUALITY,
366 android::AudioResampler::DYN_HIGH_QUALITY,
367 };
368
369 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
370 testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700371 }
372}
373
374/* Simple aliasing test
375 *
376 * This checks stopband response of the chirp signal to make sure frequencies
377 * are properly suppressed. It uses downsampling because the stopband can be
378 * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
379 */
Andy Hung42b01112014-07-20 14:04:19 -0700380TEST(audioflinger_resampler, stopbandresponse_integer) {
Andy Hung546734b2014-04-01 18:31:42 -0700381 // not all of these may work (old resamplers fail on downsampling)
382 static const enum android::AudioResampler::src_quality kQualityArray[] = {
383 //android::AudioResampler::LOW_QUALITY,
384 //android::AudioResampler::MED_QUALITY,
385 //android::AudioResampler::HIGH_QUALITY,
386 //android::AudioResampler::VERY_HIGH_QUALITY,
387 android::AudioResampler::DYN_LOW_QUALITY,
388 android::AudioResampler::DYN_MED_QUALITY,
389 android::AudioResampler::DYN_HIGH_QUALITY,
390 };
391
392 // in this test we assume a maximum transition band between 12kHz and 20kHz.
393 // there must be at least 60dB relative attenuation between stopband and passband.
394 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700395 testStopbandDownconversion<int16_t, int32_t>(
396 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700397 }
398
399 // in this test we assume a maximum transition band between 7kHz and 15kHz.
400 // there must be at least 60dB relative attenuation between stopband and passband.
401 // (the weird ratio triggers interpolative resampling)
402 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
Andy Hung42b01112014-07-20 14:04:19 -0700403 testStopbandDownconversion<int16_t, int32_t>(
404 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
Andy Hung546734b2014-04-01 18:31:42 -0700405 }
406}
Andy Hung42b01112014-07-20 14:04:19 -0700407
Andy Hungadc5d9c2017-01-05 17:26:08 -0800408TEST(audioflinger_resampler, stopbandresponse_integer_mono) {
409 // not all of these may work (old resamplers fail on downsampling)
410 static const enum android::AudioResampler::src_quality kQualityArray[] = {
411 //android::AudioResampler::LOW_QUALITY,
412 //android::AudioResampler::MED_QUALITY,
413 //android::AudioResampler::HIGH_QUALITY,
414 //android::AudioResampler::VERY_HIGH_QUALITY,
415 android::AudioResampler::DYN_LOW_QUALITY,
416 android::AudioResampler::DYN_MED_QUALITY,
417 android::AudioResampler::DYN_HIGH_QUALITY,
418 };
419
420 // in this test we assume a maximum transition band between 12kHz and 20kHz.
421 // there must be at least 60dB relative attenuation between stopband and passband.
422 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
423 testStopbandDownconversion<int16_t, int32_t>(
424 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
425 }
426
427 // in this test we assume a maximum transition band between 7kHz and 15kHz.
428 // there must be at least 60dB relative attenuation between stopband and passband.
429 // (the weird ratio triggers interpolative resampling)
430 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
431 testStopbandDownconversion<int16_t, int32_t>(
432 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
433 }
434}
435
Andy Hung42b01112014-07-20 14:04:19 -0700436TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
437 // not all of these may work (old resamplers fail on downsampling)
438 static const enum android::AudioResampler::src_quality kQualityArray[] = {
439 //android::AudioResampler::LOW_QUALITY,
440 //android::AudioResampler::MED_QUALITY,
441 //android::AudioResampler::HIGH_QUALITY,
442 //android::AudioResampler::VERY_HIGH_QUALITY,
443 android::AudioResampler::DYN_LOW_QUALITY,
444 android::AudioResampler::DYN_MED_QUALITY,
445 android::AudioResampler::DYN_HIGH_QUALITY,
446 };
447
448 // in this test we assume a maximum transition band between 12kHz and 20kHz.
449 // there must be at least 60dB relative attenuation between stopband and passband.
450 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
451 testStopbandDownconversion<int16_t, int32_t>(
452 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
453 }
454
455 // in this test we assume a maximum transition band between 7kHz and 15kHz.
456 // there must be at least 60dB relative attenuation between stopband and passband.
457 // (the weird ratio triggers interpolative resampling)
458 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
459 testStopbandDownconversion<int16_t, int32_t>(
460 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
461 }
462}
463
464TEST(audioflinger_resampler, stopbandresponse_float) {
465 // not all of these may work (old resamplers fail on downsampling)
466 static const enum android::AudioResampler::src_quality kQualityArray[] = {
467 //android::AudioResampler::LOW_QUALITY,
468 //android::AudioResampler::MED_QUALITY,
469 //android::AudioResampler::HIGH_QUALITY,
470 //android::AudioResampler::VERY_HIGH_QUALITY,
471 android::AudioResampler::DYN_LOW_QUALITY,
472 android::AudioResampler::DYN_MED_QUALITY,
473 android::AudioResampler::DYN_HIGH_QUALITY,
474 };
475
476 // in this test we assume a maximum transition band between 12kHz and 20kHz.
477 // there must be at least 60dB relative attenuation between stopband and passband.
478 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
479 testStopbandDownconversion<float, float>(
480 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
481 }
482
483 // in this test we assume a maximum transition band between 7kHz and 15kHz.
484 // there must be at least 60dB relative attenuation between stopband and passband.
485 // (the weird ratio triggers interpolative resampling)
486 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
487 testStopbandDownconversion<float, float>(
488 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
489 }
490}
491
Andy Hungadc5d9c2017-01-05 17:26:08 -0800492TEST(audioflinger_resampler, stopbandresponse_float_mono) {
493 // not all of these may work (old resamplers fail on downsampling)
494 static const enum android::AudioResampler::src_quality kQualityArray[] = {
495 //android::AudioResampler::LOW_QUALITY,
496 //android::AudioResampler::MED_QUALITY,
497 //android::AudioResampler::HIGH_QUALITY,
498 //android::AudioResampler::VERY_HIGH_QUALITY,
499 android::AudioResampler::DYN_LOW_QUALITY,
500 android::AudioResampler::DYN_MED_QUALITY,
501 android::AudioResampler::DYN_HIGH_QUALITY,
502 };
503
504 // in this test we assume a maximum transition band between 12kHz and 20kHz.
505 // there must be at least 60dB relative attenuation between stopband and passband.
506 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
507 testStopbandDownconversion<float, float>(
508 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
509 }
510
511 // in this test we assume a maximum transition band between 7kHz and 15kHz.
512 // there must be at least 60dB relative attenuation between stopband and passband.
513 // (the weird ratio triggers interpolative resampling)
514 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
515 testStopbandDownconversion<float, float>(
516 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
517 }
518}
519
Andy Hung42b01112014-07-20 14:04:19 -0700520TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
521 // not all of these may work (old resamplers fail on downsampling)
522 static const enum android::AudioResampler::src_quality kQualityArray[] = {
523 //android::AudioResampler::LOW_QUALITY,
524 //android::AudioResampler::MED_QUALITY,
525 //android::AudioResampler::HIGH_QUALITY,
526 //android::AudioResampler::VERY_HIGH_QUALITY,
527 android::AudioResampler::DYN_LOW_QUALITY,
528 android::AudioResampler::DYN_MED_QUALITY,
529 android::AudioResampler::DYN_HIGH_QUALITY,
530 };
531
532 // in this test we assume a maximum transition band between 12kHz and 20kHz.
533 // there must be at least 60dB relative attenuation between stopband and passband.
534 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
535 testStopbandDownconversion<float, float>(
536 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
537 }
538
539 // in this test we assume a maximum transition band between 7kHz and 15kHz.
540 // there must be at least 60dB relative attenuation between stopband and passband.
541 // (the weird ratio triggers interpolative resampling)
542 for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
543 testStopbandDownconversion<float, float>(
544 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
545 }
546}
547
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700548// Selected downsampling responses for various frequencies relating to hearing aid.
549TEST(audioflinger_resampler, downsamplingresponse) {
550 static constexpr android::AudioResampler::src_quality qualities[] = {
551 android::AudioResampler::DYN_LOW_QUALITY,
552 android::AudioResampler::DYN_MED_QUALITY,
553 android::AudioResampler::DYN_HIGH_QUALITY,
554 };
555 static constexpr int inSampleRates[] = {
556 32000,
557 44100,
558 48000,
559 };
560 static constexpr int outSampleRates[] = {
561 16000,
562 24000,
563 };
564
565 for (auto quality : qualities) {
566 for (int outSampleRate : outSampleRates) {
567 for (int inSampleRate : inSampleRates) {
568 testFilterResponse(2 /* channels */, inSampleRate, outSampleRate, quality);
569 }
570 }
571 }
572}
573
574// General responses for typical output device scenarios - 44.1, 48, 96 kHz
575// (48, 96 are part of the same resampler generation family).
576TEST(audioflinger_resampler, generalresponse) {
577 static constexpr int inSampleRates[] = {
Andy Hung6bd378f2017-10-24 19:23:52 -0700578 8000,
579 11025,
580 12000,
581 16000,
582 22050,
583 24000,
584 32000,
585 44100,
586 48000,
587 88200,
588 96000,
589 176400,
590 192000,
591 };
Andy Hung2eaa1ee2019-04-02 15:49:55 -0700592 static constexpr int outSampleRates[] = {
593 44100,
Andy Hung6bd378f2017-10-24 19:23:52 -0700594 48000,
595 96000,
596 };
597
598 for (int outSampleRate : outSampleRates) {
599 for (int inSampleRate : inSampleRates) {
600 testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
601 }
602 }
603}