1*05767d91SRobert Wu /*
2*05767d91SRobert Wu * Copyright 2022 The Android Open Source Project
3*05767d91SRobert Wu *
4*05767d91SRobert Wu * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu * You may obtain a copy of the License at
7*05767d91SRobert Wu *
8*05767d91SRobert Wu * http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu *
10*05767d91SRobert Wu * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu * See the License for the specific language governing permissions and
14*05767d91SRobert Wu * limitations under the License.
15*05767d91SRobert Wu */
16*05767d91SRobert Wu
17*05767d91SRobert Wu /*
18*05767d91SRobert Wu * Test FlowGraph
19*05767d91SRobert Wu */
20*05767d91SRobert Wu
21*05767d91SRobert Wu #include "math.h"
22*05767d91SRobert Wu #include "stdio.h"
23*05767d91SRobert Wu
24*05767d91SRobert Wu #include <gtest/gtest.h>
25*05767d91SRobert Wu #include <oboe/Oboe.h>
26*05767d91SRobert Wu
27*05767d91SRobert Wu #include "flowgraph/resampler/MultiChannelResampler.h"
28*05767d91SRobert Wu
29*05767d91SRobert Wu using namespace oboe::resampler;
30*05767d91SRobert Wu
31*05767d91SRobert Wu // Measure zero crossings.
countZeroCrossingsWithHysteresis(float * input,int32_t numSamples)32*05767d91SRobert Wu static int32_t countZeroCrossingsWithHysteresis(float *input, int32_t numSamples) {
33*05767d91SRobert Wu const float kHysteresisLevel = 0.25f;
34*05767d91SRobert Wu int zeroCrossingCount = 0;
35*05767d91SRobert Wu int state = 0; // can be -1, 0, +1
36*05767d91SRobert Wu for (int i = 0; i < numSamples; i++) {
37*05767d91SRobert Wu if (input[i] >= kHysteresisLevel) {
38*05767d91SRobert Wu if (state < 0) {
39*05767d91SRobert Wu zeroCrossingCount++;
40*05767d91SRobert Wu }
41*05767d91SRobert Wu state = 1;
42*05767d91SRobert Wu } else if (input[i] <= -kHysteresisLevel) {
43*05767d91SRobert Wu if (state > 0) {
44*05767d91SRobert Wu zeroCrossingCount++;
45*05767d91SRobert Wu }
46*05767d91SRobert Wu state = -1;
47*05767d91SRobert Wu }
48*05767d91SRobert Wu }
49*05767d91SRobert Wu return zeroCrossingCount;
50*05767d91SRobert Wu }
51*05767d91SRobert Wu
52*05767d91SRobert Wu static constexpr int kChannelCount = 1;
53*05767d91SRobert Wu
54*05767d91SRobert Wu /**
55*05767d91SRobert Wu * Convert a sine wave and then look for glitches.
56*05767d91SRobert Wu * Glitches have a high value in the second derivative.
57*05767d91SRobert Wu */
checkResampler(int32_t sourceRate,int32_t sinkRate,MultiChannelResampler::Quality quality)58*05767d91SRobert Wu static void checkResampler(int32_t sourceRate, int32_t sinkRate,
59*05767d91SRobert Wu MultiChannelResampler::Quality quality) {
60*05767d91SRobert Wu const int kNumOutputSamples = 10000;
61*05767d91SRobert Wu const double framesPerCycle = 81.379; // target output period
62*05767d91SRobert Wu
63*05767d91SRobert Wu int numInputSamples = kNumOutputSamples * sourceRate / sinkRate;
64*05767d91SRobert Wu
65*05767d91SRobert Wu std::unique_ptr<float[]> inputBuffer = std::make_unique<float[]>(numInputSamples);
66*05767d91SRobert Wu std::unique_ptr<float[]> outputBuffer = std::make_unique<float[]>(kNumOutputSamples);
67*05767d91SRobert Wu
68*05767d91SRobert Wu // Generate a sine wave for input.
69*05767d91SRobert Wu const double kPhaseIncrement = 2.0 * sinkRate / (framesPerCycle * sourceRate);
70*05767d91SRobert Wu double phase = 0.0;
71*05767d91SRobert Wu for (int i = 0; i < numInputSamples; i++) {
72*05767d91SRobert Wu inputBuffer[i] = sin(phase * M_PI);
73*05767d91SRobert Wu phase += kPhaseIncrement;
74*05767d91SRobert Wu while (phase > 1.0) {
75*05767d91SRobert Wu phase -= 2.0;
76*05767d91SRobert Wu }
77*05767d91SRobert Wu }
78*05767d91SRobert Wu int sourceZeroCrossingCount = countZeroCrossingsWithHysteresis(inputBuffer.get(), numInputSamples);
79*05767d91SRobert Wu
80*05767d91SRobert Wu // Use a MultiChannelResampler to convert from the sourceRate to the sinkRate.
81*05767d91SRobert Wu std::unique_ptr<MultiChannelResampler> mcResampler;
82*05767d91SRobert Wu mcResampler.reset(MultiChannelResampler::make(kChannelCount,
83*05767d91SRobert Wu sourceRate,
84*05767d91SRobert Wu sinkRate,
85*05767d91SRobert Wu quality));
86*05767d91SRobert Wu int inputFramesLeft = numInputSamples;
87*05767d91SRobert Wu int numRead = 0;
88*05767d91SRobert Wu float *input = inputBuffer.get(); // for iteration
89*05767d91SRobert Wu float *output = outputBuffer.get();
90*05767d91SRobert Wu while (inputFramesLeft > 0) {
91*05767d91SRobert Wu if (mcResampler->isWriteNeeded()) {
92*05767d91SRobert Wu mcResampler->writeNextFrame(input);
93*05767d91SRobert Wu input++;
94*05767d91SRobert Wu inputFramesLeft--;
95*05767d91SRobert Wu } else {
96*05767d91SRobert Wu mcResampler->readNextFrame(output);
97*05767d91SRobert Wu output++;
98*05767d91SRobert Wu numRead++;
99*05767d91SRobert Wu }
100*05767d91SRobert Wu }
101*05767d91SRobert Wu
102*05767d91SRobert Wu // Flush out remaining frames from the flowgraph
103*05767d91SRobert Wu while (!mcResampler->isWriteNeeded()) {
104*05767d91SRobert Wu mcResampler->readNextFrame(output);
105*05767d91SRobert Wu output++;
106*05767d91SRobert Wu numRead++;
107*05767d91SRobert Wu }
108*05767d91SRobert Wu
109*05767d91SRobert Wu ASSERT_LE(numRead, kNumOutputSamples);
110*05767d91SRobert Wu // Some frames are lost priming the FIR filter.
111*05767d91SRobert Wu const int kMaxAlgorithmicFrameLoss = 5;
112*05767d91SRobert Wu EXPECT_GT(numRead, kNumOutputSamples - kMaxAlgorithmicFrameLoss);
113*05767d91SRobert Wu
114*05767d91SRobert Wu int sinkZeroCrossingCount = countZeroCrossingsWithHysteresis(outputBuffer.get(), numRead);
115*05767d91SRobert Wu // The sine wave may be cut off partially. This may cause multiple crossing
116*05767d91SRobert Wu // differences when upsampling.
117*05767d91SRobert Wu const int kMaxZeroCrossingDelta = std::max(sinkRate / sourceRate / 2, 1);
118*05767d91SRobert Wu EXPECT_LE(abs(sourceZeroCrossingCount - sinkZeroCrossingCount), kMaxZeroCrossingDelta);
119*05767d91SRobert Wu
120*05767d91SRobert Wu // Detect glitches by looking for spikes in the second derivative.
121*05767d91SRobert Wu output = outputBuffer.get();
122*05767d91SRobert Wu float previousValue = output[0];
123*05767d91SRobert Wu float previousSlope = output[1] - output[0];
124*05767d91SRobert Wu for (int i = 0; i < numRead; i++) {
125*05767d91SRobert Wu float slope = output[i] - previousValue;
126*05767d91SRobert Wu float slopeDelta = fabs(slope - previousSlope);
127*05767d91SRobert Wu // Skip a few samples because there are often some steep slope changes at the beginning.
128*05767d91SRobert Wu if (i > 10) {
129*05767d91SRobert Wu EXPECT_LT(slopeDelta, 0.1);
130*05767d91SRobert Wu }
131*05767d91SRobert Wu previousValue = output[i];
132*05767d91SRobert Wu previousSlope = slope;
133*05767d91SRobert Wu }
134*05767d91SRobert Wu
135*05767d91SRobert Wu #if 0
136*05767d91SRobert Wu // Save to disk for inspection.
137*05767d91SRobert Wu FILE *fp = fopen( "/sdcard/Download/src_float_out.raw" , "wb" );
138*05767d91SRobert Wu fwrite(outputBuffer.get(), sizeof(float), numRead, fp );
139*05767d91SRobert Wu fclose(fp);
140*05767d91SRobert Wu #endif
141*05767d91SRobert Wu }
142*05767d91SRobert Wu
143*05767d91SRobert Wu
TEST(test_resampler,resampler_scan_all)144*05767d91SRobert Wu TEST(test_resampler, resampler_scan_all) {
145*05767d91SRobert Wu const int rates[] = {8000, 11025, 22050, 32000, 44100, 48000, 64000, 88200, 96000};
146*05767d91SRobert Wu const MultiChannelResampler::Quality qualities[] =
147*05767d91SRobert Wu {
148*05767d91SRobert Wu MultiChannelResampler::Quality::Fastest,
149*05767d91SRobert Wu MultiChannelResampler::Quality::Low,
150*05767d91SRobert Wu MultiChannelResampler::Quality::Medium,
151*05767d91SRobert Wu MultiChannelResampler::Quality::High,
152*05767d91SRobert Wu MultiChannelResampler::Quality::Best
153*05767d91SRobert Wu };
154*05767d91SRobert Wu for (int srcRate : rates) {
155*05767d91SRobert Wu for (int destRate : rates) {
156*05767d91SRobert Wu for (auto quality : qualities) {
157*05767d91SRobert Wu if (srcRate != destRate) {
158*05767d91SRobert Wu checkResampler(srcRate, destRate, quality);
159*05767d91SRobert Wu }
160*05767d91SRobert Wu }
161*05767d91SRobert Wu }
162*05767d91SRobert Wu }
163*05767d91SRobert Wu }
164*05767d91SRobert Wu
TEST(test_resampler,resampler_8000_11025_best)165*05767d91SRobert Wu TEST(test_resampler, resampler_8000_11025_best) {
166*05767d91SRobert Wu checkResampler(8000, 11025, MultiChannelResampler::Quality::Best);
167*05767d91SRobert Wu }
TEST(test_resampler,resampler_8000_48000_best)168*05767d91SRobert Wu TEST(test_resampler, resampler_8000_48000_best) {
169*05767d91SRobert Wu checkResampler(8000, 48000, MultiChannelResampler::Quality::Best);
170*05767d91SRobert Wu }
171*05767d91SRobert Wu
TEST(test_resampler,resampler_8000_44100_best)172*05767d91SRobert Wu TEST(test_resampler, resampler_8000_44100_best) {
173*05767d91SRobert Wu checkResampler(8000, 44100, MultiChannelResampler::Quality::Best);
174*05767d91SRobert Wu }
175*05767d91SRobert Wu
TEST(test_resampler,resampler_11025_24000_best)176*05767d91SRobert Wu TEST(test_resampler, resampler_11025_24000_best) {
177*05767d91SRobert Wu checkResampler(11025, 24000, MultiChannelResampler::Quality::Best);
178*05767d91SRobert Wu }
179*05767d91SRobert Wu
TEST(test_resampler,resampler_11025_48000_fastest)180*05767d91SRobert Wu TEST(test_resampler, resampler_11025_48000_fastest) {
181*05767d91SRobert Wu checkResampler(11025, 48000, MultiChannelResampler::Quality::Fastest);
182*05767d91SRobert Wu }
TEST(test_resampler,resampler_11025_48000_low)183*05767d91SRobert Wu TEST(test_resampler, resampler_11025_48000_low) {
184*05767d91SRobert Wu checkResampler(11025, 48000, MultiChannelResampler::Quality::Low);
185*05767d91SRobert Wu }
TEST(test_resampler,resampler_11025_48000_medium)186*05767d91SRobert Wu TEST(test_resampler, resampler_11025_48000_medium) {
187*05767d91SRobert Wu checkResampler(11025, 48000, MultiChannelResampler::Quality::Medium);
188*05767d91SRobert Wu }
TEST(test_resampler,resampler_11025_48000_high)189*05767d91SRobert Wu TEST(test_resampler, resampler_11025_48000_high) {
190*05767d91SRobert Wu checkResampler(11025, 48000, MultiChannelResampler::Quality::High);
191*05767d91SRobert Wu }
192*05767d91SRobert Wu
TEST(test_resampler,resampler_11025_48000_best)193*05767d91SRobert Wu TEST(test_resampler, resampler_11025_48000_best) {
194*05767d91SRobert Wu checkResampler(11025, 48000, MultiChannelResampler::Quality::Best);
195*05767d91SRobert Wu }
196*05767d91SRobert Wu
TEST(test_resampler,resampler_11025_44100_best)197*05767d91SRobert Wu TEST(test_resampler, resampler_11025_44100_best) {
198*05767d91SRobert Wu checkResampler(11025, 44100, MultiChannelResampler::Quality::Best);
199*05767d91SRobert Wu }
200*05767d91SRobert Wu
TEST(test_resampler,resampler_11025_88200_best)201*05767d91SRobert Wu TEST(test_resampler, resampler_11025_88200_best) {
202*05767d91SRobert Wu checkResampler(11025, 88200, MultiChannelResampler::Quality::Best);
203*05767d91SRobert Wu }
204*05767d91SRobert Wu
TEST(test_resampler,resampler_16000_48000_best)205*05767d91SRobert Wu TEST(test_resampler, resampler_16000_48000_best) {
206*05767d91SRobert Wu checkResampler(16000, 48000, MultiChannelResampler::Quality::Best);
207*05767d91SRobert Wu }
208*05767d91SRobert Wu
TEST(test_resampler,resampler_44100_48000_low)209*05767d91SRobert Wu TEST(test_resampler, resampler_44100_48000_low) {
210*05767d91SRobert Wu checkResampler(44100, 48000, MultiChannelResampler::Quality::Low);
211*05767d91SRobert Wu }
TEST(test_resampler,resampler_44100_48000_best)212*05767d91SRobert Wu TEST(test_resampler, resampler_44100_48000_best) {
213*05767d91SRobert Wu checkResampler(44100, 48000, MultiChannelResampler::Quality::Best);
214*05767d91SRobert Wu }
215*05767d91SRobert Wu
216*05767d91SRobert Wu // Look for glitches when downsampling.
TEST(test_resampler,resampler_48000_11025_best)217*05767d91SRobert Wu TEST(test_resampler, resampler_48000_11025_best) {
218*05767d91SRobert Wu checkResampler(48000, 11025, MultiChannelResampler::Quality::Best);
219*05767d91SRobert Wu }
TEST(test_resampler,resampler_48000_44100_best)220*05767d91SRobert Wu TEST(test_resampler, resampler_48000_44100_best) {
221*05767d91SRobert Wu checkResampler(48000, 44100, MultiChannelResampler::Quality::Best);
222*05767d91SRobert Wu }
TEST(test_resampler,resampler_44100_11025_best)223*05767d91SRobert Wu TEST(test_resampler, resampler_44100_11025_best) {
224*05767d91SRobert Wu checkResampler(44100, 11025, MultiChannelResampler::Quality::Best);
225*05767d91SRobert Wu }
226