800 lines
30 KiB
C++
800 lines
30 KiB
C++
/**
|
||
* @file test_audio_processing_comprehensive.cpp
|
||
* @brief 音频处理函数综合测试套件
|
||
*
|
||
* 测试覆盖:
|
||
* - 9个音频处理函数确性测试
|
||
* - 标量与SIMD版本的一致性测试
|
||
* - 边界条件和错误处理测试
|
||
* - 性能对比测试
|
||
* - 跨平台兼容性测试
|
||
*/
|
||
|
||
#include <gtest/gtest.h>
|
||
#include <vector>
|
||
#include <cmath>
|
||
#include <random>
|
||
#include <chrono>
|
||
#include <iomanip>
|
||
#include <algorithm>
|
||
#include <numeric>
|
||
#include <functional>
|
||
|
||
// 确保M_PI定义可用
|
||
#ifndef M_PI
|
||
#define M_PI 3.14159265358979323846
|
||
#endif
|
||
|
||
// 音频处理函数头文件
|
||
#include "aligned_allocator.h"
|
||
#include "simd_func_dispatcher.h"
|
||
#include "audio_processing/scalar_audio_processing_func.h"
|
||
#include "audio_processing/simd_audio_processing.h"
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
#include "audio_processing/x86_simd_audio_processing_func.h"
|
||
#endif
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
#include "audio_processing/arm_simd_audio_processing_func.h"
|
||
#endif
|
||
|
||
// 测试容差设置
|
||
constexpr float FLOAT_TOLERANCE = 1e-6f;
|
||
constexpr float RMS_TOLERANCE = 1e-5f;
|
||
constexpr float PEAK_TOLERANCE = 1e-6f;
|
||
|
||
// 性能测试设置
|
||
constexpr size_t PERF_TEST_SIZE = 1024 * 1024; // 1M samples
|
||
constexpr int PERF_TEST_ITERATIONS = 100;
|
||
|
||
using aligned_audio_buffer = std::vector<float, avx512_aligned_allocator<float>>;
|
||
|
||
/**
|
||
* 浮点数比较函数
|
||
*/
|
||
bool float_equal(float a, float b, float tolerance = FLOAT_TOLERANCE) {
|
||
if (std::isnan(a) && std::isnan(b))
|
||
return true;
|
||
if (std::isinf(a) && std::isinf(b))
|
||
return (a > 0) == (b > 0);
|
||
return std::abs(a - b) <= tolerance;
|
||
}
|
||
|
||
/**
|
||
* 数组比较函数
|
||
*/
|
||
bool arrays_equal(const float* arr1, const float* arr2, size_t size, float tolerance = FLOAT_TOLERANCE) {
|
||
for (size_t i = 0; i < size; ++i) {
|
||
if (!float_equal(arr1[i], arr2[i], tolerance)) {
|
||
std::cout << " 差异在位置 " << i << ": " << arr1[i] << " vs " << arr2[i]
|
||
<< " (差值: " << std::abs(arr1[i] - arr2[i]) << ")" << std::endl;
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 测试数据生成器
|
||
*/
|
||
class AudioDataGenerator {
|
||
private:
|
||
mutable std::mt19937 rng_{std::random_device{}()};
|
||
|
||
public:
|
||
// 生成正弦波
|
||
auto generate_sine_wave(size_t num_samples, float frequency = 440.0f,
|
||
float sample_rate = 44100.0f, float amplitude = 1.0f) const {
|
||
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX512>> data(num_samples);
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
data[i] = amplitude * std::sin(2.0f * M_PI * frequency * i / sample_rate);
|
||
}
|
||
return data;
|
||
}
|
||
|
||
// 生成白噪声
|
||
auto generate_white_noise(size_t num_samples, float amplitude = 1.0f) const {
|
||
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX512>> data(num_samples);
|
||
std::uniform_real_distribution<float> dist(-amplitude, amplitude);
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
data[i] = dist(rng_);
|
||
}
|
||
return data;
|
||
}
|
||
|
||
// 生成脉冲信号
|
||
auto generate_impulse(size_t num_samples, size_t impulse_pos = 0, float amplitude = 1.0f) const {
|
||
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX512>> data(num_samples, 0.0f);
|
||
if (impulse_pos < num_samples) {
|
||
data[impulse_pos] = amplitude;
|
||
}
|
||
return data;
|
||
}
|
||
|
||
// 生成直流信号
|
||
aligned_audio_buffer generate_dc(size_t num_samples, float value = 1.0f) const {
|
||
return aligned_audio_buffer(num_samples, value);
|
||
}
|
||
|
||
// 生成立体声测试数据
|
||
aligned_audio_buffer generate_stereo_test_data(size_t num_stereo_samples) const {
|
||
aligned_audio_buffer data(num_stereo_samples * 2);
|
||
for (size_t i = 0; i < num_stereo_samples; ++i) {
|
||
data[i * 2] = std::sin(2.0f * M_PI * 440.0f * i / 44100.0f); // 左声道: 440Hz
|
||
data[i * 2 + 1] = std::sin(2.0f * M_PI * 880.0f * i / 44100.0f); // 右声道: 880Hz
|
||
}
|
||
return data;
|
||
}
|
||
|
||
// 生成边界测试数据
|
||
aligned_audio_buffer generate_boundary_data(size_t num_samples) const {
|
||
aligned_audio_buffer data;
|
||
data.reserve(num_samples);
|
||
|
||
// 添加各种边界值
|
||
if (num_samples > 0)
|
||
data.push_back(0.0f);
|
||
if (num_samples > 1)
|
||
data.push_back(1.0f);
|
||
if (num_samples > 2)
|
||
data.push_back(-1.0f);
|
||
if (num_samples > 3)
|
||
data.push_back(std::numeric_limits<float>::min());
|
||
if (num_samples > 4)
|
||
data.push_back(std::numeric_limits<float>::max());
|
||
if (num_samples > 5)
|
||
data.push_back(std::numeric_limits<float>::epsilon());
|
||
if (num_samples > 6)
|
||
data.push_back(-std::numeric_limits<float>::epsilon());
|
||
|
||
// 填充剩余位置
|
||
std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
|
||
while (data.size() < num_samples) {
|
||
data.push_back(dist(rng_));
|
||
}
|
||
|
||
return data;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 性能测试辅助类
|
||
*/
|
||
class PerformanceTester {
|
||
public:
|
||
template <typename Func>
|
||
double measure_execution_time(Func&& func, int iterations = PERF_TEST_ITERATIONS) {
|
||
auto start = std::chrono::high_resolution_clock::now();
|
||
|
||
for (int i = 0; i < iterations; ++i) {
|
||
func();
|
||
}
|
||
|
||
auto end = std::chrono::high_resolution_clock::now();
|
||
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
|
||
|
||
return duration.count() / 1e6 / iterations; // 返回平均毫秒数
|
||
}
|
||
|
||
void print_performance_comparison(const std::string& test_name,
|
||
double scalar_time,
|
||
double simd_time) {
|
||
double speedup = scalar_time / simd_time;
|
||
std::cout << "[PERF] " << test_name << std::endl;
|
||
std::cout << " 标量版本: " << std::fixed << std::setprecision(3) << scalar_time << "ms" << std::endl;
|
||
std::cout << " SIMD版本: " << std::fixed << std::setprecision(3) << simd_time << "ms" << std::endl;
|
||
std::cout << " 加速比: " << std::fixed << std::setprecision(2) << speedup << "x" << std::endl;
|
||
}
|
||
};
|
||
|
||
// 音频处理函数测试类
|
||
class AudioProcessingTest : public ::testing::Test {
|
||
protected:
|
||
void SetUp() override {
|
||
// 初始化测试环境
|
||
audio_processing_registry::register_all_functions();
|
||
}
|
||
|
||
void TearDown() override {
|
||
// 清理测试环境
|
||
}
|
||
|
||
// 全局实例
|
||
AudioDataGenerator data_gen;
|
||
PerformanceTester perf_tester;
|
||
};
|
||
|
||
/**
|
||
* ========================================
|
||
* 基础功能测试
|
||
* ========================================
|
||
*/
|
||
|
||
// 测试 simd_audio_processing_registry 注册功能
|
||
TEST_F(AudioProcessingTest, RegistryRegistration) {
|
||
// 打印已注册的函数以供调试
|
||
audio_processing_registry::print_available_functions();
|
||
|
||
// 验证关键函数已注册
|
||
auto& dispatcher = simd_func_dispatcher::instance();
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<void(const float*, const float*, float*, size_t)>("mix_audio");
|
||
}) << "函数 mix_audio 未正确注册";
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<void(const float*, float*, float, size_t)>("apply_gain");
|
||
}) << "函数 apply_gain 未正确注册";
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<float(const float*, size_t)>("calculate_rms");
|
||
}) << "函数 calculate_rms 未正确注册";
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<float(const float*, size_t)>("calculate_peak");
|
||
}) << "函数 calculate_peak 未正确注册";
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<void(const float*, float*, float, size_t)>("normalize_audio");
|
||
}) << "函数 normalize_audio 未正确注册";
|
||
|
||
EXPECT_NO_THROW({
|
||
dispatcher.get_function<void(const float*, float*, size_t)>("stereo_to_mono");
|
||
}) << "函数 stereo_to_mono 未正确注册";
|
||
}
|
||
|
||
// 测试 mix_audio 函数
|
||
TEST_F(AudioProcessingTest, MixAudioBasic) {
|
||
const size_t num_samples = 16;
|
||
auto src1 = data_gen.generate_sine_wave(num_samples, 440.0f);
|
||
auto src2 = data_gen.generate_sine_wave(num_samples, 880.0f);
|
||
aligned_audio_buffer result(num_samples);
|
||
aligned_audio_buffer expected(num_samples);
|
||
|
||
// 计算期望结果
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
expected[i] = src1[i] + src2[i];
|
||
}
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::mix_audio(src1.data(), src2.data(), result.data(), num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(result.data(), expected.data(), num_samples))
|
||
<< "混合音频结果与期望不符";
|
||
}
|
||
|
||
// 测试 apply_gain 函数
|
||
TEST_F(AudioProcessingTest, ApplyGainBasic) {
|
||
const size_t num_samples = 16;
|
||
const float gain = 0.5f;
|
||
auto src = data_gen.generate_sine_wave(num_samples);
|
||
std::vector<float, avx512_aligned_allocator<float>> result(num_samples);
|
||
std::vector<float, avx512_aligned_allocator<float>> expected(num_samples);
|
||
|
||
// 计算期望结果
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
expected[i] = src[i] * gain;
|
||
}
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::apply_gain(src.data(), result.data(), gain, num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(result.data(), expected.data(), num_samples))
|
||
<< "增益应用结果与期望不符";
|
||
}
|
||
|
||
// 测试 calculate_rms 函数
|
||
TEST_F(AudioProcessingTest, CalculateRmsBasic) {
|
||
const size_t num_samples = 1024;
|
||
auto src = data_gen.generate_sine_wave(num_samples);
|
||
|
||
// 计算期望的RMS值
|
||
double sum_squares = 0.0;
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
sum_squares += src[i] * src[i];
|
||
}
|
||
float expected_rms = std::sqrt(sum_squares / num_samples);
|
||
|
||
// 测试标量版本
|
||
float result_rms = scalar_audio_processing_func::calculate_rms(src.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(result_rms, expected_rms, RMS_TOLERANCE))
|
||
<< "期望 RMS: " << expected_rms << ", 得到: " << result_rms;
|
||
}
|
||
|
||
// 测试 calculate_peak 函数
|
||
TEST_F(AudioProcessingTest, CalculatePeakBasic) {
|
||
const size_t num_samples = 1024;
|
||
auto src = data_gen.generate_boundary_data(num_samples);
|
||
|
||
// 计算期望的峰值
|
||
float expected_peak = 0.0f;
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
expected_peak = std::max(expected_peak, std::abs(src[i]));
|
||
}
|
||
|
||
// 测试标量版本
|
||
float result_peak = scalar_audio_processing_func::calculate_peak(src.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(result_peak, expected_peak, PEAK_TOLERANCE))
|
||
<< "期望峰值: " << expected_peak << ", 得到: " << result_peak;
|
||
}
|
||
|
||
/**
|
||
* ========================================
|
||
* 新增功能测试
|
||
* ========================================
|
||
*/
|
||
|
||
// 测试 normalize_audio 函数
|
||
TEST_F(AudioProcessingTest, NormalizeAudioBasic) {
|
||
const size_t num_samples = 1024;
|
||
const float target_peak = 0.8f;
|
||
auto src = data_gen.generate_sine_wave(num_samples, 440.0f, 44100.0f, 2.0f); // 超过1.0的幅度
|
||
aligned_audio_buffer result(num_samples);
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::normalize_audio(src.data(), result.data(), target_peak, num_samples);
|
||
|
||
// 验证归一化后的峰值
|
||
float actual_peak = scalar_audio_processing_func::calculate_peak(result.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(actual_peak, target_peak, PEAK_TOLERANCE))
|
||
<< "期望峰值: " << target_peak << ", 实际峰值: " << actual_peak;
|
||
}
|
||
|
||
// 测试 stereo_to_mono 函数
|
||
TEST_F(AudioProcessingTest, StereoToMonoBasic) {
|
||
const size_t num_stereo_samples = 512;
|
||
auto stereo_src = data_gen.generate_stereo_test_data(num_stereo_samples);
|
||
aligned_audio_buffer mono_result(num_stereo_samples);
|
||
aligned_audio_buffer expected_mono(num_stereo_samples);
|
||
|
||
// 计算期望结果
|
||
for (size_t i = 0; i < num_stereo_samples; ++i) {
|
||
expected_mono[i] = (stereo_src[i * 2] + stereo_src[i * 2 + 1]) * 0.5f;
|
||
}
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::stereo_to_mono(stereo_src.data(), mono_result.data(), num_stereo_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(mono_result.data(), expected_mono.data(), num_stereo_samples))
|
||
<< "立体声转单声道果与期望不符";
|
||
}
|
||
|
||
// 测试 limit_audio 函数
|
||
TEST_F(AudioProcessingTest, LimitAudioBasic) {
|
||
const size_t num_samples = 1024;
|
||
const float threshold = 0.5f;
|
||
auto src = data_gen.generate_sine_wave(num_samples, 440.0f, 44100.0f, 1.0f);
|
||
aligned_audio_buffer result(num_samples);
|
||
float limiter_state = 1.0f;
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::limit_audio(src.data(), result.data(), threshold, &limiter_state, 44100.f,
|
||
num_samples);
|
||
|
||
// 验证没有样本超过阈值
|
||
bool all_samples_limited = true;
|
||
size_t violation_index = 0;
|
||
float violation_value = 0.0f;
|
||
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
if (std::abs(result[i]) > threshold + FLOAT_TOLERANCE) {
|
||
all_samples_limited = false;
|
||
violation_index = i;
|
||
violation_value = result[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
EXPECT_TRUE(all_samples_limited)
|
||
<< "样本 " << violation_index << " 超过阈值: " << violation_value;
|
||
}
|
||
|
||
// 测试 fade_audio 函数
|
||
TEST_F(AudioProcessingTest, FadeAudioBasic) {
|
||
const size_t num_samples = 1024;
|
||
const size_t fade_in_samples = 100;
|
||
const size_t fade_out_samples = 100;
|
||
auto src = data_gen.generate_dc(num_samples, 1.0f);
|
||
aligned_audio_buffer result(num_samples);
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::fade_audio(src.data(), result.data(), fade_in_samples, fade_out_samples, num_samples);
|
||
|
||
// 验证淡入淡出效果
|
||
|
||
// 检查淡入部分
|
||
EXPECT_FLOAT_EQ(result[0], 0.0f)
|
||
<< "淡入开始应为0,实际为: " << result[0];
|
||
|
||
// 检查中间部分(应该是1.0)
|
||
EXPECT_FLOAT_EQ(result[num_samples / 2], 1.0f)
|
||
<< "中间部分应保持原始值1.0,实际为: " << result[num_samples / 2];
|
||
|
||
// 检查淡出部分
|
||
EXPECT_TRUE(float_equal(result[num_samples - 1], 0.0f, FLOAT_TOLERANCE))
|
||
<< "淡出结束应为0,实际为: " << result[num_samples - 1];
|
||
}
|
||
|
||
// 测试 simple_eq 函数
|
||
TEST_F(AudioProcessingTest, SimpleEqBasic) {
|
||
const size_t num_samples = 1024;
|
||
const float low_gain = 1.2f;
|
||
const float mid_gain = 1.0f;
|
||
const float high_gain = 0.8f;
|
||
auto src = data_gen.generate_white_noise(num_samples, 0.5f);
|
||
aligned_audio_buffer result(num_samples);
|
||
aligned_audio_buffer eq_state(2, 0.0f); // 低通和高通滤波器状态
|
||
|
||
// 测试标量版本
|
||
scalar_audio_processing_func::simple_eq(src.data(), result.data(), low_gain, mid_gain, high_gain, eq_state.data(),
|
||
num_samples);
|
||
|
||
// 基本验证:结果不应该全为零(除非输入全为零)
|
||
bool has_nonzero = false;
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
if (result[i] != 0.0f) {
|
||
has_nonzero = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
EXPECT_TRUE(has_nonzero)
|
||
<< "EQ处理后的结果全为零,可能存在处理错误";
|
||
}
|
||
|
||
/**
|
||
* ========================================
|
||
* 边界条件测试
|
||
* ========================================
|
||
*/
|
||
|
||
// 测试零长度输入
|
||
TEST_F(AudioProcessingTest, ZeroLengthInput) {
|
||
const size_t num_samples = 0;
|
||
aligned_audio_buffer dummy(1, 0.0f);
|
||
aligned_audio_buffer result(1, 0.0f);
|
||
float state = 1.0f;
|
||
|
||
// 这些函数应该能安全处理零长度输入
|
||
EXPECT_NO_THROW({
|
||
scalar_audio_processing_func::mix_audio(dummy.data(), dummy.data(), result.data(), num_samples);
|
||
scalar_audio_processing_func::apply_gain(dummy.data(), result.data(), 1.0f, num_samples);
|
||
scalar_audio_processing_func::normalize_audio(dummy.data(), result.data(), 1.0f, num_samples);
|
||
scalar_audio_processing_func::stereo_to_mono(dummy.data(), result.data(), num_samples);
|
||
scalar_audio_processing_func::limit_audio(dummy.data(), result.data(), 1.0f, &state, 44100.f, num_samples);
|
||
scalar_audio_processing_func::fade_audio(dummy.data(), result.data(), 0, 0, num_samples);
|
||
scalar_audio_processing_func::simple_eq(dummy.data(), result.data(), 1.0f, 1.0f, 1.0f, &state, num_samples);
|
||
});
|
||
}
|
||
|
||
// 测试单样本输入
|
||
TEST_F(AudioProcessingTest, SingleSampleInput) {
|
||
const size_t num_samples = 1;
|
||
aligned_audio_buffer src1{0.5f};
|
||
aligned_audio_buffer src2{0.3f};
|
||
aligned_audio_buffer result(1);
|
||
float state = 1.0f;
|
||
|
||
// 测试混合
|
||
scalar_audio_processing_func::mix_audio(src1.data(), src2.data(), result.data(), num_samples);
|
||
EXPECT_TRUE(float_equal(result[0], 0.8f))
|
||
<< "混合单样本: 期望0.8,实际" << result[0];
|
||
|
||
// 测试增益
|
||
scalar_audio_processing_func::apply_gain(src1.data(), result.data(), 2.0f, num_samples);
|
||
EXPECT_TRUE(float_equal(result[0], 1.0f))
|
||
<< "应用增益: 期望1.0,实际" << result[0];
|
||
|
||
// 测试RMS
|
||
float rms = scalar_audio_processing_func::calculate_rms(src1.data(), num_samples);
|
||
EXPECT_TRUE(float_equal(rms, 0.5f))
|
||
<< "单样本RMS: 期望0.5,实际" << rms;
|
||
|
||
// 测试峰值
|
||
float peak = scalar_audio_processing_func::calculate_peak(src1.data(), num_samples);
|
||
EXPECT_TRUE(float_equal(peak, 0.5f))
|
||
<< "单样本峰值: 期望0.5,实际" << peak;
|
||
}
|
||
|
||
// 测试极值处理
|
||
TEST_F(AudioProcessingTest, ExtremeValues) {
|
||
const size_t num_samples = 8;
|
||
aligned_audio_buffer extreme_values = {
|
||
0.0f,
|
||
1.0f,
|
||
-1.0f,
|
||
std::numeric_limits<float>::max(),
|
||
-std::numeric_limits<float>::max(),
|
||
std::numeric_limits<float>::min(),
|
||
std::numeric_limits<float>::epsilon(),
|
||
-std::numeric_limits<float>::epsilon()
|
||
};
|
||
|
||
aligned_audio_buffer result(num_samples);
|
||
|
||
// 测试峰值计算对极值的处理
|
||
float peak = scalar_audio_processing_func::calculate_peak(extreme_values.data(), num_samples);
|
||
EXPECT_EQ(peak, std::numeric_limits<float>::max())
|
||
<< "极值峰值检测失败,期望" << std::numeric_limits<float>::max() << ",实际" << peak;
|
||
|
||
// 测试增益对极值的处理
|
||
scalar_audio_processing_func::apply_gain(extreme_values.data(), result.data(), 0.5f, num_samples);
|
||
bool all_finite = true;
|
||
size_t nan_inf_index = 0;
|
||
|
||
for (size_t i = 0; i < num_samples; ++i) {
|
||
if (std::isnan(result[i]) || std::isinf(result[i])) {
|
||
all_finite = false;
|
||
nan_inf_index = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
EXPECT_TRUE(all_finite)
|
||
<< "增益处理后在位置" << nan_inf_index << "存在NaN或Inf";
|
||
}
|
||
|
||
/**
|
||
* ========================================
|
||
* 一致性测试(标量 vs SIMD)
|
||
* ========================================
|
||
*/
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
|
||
// 测试x86 SIMD版本与标量版的一致性
|
||
TEST_F(AudioProcessingTest, X86SimdConsistency) {
|
||
const size_t num_samples = 1024;
|
||
auto src1 = data_gen.generate_sine_wave(num_samples, 440.0f);
|
||
auto src2 = data_gen.generate_sine_wave(num_samples, 880.0f);
|
||
auto stereo_src = data_gen.generate_stereo_test_data(num_samples);
|
||
|
||
aligned_audio_buffer scalar_result(num_samples);
|
||
aligned_audio_buffer sse_result(num_samples);
|
||
aligned_audio_buffer avx_result(num_samples);
|
||
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX512>> avx512_result(num_samples);
|
||
|
||
// 测试 mix_audio 一致性
|
||
scalar_audio_processing_func::mix_audio(src1.data(), src2.data(), scalar_result.data(), num_samples);
|
||
x86_simd_audio_processing_func::mix_audio_sse(src1.data(), src2.data(), sse_result.data(), num_samples);
|
||
x86_simd_audio_processing_func::mix_audio_avx(src1.data(), src2.data(), avx_result.data(), num_samples);
|
||
x86_simd_audio_processing_func::mix_audio_avx512(src1.data(), src2.data(), avx512_result.data(), num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), sse_result.data(), num_samples))
|
||
<< "mix_audio SSE版本与标量版本不一致";
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), avx_result.data(), num_samples))
|
||
<< "mix_audio AVX版本与标量版本不一致";
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), avx512_result.data(), num_samples))
|
||
<< "mix_audio AVX512版本与标量版本不一致";
|
||
|
||
// 测试 apply_gain 一致性
|
||
const float gain = 0.75f;
|
||
scalar_audio_processing_func::apply_gain(src1.data(), scalar_result.data(), gain, num_samples);
|
||
x86_simd_audio_processing_func::apply_gain_sse(src1.data(), sse_result.data(), gain, num_samples);
|
||
x86_simd_audio_processing_func::apply_gain_avx(src1.data(), avx_result.data(), gain, num_samples);
|
||
x86_simd_audio_processing_func::apply_gain_avx512(src1.data(), avx512_result.data(), gain, num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), sse_result.data(), num_samples))
|
||
<< "apply_gain SSE版本与标量版本不一致";
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), avx_result.data(), num_samples))
|
||
<< "apply_gain AVX版本与标量版本不一致";
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), avx512_result.data(), num_samples))
|
||
<< "apply_gain AVX512版本与标量版本不一致";
|
||
|
||
// 测试 calculate_rms 一致性
|
||
float scalar_rms = scalar_audio_processing_func::calculate_rms(src1.data(), num_samples);
|
||
float sse_rms = x86_simd_audio_processing_func::calculate_rms_sse(src1.data(), num_samples);
|
||
float avx_rms = x86_simd_audio_processing_func::calculate_rms_avx(src1.data(), num_samples);
|
||
float avx512_rms = x86_simd_audio_processing_func::calculate_rms_avx512(src1.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(scalar_rms, sse_rms, RMS_TOLERANCE))
|
||
<< "calculate_rms SSE版本与标量版本不一致: " << scalar_rms << " vs " << sse_rms;
|
||
EXPECT_TRUE(float_equal(scalar_rms, avx_rms, RMS_TOLERANCE))
|
||
<< "calculate_rms AVX版本与标量版本不一致: " << scalar_rms << " vs " << avx_rms;
|
||
EXPECT_TRUE(float_equal(scalar_rms, avx512_rms, RMS_TOLERANCE))
|
||
<< "calculate_rms AVX512版本与标量版本不一致: " << scalar_rms << " vs " << avx512_rms;
|
||
|
||
// 测试 calculate_peak 一致性
|
||
float scalar_peak = scalar_audio_processing_func::calculate_peak(src1.data(), num_samples);
|
||
float sse_peak = x86_simd_audio_processing_func::calculate_peak_sse(src1.data(), num_samples);
|
||
float avx_peak = x86_simd_audio_processing_func::calculate_peak_avx(src1.data(), num_samples);
|
||
float avx512_peak = x86_simd_audio_processing_func::calculate_peak_avx512(src1.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(scalar_peak, sse_peak, PEAK_TOLERANCE))
|
||
<< "calculate_peak SSE版本与标量版本不一致: " << scalar_peak << " vs " << sse_peak;
|
||
EXPECT_TRUE(float_equal(scalar_peak, avx_peak, PEAK_TOLERANCE))
|
||
<< "calculate_peak AVX版本与标量版本不一致: " << scalar_peak << " vs " << avx_peak;
|
||
EXPECT_TRUE(float_equal(scalar_peak, avx512_peak, PEAK_TOLERANCE))
|
||
<< "calculate_peak AVX512版本与标量版本不一致: " << scalar_peak << " vs " << avx512_peak;
|
||
}
|
||
|
||
#endif // ALICHO_PLATFORM_X86
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
|
||
// 测试ARM NEON版本与标量版的一致性
|
||
TEST_F(AudioProcessingTest, ArmSimdConsistency) {
|
||
const size_t num_samples = 1024;
|
||
auto src1 = data_gen.generate_sine_wave(num_samples, 440.0f);
|
||
auto src2 = data_gen.generate_sine_wave(num_samples, 880.0f);
|
||
|
||
aligned_audio_buffer scalar_result(num_samples);
|
||
aligned_audio_buffer neon_result(num_samples);
|
||
|
||
// 测试 mix_audio 一致性
|
||
scalar_audio_processing_func::mix_audio(src1.data(), src2.data(), scalar_result.data(), num_samples);
|
||
arm_simd_audio_processing_func::mix_audio_neon(src1.data(), src2.data(), neon_result.data(), num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), neon_result.data(), num_samples))
|
||
<< "mix_audio NEON版本与标量版不一致";
|
||
|
||
// 测试 apply_gain 一致性
|
||
const float gain = 0.75f;
|
||
scalar_audio_processing_func::apply_gain(src1.data(), scalar_result.data(), gain, num_samples);
|
||
arm_simd_audio_processing_func::apply_gain_neon(src1.data(), neon_result.data(), gain, num_samples);
|
||
|
||
EXPECT_TRUE(arrays_equal(scalar_result.data(), neon_result.data(), num_samples))
|
||
<< "apply_gain NEON版本与标量版不一致";
|
||
|
||
// 测试 calculate_rms 一致性
|
||
float scalar_rms = scalar_audio_processing_func::calculate_rms(src1.data(), num_samples);
|
||
float neon_rms = arm_simd_audio_processing_func::calculate_rms_neon(src1.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(scalar_rms, neon_rms, RMS_TOLERANCE))
|
||
<< "calculate_rms NEON版本与标量版不一致: " << scalar_rms << " vs " << neon_rms;
|
||
|
||
// 测试 calculate_peak 一致性
|
||
float scalar_peak = scalar_audio_processing_func::calculate_peak(src1.data(), num_samples);
|
||
float neon_peak = arm_simd_audio_processing_func::calculate_peak_neon(src1.data(), num_samples);
|
||
|
||
EXPECT_TRUE(float_equal(scalar_peak, neon_peak, PEAK_TOLERANCE))
|
||
<< "calculate_peak NEON版本与标量版不一致: " << scalar_peak << " vs " << neon_peak;
|
||
}
|
||
|
||
#endif // ALICHO_PLATFORM_ARM
|
||
|
||
/**
|
||
* ========================================
|
||
* 性能测试
|
||
* ========================================
|
||
*/
|
||
|
||
// 性能测试运行为 TEST_F 测试,但不使用 EXPECT/ASSERT
|
||
TEST_F(AudioProcessingTest, PerformanceTests) {
|
||
std::cout << "\n=== 性能测试 ===" << std::endl;
|
||
|
||
// 生成大量测试数据
|
||
auto src1 = data_gen.generate_sine_wave(PERF_TEST_SIZE, 440.0f);
|
||
auto src2 = data_gen.generate_sine_wave(PERF_TEST_SIZE, 880.0f);
|
||
aligned_audio_buffer result(PERF_TEST_SIZE);
|
||
|
||
// 性能测试:mix_audio
|
||
{
|
||
double scalar_time = perf_tester.measure_execution_time([&]() {
|
||
scalar_audio_processing_func::mix_audio(src1.data(), src2.data(), result.data(), PERF_TEST_SIZE);
|
||
});
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
double sse_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::mix_audio_sse(src1.data(), src2.data(), result.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("mix_audio (SSE vs Scalar)", scalar_time, sse_time);
|
||
|
||
double avx_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::mix_audio_avx(src1.data(), src2.data(), result.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("mix_audio (AVX vs Scalar)", scalar_time, avx_time);
|
||
|
||
double avx512_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::mix_audio_avx512(src1.data(), src2.data(), result.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("mix_audio (AVX512 vs Scalar)", scalar_time, avx512_time);
|
||
#endif
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
double neon_time = perf_tester.measure_execution_time([&]() {
|
||
arm_simd_audio_processing_func::mix_audio_neon(src1.data(), src2.data(), result.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("mix_audio (NEON vs Scalar)", scalar_time, neon_time);
|
||
#endif
|
||
}
|
||
|
||
// 性能测试:apply_gain
|
||
{
|
||
const float gain = 0.5f;
|
||
double scalar_time = perf_tester.measure_execution_time([&]() {
|
||
scalar_audio_processing_func::apply_gain(src1.data(), result.data(), gain, PERF_TEST_SIZE);
|
||
});
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
double sse_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::apply_gain_sse(src1.data(), result.data(), gain, PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("apply_gain (SSE vs Scalar)", scalar_time, sse_time);
|
||
|
||
double avx_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::apply_gain_avx(src1.data(), result.data(), gain, PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("apply_gain (AVX vs Scalar)", scalar_time, avx_time);
|
||
|
||
double avx512_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::apply_gain_avx512(src1.data(), result.data(), gain, PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("apply_gain (AVX512 vs Scalar)", scalar_time, avx512_time);
|
||
#endif
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
double neon_time = perf_tester.measure_execution_time([&]() {
|
||
arm_simd_audio_processing_func::apply_gain_neon(src1.data(), result.data(), gain, PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("apply_gain (NEON vs Scalar)", scalar_time, neon_time);
|
||
#endif
|
||
}
|
||
|
||
// 性能测试:calculate_rms
|
||
{
|
||
double scalar_time = perf_tester.measure_execution_time([&]() {
|
||
scalar_audio_processing_func::calculate_rms(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
double sse_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_rms_sse(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_rms (SSE vs Scalar)", scalar_time, sse_time);
|
||
|
||
double avx_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_rms_avx(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_rms (AVX vs Scalar)", scalar_time, avx_time);
|
||
|
||
double avx512_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_rms_avx512(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_rms (AVX512 vs Scalar)", scalar_time, avx512_time);
|
||
#endif
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
double neon_time = perf_tester.measure_execution_time([&]() {
|
||
arm_simd_audio_processing_func::calculate_rms_neon(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_rms (NEON vs Scalar)", scalar_time, neon_time);
|
||
#endif
|
||
}
|
||
|
||
// 性能测试:calculate_peak
|
||
{
|
||
double scalar_time = perf_tester.measure_execution_time([&]() {
|
||
scalar_audio_processing_func::calculate_peak(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
|
||
#if ALICHO_PLATFORM_X86
|
||
double sse_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_peak_sse(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_peak (SSE vs Scalar)", scalar_time, sse_time);
|
||
|
||
double avx_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_peak_avx(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_peak (AVX vs Scalar)", scalar_time, avx_time);
|
||
|
||
double avx512_time = perf_tester.measure_execution_time([&]() {
|
||
x86_simd_audio_processing_func::calculate_peak_avx512(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_peak (AVX512 vs Scalar)", scalar_time, avx512_time);
|
||
#endif
|
||
|
||
#if ALICHO_PLATFORM_ARM
|
||
double neon_time = perf_tester.measure_execution_time([&]() {
|
||
arm_simd_audio_processing_func::calculate_peak_neon(src1.data(), PERF_TEST_SIZE);
|
||
});
|
||
perf_tester.print_performance_comparison("calculate_peak (NEON vs Scalar)", scalar_time, neon_time);
|
||
#endif
|
||
}
|
||
}
|