Files
Alicho/tests/simd/test_simd_audio_processing.cpp
nanako 886b6843e6 Add SIMD audio processing interface and implementations
- Created a new SIMD interface header and source files for audio processing functions.
- Implemented functions for filling buffers, mixing audio, applying gain, calculating RMS and peak values, normalizing audio, converting stereo to mono, limiting audio, fading audio, and a simple equalizer.
- Added SSE-specific implementations for the audio processing functions to leverage SIMD for performance improvements.
- Updated CMakeLists.txt files to include new libraries and link dependencies for the SIMD interface and SSE implementations.
- Introduced a static test helper library for unit testing with Google Test framework.
2025-11-14 23:27:55 +08:00

728 lines
24 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <gtest/gtest.h>
#include <vector>
#include <cmath>
#include <limits>
#include <algorithm>
#include <numeric>
#include <chrono>
#include <iostream>
// 修正include路径
#include "simd_api.h"
#include "aligned_allocator.h"
#include "performance_timer.h"
using namespace shm_test;
namespace {
// ============================================================================
// 测试数据生成辅助函数
// ============================================================================
/**
* @brief 生成正弦波测试数据
* @param frequency 频率0-1相对于采样率
* @param num_samples 样本数量
* @return 正弦波数据向量
*/
template<typename Allocator = std::allocator<float>>
std::vector<float, Allocator> generate_sine_wave(float frequency, size_t num_samples) {
std::vector<float, Allocator> data(num_samples);
for (size_t i = 0; i < num_samples; ++i) {
data[i] = std::sin(2.0f * 3.14159265f * frequency * i);
}
return data;
}
/**
* @brief 生成常数值测试数据
* @param value 常数值
* @param num_samples 样本数量
* @return 常数值数据向量
*/
template<typename Allocator = std::allocator<float>>
std::vector<float, Allocator> generate_constant_data(float value, size_t num_samples) {
return std::vector<float, Allocator>(num_samples, value);
}
/**
* @brief 检查两个浮点数是否接近
* @param a 第一个值
* @param b 第二个值
* @param tolerance 容差
* @return 是否接近
*/
bool float_near(float a, float b, float tolerance = 1e-5f) {
if (std::isnan(a) || std::isnan(b)) return false;
if (std::isinf(a) || std::isinf(b)) return a == b;
return std::abs(a - b) < tolerance;
}
/**
* @brief 检查两个缓冲区是否相等(允许浮点误差)
* @param expected 期望值
* @param actual 实际值
* @param tolerance 容差
* @return 是否相等
*/
template<typename Allocator1, typename Allocator2>
bool buffers_equal(const std::vector<float, Allocator1>& expected,
const std::vector<float, Allocator2>& actual,
float tolerance = 1e-5f) {
if (expected.size() != actual.size()) {
return false;
}
for (size_t i = 0; i < expected.size(); ++i) {
if (!float_near(expected[i], actual[i], tolerance)) {
return false;
}
}
return true;
}
// ============================================================================
// 功能单元测试 - 参数化测试
// ============================================================================
/**
* @brief 测试参数结构体
*/
struct AudioProcessingTestParams {
size_t buffer_size; // 缓冲区大小
int num_channels; // 通道数
float gain_value; // 增益值
};
/**
* @brief 填充缓冲区功能测试类
*/
class FillBufferTest : public ::testing::TestWithParam<AudioProcessingTestParams> {
protected:
void SetUp() override {
params = GetParam();
}
AudioProcessingTestParams params;
};
TEST_P(FillBufferTest, FillsBufferWithValue) {
const float fill_value = 3.14f;
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> buffer(total_samples);
simd::fill_buffer(buffer.data(), fill_value, total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(buffer[i], fill_value)
<< "值不匹配于索引 " << i;
}
}
TEST_P(FillBufferTest, FillWithZero) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> buffer(total_samples);
simd::fill_buffer(buffer.data(), 0.0f, total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_EQ(buffer[i], 0.0f);
}
}
TEST_P(FillBufferTest, FillWithNegativeValue) {
const float fill_value = -2.5f;
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> buffer(total_samples);
simd::fill_buffer(buffer.data(), fill_value, total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(buffer[i], fill_value);
}
}
INSTANTIATE_TEST_SUITE_P(
FillBufferParametrized,
FillBufferTest,
::testing::Values(
AudioProcessingTestParams{64, 1, 1.0f},
AudioProcessingTestParams{256, 2, 1.0f},
AudioProcessingTestParams{1024, 4, 1.0f},
AudioProcessingTestParams{4096, 8, 1.0f},
AudioProcessingTestParams{8192, 1, 1.0f}
)
);
/**
* @brief 应用增益功能测试类
*/
class ApplyGainTest : public ::testing::TestWithParam<AudioProcessingTestParams> {
protected:
void SetUp() override {
params = GetParam();
}
AudioProcessingTestParams params;
};
TEST_P(ApplyGainTest, AppliesGainCorrectly) {
size_t total_samples = params.buffer_size * params.num_channels;
const float gain = params.gain_value;
std::vector<float, avx512_aligned_allocator> src(total_samples, 2.0f);
std::vector<float, avx512_aligned_allocator> dst(total_samples, 0.0f);
simd::apply_gain(src.data(), dst.data(), gain, total_samples);
const float expected_value = 2.0f * gain;
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(dst[i], expected_value)
<< "增益应用错误于索引 " << i;
}
}
TEST_P(ApplyGainTest, GainZeroMakesOutputZero) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> src(total_samples, 5.0f);
std::vector<float, avx512_aligned_allocator> dst(total_samples, 1.0f);
simd::apply_gain(src.data(), dst.data(), 0.0f, total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(dst[i], 0.0f);
}
}
TEST_P(ApplyGainTest, GainOnePreservesValues) {
size_t total_samples = params.buffer_size * params.num_channels;
auto raw_src = generate_sine_wave(0.1f, total_samples);
std::vector<float, avx512_aligned_allocator> src(raw_src.begin(), raw_src.end());
std::vector<float, avx512_aligned_allocator> dst(total_samples, 0.0f);
simd::apply_gain(src.data(), dst.data(), 1.0f, total_samples);
// 验证增益为1.0时,源数据应该保持不变
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(src[i], raw_src[i]);
}
}
TEST_P(ApplyGainTest, NegativeGainInvertsSignal) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> src(total_samples, 3.0f);
std::vector<float, avx512_aligned_allocator> dst(total_samples, 0.0f);
simd::apply_gain(src.data(), dst.data(), -1.0f, total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(dst[i], -3.0f);
}
}
INSTANTIATE_TEST_SUITE_P(
ApplyGainParametrized,
ApplyGainTest,
::testing::Values(
AudioProcessingTestParams{64, 1, 0.0f},
AudioProcessingTestParams{256, 2, 0.5f},
AudioProcessingTestParams{1024, 4, 1.0f},
AudioProcessingTestParams{4096, 8, 2.0f},
AudioProcessingTestParams{8192, 1, 0.1f}
)
);
/**
* @brief 混音功能测试类
*/
class MixAudioTest : public ::testing::TestWithParam<AudioProcessingTestParams> {
protected:
void SetUp() override {
params = GetParam();
}
AudioProcessingTestParams params;
};
TEST_P(MixAudioTest, MixesAudioCorrectly) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> src1(total_samples, 1.0f);
std::vector<float, avx512_aligned_allocator> src2(total_samples, 2.0f);
std::vector<float, avx512_aligned_allocator> dst(total_samples, 0.0f);
simd::mix_audio(src1.data(), src2.data(), dst.data(), total_samples);
for (size_t i = 0; i < total_samples; ++i) {
EXPECT_FLOAT_EQ(dst[i], 3.0f)
<< "混音结果错误于索引 " << i;
}
}
TEST_P(MixAudioTest, MixWithZero) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> src1 = generate_sine_wave<avx512_aligned_allocator>(0.1f, total_samples);
std::vector<float, avx512_aligned_allocator> src2(total_samples, 0.0f);
std::vector<float, avx512_aligned_allocator> dst(total_samples, 0.0f);
simd::mix_audio(src1.data(), src2.data(), dst.data(), total_samples);
EXPECT_TRUE(buffers_equal(src1, dst, 1e-5f));
}
TEST_P(MixAudioTest, MixSymmetry) {
size_t total_samples = params.buffer_size * params.num_channels;
std::vector<float, avx512_aligned_allocator> src1 = generate_sine_wave<avx512_aligned_allocator>(0.1f, total_samples);
std::vector<float, avx512_aligned_allocator> src2 = generate_sine_wave<avx512_aligned_allocator>(0.05f, total_samples);
std::vector<float, avx512_aligned_allocator> dst1(total_samples, 0.0f);
std::vector<float, avx512_aligned_allocator> dst2(total_samples, 0.0f);
simd::mix_audio(src1.data(), src2.data(), dst1.data(), total_samples);
simd::mix_audio(src2.data(), src1.data(), dst2.data(), total_samples);
EXPECT_TRUE(buffers_equal(dst1, dst2, 1e-5f));
}
INSTANTIATE_TEST_SUITE_P(
MixAudioParametrized,
MixAudioTest,
::testing::Values(
AudioProcessingTestParams{64, 1, 0.0f},
AudioProcessingTestParams{256, 2, 0.0f},
AudioProcessingTestParams{1024, 4, 0.0f},
AudioProcessingTestParams{4096, 8, 0.0f},
AudioProcessingTestParams{8192, 1, 0.0f}
)
);
// ============================================================================
// 边界条件测试
// ============================================================================
class BoundaryConditionTest : public ::testing::Test {
protected:
const float epsilon = 1e-5f;
};
TEST_F(BoundaryConditionTest, FillBufferZeroLength) {
std::vector<float, avx512_aligned_allocator> buffer(10, 1.0f);
simd::fill_buffer(buffer.data(), 0.0f, 0); // 不应该修改任何元素
for (auto val : buffer) {
EXPECT_EQ(val, 1.0f);
}
}
TEST_F(BoundaryConditionTest, FillBufferSingleSample) {
std::vector<float, avx512_aligned_allocator> buffer(1);
const float fill_value = 7.5f;
simd::fill_buffer(buffer.data(), fill_value, 1);
EXPECT_FLOAT_EQ(buffer[0], fill_value);
}
TEST_F(BoundaryConditionTest, ApplyGainZeroLength) {
std::vector<float, avx512_aligned_allocator> src(10, 5.0f);
std::vector<float, avx512_aligned_allocator> dst(10, 1.0f);
simd::apply_gain(src.data(), dst.data(), 2.0f, 0);
for (auto val : dst) {
EXPECT_EQ(val, 1.0f);
}
}
TEST_F(BoundaryConditionTest, ApplyGainSingleSample) {
std::vector<float, avx512_aligned_allocator> src = {3.0f};
std::vector<float, avx512_aligned_allocator> dst = {0.0f};
simd::apply_gain(src.data(), dst.data(), 4.0f, 1);
EXPECT_FLOAT_EQ(dst[0], 12.0f);
}
TEST_F(BoundaryConditionTest, MixAudioZeroLength) {
std::vector<float, avx512_aligned_allocator> src1(10, 1.0f);
std::vector<float, avx512_aligned_allocator> src2(10, 2.0f);
std::vector<float, avx512_aligned_allocator> dst(10, 0.0f);
simd::mix_audio(src1.data(), src2.data(), dst.data(), 0);
for (auto val : dst) {
EXPECT_EQ(val, 0.0f);
}
}
TEST_F(BoundaryConditionTest, MixAudioSingleSample) {
std::vector<float, avx512_aligned_allocator> src1 = {2.5f};
std::vector<float, avx512_aligned_allocator> src2 = {3.5f};
std::vector<float, avx512_aligned_allocator> dst = {0.0f};
simd::mix_audio(src1.data(), src2.data(), dst.data(), 1);
EXPECT_FLOAT_EQ(dst[0], 6.0f);
}
TEST_F(BoundaryConditionTest, ExtremeLargeValues) {
std::vector<float, avx512_aligned_allocator> buffer(100);
const float large_value = 1e6f;
simd::fill_buffer(buffer.data(), large_value, buffer.size());
for (auto val : buffer) {
EXPECT_FLOAT_EQ(val, large_value);
}
}
TEST_F(BoundaryConditionTest, ExtremeSmallValues) {
std::vector<float, avx512_aligned_allocator> buffer(100);
const float small_value = 1e-6f;
simd::fill_buffer(buffer.data(), small_value, buffer.size());
for (auto val : buffer) {
EXPECT_NEAR(val, small_value, 1e-12f);
}
}
TEST_F(BoundaryConditionTest, FillBufferWithMaxFloat) {
std::vector<float, avx512_aligned_allocator> buffer(10);
const float max_val = std::numeric_limits<float>::max();
simd::fill_buffer(buffer.data(), max_val, buffer.size());
for (auto val : buffer) {
EXPECT_EQ(val, max_val);
}
}
TEST_F(BoundaryConditionTest, ApplyGainWithVerySmallGain) {
std::vector<float, avx512_aligned_allocator> src(100, 1e6f);
std::vector<float, avx512_aligned_allocator> dst(100);
const float tiny_gain = 1e-7f;
simd::apply_gain(src.data(), dst.data(), tiny_gain, src.size());
for (size_t i = 0; i < src.size(); ++i) {
EXPECT_NEAR(dst[i], src[i] * tiny_gain, 1e-10f);
}
}
// ============================================================================
// 数据对齐测试
// ============================================================================
class AlignmentTest : public ::testing::Test {
protected:
template<size_t Alignment>
bool check_alignment(const void* ptr) const {
return reinterpret_cast<uintptr_t>(ptr) % Alignment == 0;
}
};
TEST_F(AlignmentTest, SSEAlignedBuffer) {
std::vector<float, aligned_allocator<float, ALIGNMENT_SSE>> buffer(1024);
EXPECT_TRUE(check_alignment<ALIGNMENT_SSE>(buffer.data()));
}
TEST_F(AlignmentTest, AVXAlignedBuffer) {
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX>> buffer(1024);
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX>(buffer.data()));
}
TEST_F(AlignmentTest, AVX512AlignedBuffer) {
std::vector<float, aligned_allocator<float, ALIGNMENT_AVX512>> buffer(1024);
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(buffer.data()));
}
TEST_F(AlignmentTest, FillBufferMaintainsAlignment) {
std::vector<float, avx512_aligned_allocator> buffer(1024);
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(buffer.data()));
simd::fill_buffer(buffer.data(), 1.0f, buffer.size());
// 数据仍然在原地,对齐不变
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(buffer.data()));
}
TEST_F(AlignmentTest, ApplyGainWithAlignedData) {
std::vector<float, avx512_aligned_allocator> src(256);
std::vector<float, avx512_aligned_allocator> dst(256);
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(src.data()));
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(dst.data()));
simd::apply_gain(src.data(), dst.data(), 0.5f, src.size());
// 对齐在操作后仍然有效
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(src.data()));
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(dst.data()));
}
TEST_F(AlignmentTest, MixAudioWithAlignedData) {
std::vector<float, avx512_aligned_allocator> src1(512);
std::vector<float, avx512_aligned_allocator> src2(512);
std::vector<float, avx512_aligned_allocator> dst(512);
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(src1.data()));
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(src2.data()));
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(dst.data()));
simd::mix_audio(src1.data(), src2.data(), dst.data(), src1.size());
EXPECT_TRUE(check_alignment<ALIGNMENT_AVX512>(dst.data()));
}
TEST_F(AlignmentTest, UnalignedBufferHandling) {
// 创建一个未对齐的缓冲区(通过跳过第一个字节)
std::vector<float, avx512_aligned_allocator> aligned_storage(1025);
float* unaligned_ptr = aligned_storage.data() + 1; // 偏移1个元素破坏对齐
// 虽然指针未对齐,但函数应该仍然能工作(可能性能较低)
// 这测试了函数的鲁棒性,而不是对齐的要求
std::vector<float> expected(1024, 5.0f);
simd::fill_buffer(unaligned_ptr, 5.0f, 1024);
for (size_t i = 0; i < 1024; ++i) {
EXPECT_FLOAT_EQ(unaligned_ptr[i], 5.0f);
}
}
// ============================================================================
// 性能基准测试
// ============================================================================
class PerformanceBenchmark : public ::testing::Test {
protected:
const int ITERATIONS = 100;
};
TEST_F(PerformanceBenchmark, FillBufferThroughput64Samples) {
std::vector<float, avx512_aligned_allocator> buffer(64);
LatencyRecorder latency_recorder("FillBuffer_64");
for (int iter = 0; iter < ITERATIONS; ++iter) {
ScopedTimer timer("", false);
simd::fill_buffer(buffer.data(), 1.0f, buffer.size());
timer.stop();
latency_recorder.record(timer.elapsed_ns());
}
auto stats = latency_recorder.get_statistics();
double samples_per_sec = (64.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS);
std::cout << "FillBuffer (64 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl;
EXPECT_GT(samples_per_sec, 0.0); // 基本健全性检查
}
TEST_F(PerformanceBenchmark, FillBufferThroughput1024Samples) {
std::vector<float, avx512_aligned_allocator> buffer(1024);
LatencyRecorder latency_recorder("FillBuffer_1024");
for (int iter = 0; iter < ITERATIONS; ++iter) {
ScopedTimer timer("", false);
simd::fill_buffer(buffer.data(), 1.0f, buffer.size());
timer.stop();
latency_recorder.record(timer.elapsed_ns());
}
auto stats = latency_recorder.get_statistics();
double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS);
std::cout << "FillBuffer (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl;
EXPECT_GT(samples_per_sec, 0.0);
}
TEST_F(PerformanceBenchmark, ApplyGainThroughput) {
std::vector<float, avx512_aligned_allocator> src(1024, 1.0f);
std::vector<float, avx512_aligned_allocator> dst(1024);
LatencyRecorder latency_recorder("ApplyGain_1024");
for (int iter = 0; iter < ITERATIONS; ++iter) {
ScopedTimer timer("", false);
simd::apply_gain(src.data(), dst.data(), 0.5f, src.size());
timer.stop();
latency_recorder.record(timer.elapsed_ns());
}
auto stats = latency_recorder.get_statistics();
double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS);
std::cout << "ApplyGain (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl;
EXPECT_GT(samples_per_sec, 0.0);
}
TEST_F(PerformanceBenchmark, MixAudioThroughput) {
std::vector<float, avx512_aligned_allocator> src1(1024, 1.0f);
std::vector<float, avx512_aligned_allocator> src2(1024, 2.0f);
std::vector<float, avx512_aligned_allocator> dst(1024);
LatencyRecorder latency_recorder("MixAudio_1024");
for (int iter = 0; iter < ITERATIONS; ++iter) {
ScopedTimer timer("", false);
simd::mix_audio(src1.data(), src2.data(), dst.data(), src1.size());
timer.stop();
latency_recorder.record(timer.elapsed_ns());
}
auto stats = latency_recorder.get_statistics();
double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS);
std::cout << "MixAudio (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl;
EXPECT_GT(samples_per_sec, 0.0);
}
// ============================================================================
// 跨实现一致性测试
// ============================================================================
class CrossImplementationConsistencyTest : public ::testing::Test {
protected:
void SetUp() override {
// 初始化测试数据
test_data_ = generate_sine_wave<avx512_aligned_allocator>(0.1f, 1024);
expected_result_ = test_data_;
}
std::vector<float, avx512_aligned_allocator> test_data_;
std::vector<float, avx512_aligned_allocator> expected_result_;
};
TEST_F(CrossImplementationConsistencyTest, FillBufferConsistency) {
std::vector<float, avx512_aligned_allocator> result(1024);
// 使用SIMD实现
simd::fill_buffer(result.data(), 5.0f, 1024);
// 验证所有元素都是5.0
for (size_t i = 0; i < 1024; ++i) {
EXPECT_FLOAT_EQ(result[i], 5.0f)
<< "SIMD实现结果不一致于索引 " << i;
}
}
TEST_F(CrossImplementationConsistencyTest, ApplyGainConsistency) {
std::vector<float, avx512_aligned_allocator> src(1024, 3.0f);
std::vector<float, avx512_aligned_allocator> result(1024);
// 使用SIMD实现
simd::apply_gain(src.data(), result.data(), 2.0f, 1024);
// 验证结果为6.03.0 * 2.0
for (size_t i = 0; i < 1024; ++i) {
EXPECT_FLOAT_EQ(result[i], 6.0f)
<< "SIMD实现结果不一致于索引 " << i;
}
}
TEST_F(CrossImplementationConsistencyTest, MixAudioConsistency) {
std::vector<float, avx512_aligned_allocator> src1(1024, 1.0f);
std::vector<float, avx512_aligned_allocator> src2(1024, 2.0f);
std::vector<float, avx512_aligned_allocator> result(1024);
// 使用SIMD实现
simd::mix_audio(src1.data(), src2.data(), result.data(), 1024);
// 验证结果为3.01.0 + 2.0
for (size_t i = 0; i < 1024; ++i) {
EXPECT_FLOAT_EQ(result[i], 3.0f)
<< "SIMD实现结果不一致于索引 " << i;
}
}
// ============================================================================
// 额外功能测试
// ============================================================================
/**
* @brief 计算RMS值的辅助函数
*/
float calculate_rms(const std::vector<float>& data) {
double sum = 0.0;
for (float val : data) {
sum += val * val;
}
return std::sqrt(sum / data.size());
}
/**
* @brief 计算峰值辅助函数
*/
float calculate_peak(const std::vector<float>& data) {
float peak = 0.0f;
for (float val : data) {
peak = std::max(peak, std::abs(val));
}
return peak;
}
class AdditionalFunctionalityTest : public ::testing::Test {
protected:
void SetUp() override {
test_data_ = generate_sine_wave<avx512_aligned_allocator>(0.1f, 1024);
}
std::vector<float, avx512_aligned_allocator> test_data_;
};
TEST_F(AdditionalFunctionalityTest, RMSCalculation) {
std::vector<float, avx512_aligned_allocator> src(test_data_.begin(), test_data_.end());
std::vector<float, avx512_aligned_allocator> dst(1024);
// 使用SIMD实现计算RMS
float rms = simd::calculate_rms(src.data(), 1024);
// 验证RMS值在合理范围内
EXPECT_GT(rms, 0.0);
EXPECT_LT(rms, 1.0);
// 验证与参考实现的一致性
std::vector<float> test_data_copy(test_data_.begin(), test_data_.end());
float expected_rms = calculate_rms(test_data_copy);
EXPECT_NEAR(rms, expected_rms, 0.01f);
}
TEST_F(AdditionalFunctionalityTest, PeakCalculation) {
std::vector<float, avx512_aligned_allocator> src(test_data_.begin(), test_data_.end());
// 使用SIMD实现计算峰值
float peak = simd::calculate_peak(src.data(), 1024);
// 验证峰值在合理范围内
EXPECT_GT(peak, 0.0);
EXPECT_LT(peak, 1.1f); // 允许一些误差
// 验证与参考实现的一致性
std::vector<float> test_data_copy(test_data_.begin(), test_data_.end());
float expected_peak = calculate_peak(test_data_copy);
EXPECT_NEAR(peak, expected_peak, 0.01f);
}
TEST_F(AdditionalFunctionalityTest, StereoToMono) {
// 创建交错的立体声测试数据 (LRLRLR...)
std::vector<float, avx512_aligned_allocator> stereo_interleaved(1024);
std::vector<float, avx512_aligned_allocator> mono_result(512);
// 填充交错数据:左声道=1.0,右声道=2.0
for (size_t i = 0; i < 512; ++i) {
stereo_interleaved[i * 2] = 1.0f; // 左声道
stereo_interleaved[i * 2 + 1] = 2.0f; // 右声道
}
// 转换为单声道
simd::stereo_to_mono(stereo_interleaved.data(), mono_result.data(), 512);
// 验证结果为平均值 (1.0 + 2.0) / 2 = 1.5
for (size_t i = 0; i < 512; ++i) {
EXPECT_FLOAT_EQ(mono_result[i], 1.5f);
}
}
} // namespace