remix_resample_unittest.cc (10261B)
1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "audio/remix_resample.h" 12 13 #include <cmath> 14 #include <cstddef> 15 #include <cstdint> 16 #include <cstdio> 17 18 #include "api/audio/audio_frame.h" 19 #include "common_audio/resampler/include/push_resampler.h" 20 #include "test/gtest.h" 21 22 namespace webrtc { 23 namespace voe { 24 namespace { 25 26 int GetFrameSize(int sample_rate_hz) { 27 return sample_rate_hz / 100; 28 } 29 30 class UtilityTest : public ::testing::Test { 31 protected: 32 UtilityTest() { 33 src_frame_.sample_rate_hz_ = 16000; 34 src_frame_.samples_per_channel_ = src_frame_.sample_rate_hz_ / 100; 35 src_frame_.num_channels_ = 1; 36 dst_frame_.CopyFrom(src_frame_); 37 golden_frame_.CopyFrom(src_frame_); 38 } 39 40 void RunResampleTest(int src_channels, 41 int src_sample_rate_hz, 42 int dst_channels, 43 int dst_sample_rate_hz); 44 45 PushResampler<int16_t> resampler_; 46 AudioFrame src_frame_; 47 AudioFrame dst_frame_; 48 AudioFrame golden_frame_; 49 }; 50 51 // Sets the signal value to increase by `data` with every sample. Floats are 52 // used so non-integer values result in rounding error, but not an accumulating 53 // error. 54 void SetMonoFrame(float data, int sample_rate_hz, AudioFrame* frame) { 55 frame->Mute(); 56 frame->num_channels_ = 1; 57 frame->sample_rate_hz_ = sample_rate_hz; 58 frame->samples_per_channel_ = GetFrameSize(sample_rate_hz); 59 int16_t* frame_data = frame->mutable_data(); 60 for (size_t i = 0; i < frame->samples_per_channel_; i++) { 61 frame_data[i] = static_cast<int16_t>(data * i); 62 } 63 } 64 65 // Keep the existing sample rate. 66 void SetMonoFrame(float data, AudioFrame* frame) { 67 SetMonoFrame(data, frame->sample_rate_hz_, frame); 68 } 69 70 // Sets the signal value to increase by `left` and `right` with every sample in 71 // each channel respectively. 72 void SetStereoFrame(float left, 73 float right, 74 int sample_rate_hz, 75 AudioFrame* frame) { 76 frame->Mute(); 77 frame->num_channels_ = 2; 78 frame->sample_rate_hz_ = sample_rate_hz; 79 frame->samples_per_channel_ = GetFrameSize(sample_rate_hz); 80 int16_t* frame_data = frame->mutable_data(); 81 for (size_t i = 0; i < frame->samples_per_channel_; i++) { 82 frame_data[i * 2] = static_cast<int16_t>(left * i); 83 frame_data[i * 2 + 1] = static_cast<int16_t>(right * i); 84 } 85 } 86 87 // Keep the existing sample rate. 88 void SetStereoFrame(float left, float right, AudioFrame* frame) { 89 SetStereoFrame(left, right, frame->sample_rate_hz_, frame); 90 } 91 92 // Sets the signal value to increase by `ch1`, `ch2`, `ch3`, `ch4` with every 93 // sample in each channel respectively. 94 void SetQuadFrame(float ch1, 95 float ch2, 96 float ch3, 97 float ch4, 98 int sample_rate_hz, 99 AudioFrame* frame) { 100 frame->Mute(); 101 frame->num_channels_ = 4; 102 frame->sample_rate_hz_ = sample_rate_hz; 103 frame->samples_per_channel_ = GetFrameSize(sample_rate_hz); 104 int16_t* frame_data = frame->mutable_data(); 105 for (size_t i = 0; i < frame->samples_per_channel_; i++) { 106 frame_data[i * 4] = static_cast<int16_t>(ch1 * i); 107 frame_data[i * 4 + 1] = static_cast<int16_t>(ch2 * i); 108 frame_data[i * 4 + 2] = static_cast<int16_t>(ch3 * i); 109 frame_data[i * 4 + 3] = static_cast<int16_t>(ch4 * i); 110 } 111 } 112 113 void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) { 114 EXPECT_EQ(ref_frame.num_channels_, test_frame.num_channels_); 115 EXPECT_EQ(ref_frame.samples_per_channel_, test_frame.samples_per_channel_); 116 EXPECT_EQ(ref_frame.sample_rate_hz_, test_frame.sample_rate_hz_); 117 } 118 119 // Computes the best SNR based on the error between `ref_frame` and 120 // `test_frame`. It allows for up to a `max_delay` in samples between the 121 // signals to compensate for the resampling delay. 122 float ComputeSNR(const AudioFrame& ref_frame, 123 const AudioFrame& test_frame, 124 size_t max_delay) { 125 VerifyParams(ref_frame, test_frame); 126 float best_snr = 0; 127 size_t best_delay = 0; 128 for (size_t delay = 0; delay <= max_delay; delay++) { 129 float mse = 0; 130 float variance = 0; 131 const int16_t* ref_frame_data = ref_frame.data(); 132 const int16_t* test_frame_data = test_frame.data(); 133 for (size_t i = 0; 134 i < ref_frame.samples_per_channel_ * ref_frame.num_channels_ - delay; 135 i++) { 136 int error = ref_frame_data[i] - test_frame_data[i + delay]; 137 mse += error * error; 138 variance += ref_frame_data[i] * ref_frame_data[i]; 139 } 140 float snr = 100; // We assign 100 dB to the zero-error case. 141 if (mse > 0) 142 snr = 10 * std::log10(variance / mse); 143 if (snr > best_snr) { 144 best_snr = snr; 145 best_delay = delay; 146 } 147 } 148 printf("SNR=%.1f dB at delay=%zu\n", best_snr, best_delay); 149 return best_snr; 150 } 151 152 void VerifyFramesAreEqual(const AudioFrame& ref_frame, 153 const AudioFrame& test_frame) { 154 VerifyParams(ref_frame, test_frame); 155 const int16_t* ref_frame_data = ref_frame.data(); 156 const int16_t* test_frame_data = test_frame.data(); 157 for (size_t i = 0; 158 i < ref_frame.samples_per_channel_ * ref_frame.num_channels_; i++) { 159 EXPECT_EQ(ref_frame_data[i], test_frame_data[i]); 160 } 161 } 162 163 void UtilityTest::RunResampleTest(int src_channels, 164 int src_sample_rate_hz, 165 int dst_channels, 166 int dst_sample_rate_hz) { 167 PushResampler<int16_t> resampler; // Create a new one with every test. 168 const int16_t kSrcCh1 = 30; // Shouldn't overflow for any used sample rate. 169 const int16_t kSrcCh2 = 15; 170 const int16_t kSrcCh3 = 22; 171 const int16_t kSrcCh4 = 8; 172 const float resampling_factor = 173 (1.0 * src_sample_rate_hz) / dst_sample_rate_hz; 174 const float dst_ch1 = resampling_factor * kSrcCh1; 175 const float dst_ch2 = resampling_factor * kSrcCh2; 176 const float dst_ch3 = resampling_factor * kSrcCh3; 177 const float dst_ch4 = resampling_factor * kSrcCh4; 178 const float dst_stereo_to_mono = (dst_ch1 + dst_ch2) / 2; 179 const float dst_quad_to_mono = (dst_ch1 + dst_ch2 + dst_ch3 + dst_ch4) / 4; 180 const float dst_quad_to_stereo_ch1 = (dst_ch1 + dst_ch2) / 2; 181 const float dst_quad_to_stereo_ch2 = (dst_ch3 + dst_ch4) / 2; 182 if (src_channels == 1) 183 SetMonoFrame(kSrcCh1, src_sample_rate_hz, &src_frame_); 184 else if (src_channels == 2) 185 SetStereoFrame(kSrcCh1, kSrcCh2, src_sample_rate_hz, &src_frame_); 186 else 187 SetQuadFrame(kSrcCh1, kSrcCh2, kSrcCh3, kSrcCh4, src_sample_rate_hz, 188 &src_frame_); 189 190 if (dst_channels == 1) { 191 SetMonoFrame(0, dst_sample_rate_hz, &dst_frame_); 192 if (src_channels == 1) 193 SetMonoFrame(dst_ch1, dst_sample_rate_hz, &golden_frame_); 194 else if (src_channels == 2) 195 SetMonoFrame(dst_stereo_to_mono, dst_sample_rate_hz, &golden_frame_); 196 else 197 SetMonoFrame(dst_quad_to_mono, dst_sample_rate_hz, &golden_frame_); 198 } else { 199 SetStereoFrame(0, 0, dst_sample_rate_hz, &dst_frame_); 200 if (src_channels == 1) 201 SetStereoFrame(dst_ch1, dst_ch1, dst_sample_rate_hz, &golden_frame_); 202 else if (src_channels == 2) 203 SetStereoFrame(dst_ch1, dst_ch2, dst_sample_rate_hz, &golden_frame_); 204 else 205 SetStereoFrame(dst_quad_to_stereo_ch1, dst_quad_to_stereo_ch2, 206 dst_sample_rate_hz, &golden_frame_); 207 } 208 209 // The sinc resampler has a known delay, which we compute here. Multiplying by 210 // two gives us a crude maximum for any resampling, as the old resampler 211 // typically (but not always) has lower delay. 212 static const size_t kInputKernelDelaySamples = 16; 213 const size_t max_delay = static_cast<size_t>( 214 static_cast<double>(dst_sample_rate_hz) / src_sample_rate_hz * 215 kInputKernelDelaySamples * dst_channels * 2); 216 printf("(%d, %d Hz) -> (%d, %d Hz) ", // SNR reported on the same line later. 217 src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); 218 RemixAndResample(src_frame_, &resampler, &dst_frame_); 219 220 if (src_sample_rate_hz == 96000 && dst_sample_rate_hz <= 11025) { 221 // The sinc resampler gives poor SNR at this extreme conversion, but we 222 // expect to see this rarely in practice. 223 EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 14.0f); 224 } else { 225 EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 46.0f); 226 } 227 } 228 229 TEST_F(UtilityTest, RemixAndResampleCopyFrameSucceeds) { 230 // Stereo -> stereo. 231 SetStereoFrame(10, 10, &src_frame_); 232 SetStereoFrame(0, 0, &dst_frame_); 233 RemixAndResample(src_frame_, &resampler_, &dst_frame_); 234 VerifyFramesAreEqual(src_frame_, dst_frame_); 235 236 // Mono -> mono. 237 SetMonoFrame(20, &src_frame_); 238 SetMonoFrame(0, &dst_frame_); 239 RemixAndResample(src_frame_, &resampler_, &dst_frame_); 240 VerifyFramesAreEqual(src_frame_, dst_frame_); 241 } 242 243 TEST_F(UtilityTest, RemixAndResampleMixingOnlySucceeds) { 244 // Stereo -> mono. 245 SetStereoFrame(0, 0, &dst_frame_); 246 SetMonoFrame(10, &src_frame_); 247 SetStereoFrame(10, 10, &golden_frame_); 248 RemixAndResample(src_frame_, &resampler_, &dst_frame_); 249 VerifyFramesAreEqual(dst_frame_, golden_frame_); 250 251 // Mono -> stereo. 252 SetMonoFrame(0, &dst_frame_); 253 SetStereoFrame(10, 20, &src_frame_); 254 SetMonoFrame(15, &golden_frame_); 255 RemixAndResample(src_frame_, &resampler_, &dst_frame_); 256 VerifyFramesAreEqual(golden_frame_, dst_frame_); 257 } 258 259 TEST_F(UtilityTest, RemixAndResampleSucceeds) { 260 const int kSampleRates[] = {8000, 11025, 16000, 22050, 261 32000, 44100, 48000, 96000}; 262 const int kSrcChannels[] = {1, 2, 4}; 263 const int kDstChannels[] = {1, 2}; 264 265 for (int src_rate : kSampleRates) { 266 for (int dst_rate : kSampleRates) { 267 for (size_t src_channels : kSrcChannels) { 268 for (size_t dst_channels : kDstChannels) { 269 RunResampleTest(src_channels, src_rate, dst_channels, dst_rate); 270 } 271 } 272 } 273 } 274 } 275 276 } // namespace 277 } // namespace voe 278 } // namespace webrtc