Home | History | Annotate | Download | only in tests
      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>
     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 
     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 
     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 
     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>
    159 inline double sqr(T v)
    160 {
    161     double dv = static_cast<double>(v);
    162     return dv * dv;
    163 }
    164 
    165 template <typename T>
    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>
    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 
    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  */
    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 
    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 
    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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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