| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "audio_prep/mfcc.h" |
| |
| #include "pw_unit_test/framework.h" |
| |
| static MfccParams golden_params = {.num_frames = 3, |
| .num_mel_bins = 10, |
| .audio_samp_rate = 16000, |
| .low_edge_hz = 125, |
| .upper_edge_hz = 7600, |
| .win_len_sec = 0.000625, |
| .hop_len_sec = 0.0003125, |
| .log_floor = 0.01, |
| .log_scaler = 20}; |
| static int16_t golden_input[] = {7954, 10085, 8733, 10844, 29949, |
| -549, 20833, 30345, 18086, 11375, |
| -27309, 12323, -22891, -23360, 11958}; |
| static uint8_t golden_output[] = {0, 0, 191, 187, 174, 186, 179, 175, 179, 173, |
| 0, 0, 209, 205, 181, 193, 182, 199, 209, 216, |
| 0, 0, 198, 194, 192, 204, 196, 201, 212, 223}; |
| |
| TEST(MfccTest, AgreesWithGoldenValues) { |
| // set parameters |
| set_mfcc_params(&golden_params); |
| int out_len = golden_params.num_frames * golden_params.num_mel_bins; |
| uint8_t* out = reinterpret_cast<uint8_t*>(malloc(out_len * sizeof(uint8_t))); |
| // extract MFCC |
| extract_mfcc(golden_input, out, sizeof(golden_input) / sizeof(int16_t)); |
| |
| int kTolerance = 0; |
| #ifdef MFCC_WITH_RVV |
| kTolerance = 1; |
| #endif |
| for (int i = 0; i < out_len; i++) { |
| int diff = out[i] - golden_output[i]; |
| if (diff < 0) diff = -diff; |
| ASSERT_LE(diff, kTolerance); |
| } |
| free(out); |
| } |
| |
| TEST(MfccTest, DcInputSaneResult) { |
| MfccParams params = {.num_frames = 10, |
| .num_mel_bins = 64, |
| .audio_samp_rate = 16000, |
| .low_edge_hz = 125, |
| .upper_edge_hz = 7500, |
| .win_len_sec = 0.032, |
| .hop_len_sec = 0.016, |
| .log_floor = 0.01, |
| .log_scaler = 20}; |
| |
| // set parameters |
| set_mfcc_params(¶ms); |
| |
| int hop_len = static_cast<int>(params.audio_samp_rate * params.hop_len_sec); |
| int in_len = hop_len * params.num_frames; |
| int16_t* in = reinterpret_cast<int16_t*>( |
| malloc(params.num_frames * hop_len * sizeof(int16_t))); |
| int out_len = params.num_frames * params.num_mel_bins; |
| uint8_t* out = reinterpret_cast<uint8_t*>(malloc(out_len * sizeof(uint8_t))); |
| |
| // DC Input |
| memset(in, 255, in_len * sizeof(int16_t)); |
| // extract MFCC |
| extract_mfcc(in, out, in_len); |
| // ignore the 1st frame due to pre zero-padding |
| // expect zero outputs |
| for (int i = params.num_mel_bins; i < out_len; i++) { |
| ASSERT_EQ(out[i], 0); |
| } |
| |
| free(in); |
| free(out); |
| } |
| |
| TEST(MfccTest, NyquistFreqInputSaneResult) { |
| MfccParams params = {.num_frames = 15, |
| .num_mel_bins = 32, |
| .audio_samp_rate = 16000, |
| .low_edge_hz = 125, |
| .upper_edge_hz = 7500, |
| .win_len_sec = 0.016, |
| .hop_len_sec = 0.008, |
| .log_floor = 0.01, |
| .log_scaler = 20}; |
| |
| // set parameters |
| set_mfcc_params(¶ms); |
| |
| int hop_len = static_cast<int>(params.audio_samp_rate * params.hop_len_sec); |
| int in_len = hop_len * params.num_frames; |
| int16_t* in = reinterpret_cast<int16_t*>( |
| malloc(params.num_frames * hop_len * sizeof(int16_t))); |
| int out_len = params.num_frames * params.num_mel_bins; |
| uint8_t* out = reinterpret_cast<uint8_t*>(malloc(out_len * sizeof(uint8_t))); |
| |
| // High (Nyquest) frequency Input |
| memset(in, 255, in_len * sizeof(int16_t)); |
| for (int i = 1; i < in_len; i += 2) in[i] *= -1; |
| // extract MFCC |
| extract_mfcc(in, out, in_len); |
| // ignore the 1st frame due to pre zero-padding |
| // expect zero outputs |
| for (int i = params.num_mel_bins; i < out_len; i++) { |
| ASSERT_EQ(out[i], 0); |
| } |
| |
| free(in); |
| free(out); |
| } |