Files
Alicho/tests/unit/engine/audio_buffer_conversion_test.cpp
2025-10-28 10:27:49 +08:00

258 lines
10 KiB
C++

// ================================================================================================
// Audio Backend - 音频缓冲区转换测试
// ================================================================================================
#include <gtest/gtest.h>
#include "engine/audio_buffer.h"
#include "tests/common/test_fixtures.h"
#include "tests/common/test_utils.h"
using namespace audio_backend;
using namespace audio_backend::engine;
// 音频缓冲区格式转换测试固定装置
class AudioBufferConversionTest : public test::AudioEngineTest {
protected:
void SetUp() override {
test::AudioEngineTest::SetUp();
// 准备不同格式的测试值
int16_max_ = std::numeric_limits<int16_t>::max();
int24_max_ = 8388607; // 2^23 - 1
int32_max_ = std::numeric_limits<int32_t>::max();
// 创建标准测试数据
setup_test_buffers();
}
void TearDown() override {
test::AudioEngineTest::TearDown();
}
// 设置不同格式的测试缓冲区
void setup_test_buffers() {
// 浮点数据 [-1.0, 1.0]
float_buffer_ = std::make_unique<AudioBuffer>(16, 2, AudioFormat::FLOAT32);
float* float_data = float_buffer_->interleaved_data<float>();
for (int i = 0; i < 32; ++i) { // 16帧 * 2通道
float_data[i] = (i % 2 == 0) ? 1.0f * i / 31.0f : -1.0f * i / 31.0f;
}
// INT16数据 [-32768, 32767]
int16_buffer_ = std::make_unique<AudioBuffer>(16, 2, AudioFormat::INT16);
int16_t* int16_data = int16_buffer_->interleaved_data<int16_t>();
for (int i = 0; i < 32; ++i) {
int16_data[i] = (i % 2 == 0) ? static_cast<int16_t>(int16_max_ * i / 31) :
static_cast<int16_t>(-int16_max_ * i / 31);
}
// INT32数据 [-2147483648, 2147483647]
int32_buffer_ = std::make_unique<AudioBuffer>(16, 2, AudioFormat::INT32);
int32_t* int32_data = int32_buffer_->interleaved_data<int32_t>();
for (int i = 0; i < 32; ++i) {
int32_data[i] = (i % 2 == 0) ? static_cast<int32_t>(int32_max_ * i / 31) :
static_cast<int32_t>(-int32_max_ * i / 31);
}
}
// 测试辅助函数
// 检查Float32到Int16转换的精度
void check_float_to_int16(const AudioBuffer& source, const AudioBuffer& converted) {
const float* src_data = source.interleaved_data<float>();
const int16_t* conv_data = converted.interleaved_data<int16_t>();
for (size_t i = 0; i < source.frames() * source.channels(); ++i) {
int16_t expected = static_cast<int16_t>(src_data[i] * int16_max_);
EXPECT_NEAR(conv_data[i], expected, 1) << "at index " << i;
}
}
// 检查Int16到Float32转换的精度
void check_int16_to_float(const AudioBuffer& source, const AudioBuffer& converted) {
const int16_t* src_data = source.interleaved_data<int16_t>();
const float* conv_data = converted.interleaved_data<float>();
for (size_t i = 0; i < source.frames() * source.channels(); ++i) {
float expected = static_cast<float>(src_data[i]) / int16_max_;
EXPECT_NEAR(conv_data[i], expected, 1.0f/int16_max_) << "at index " << i;
}
}
// 检查Float32到Int32转换的精度
void check_float_to_int32(const AudioBuffer& source, const AudioBuffer& converted) {
const float* src_data = source.interleaved_data<float>();
const int32_t* conv_data = converted.interleaved_data<int32_t>();
for (size_t i = 0; i < source.frames() * source.channels(); ++i) {
int32_t expected = static_cast<int32_t>(src_data[i] * int32_max_);
// 允许一定的误差范围,因为浮点转整型有精度损失
EXPECT_NEAR(conv_data[i], expected, 256) << "at index " << i;
}
}
// 检查Int32到Float32转换的精度
void check_int32_to_float(const AudioBuffer& source, const AudioBuffer& converted) {
const int32_t* src_data = source.interleaved_data<int32_t>();
const float* conv_data = converted.interleaved_data<float>();
for (size_t i = 0; i < source.frames() * source.channels(); ++i) {
float expected = static_cast<float>(src_data[i]) / int32_max_;
EXPECT_NEAR(conv_data[i], expected, 1.0f/int32_max_) << "at index " << i;
}
}
protected:
std::unique_ptr<AudioBuffer> float_buffer_;
std::unique_ptr<AudioBuffer> int16_buffer_;
std::unique_ptr<AudioBuffer> int32_buffer_;
int16_t int16_max_;
int32_t int24_max_;
int32_t int32_max_;
};
// 测试Float32到INT16的转换
TEST_F(AudioBufferConversionTest, Float32ToInt16Conversion) {
AudioBuffer converted = float_buffer_->convert_format(AudioFormat::INT16);
EXPECT_EQ(converted.format(), AudioFormat::INT16);
EXPECT_EQ(converted.channels(), float_buffer_->channels());
EXPECT_EQ(converted.frames(), float_buffer_->frames());
check_float_to_int16(*float_buffer_, converted);
}
// 测试INT16到Float32的转换
TEST_F(AudioBufferConversionTest, Int16ToFloat32Conversion) {
AudioBuffer converted = int16_buffer_->convert_format(AudioFormat::FLOAT32);
EXPECT_EQ(converted.format(), AudioFormat::FLOAT32);
EXPECT_EQ(converted.channels(), int16_buffer_->channels());
EXPECT_EQ(converted.frames(), int16_buffer_->frames());
check_int16_to_float(*int16_buffer_, converted);
}
// 测试Float32到INT32的转换
TEST_F(AudioBufferConversionTest, Float32ToInt32Conversion) {
AudioBuffer converted = float_buffer_->convert_format(AudioFormat::INT32);
EXPECT_EQ(converted.format(), AudioFormat::INT32);
EXPECT_EQ(converted.channels(), float_buffer_->channels());
EXPECT_EQ(converted.frames(), float_buffer_->frames());
check_float_to_int32(*float_buffer_, converted);
}
// 测试INT32到Float32的转换
TEST_F(AudioBufferConversionTest, Int32ToFloat32Conversion) {
AudioBuffer converted = int32_buffer_->convert_format(AudioFormat::FLOAT32);
EXPECT_EQ(converted.format(), AudioFormat::FLOAT32);
EXPECT_EQ(converted.channels(), int32_buffer_->channels());
EXPECT_EQ(converted.frames(), int32_buffer_->frames());
check_int32_to_float(*int32_buffer_, converted);
}
// 测试INT16到INT32的转换
TEST_F(AudioBufferConversionTest, Int16ToInt32Conversion) {
AudioBuffer converted = int16_buffer_->convert_format(AudioFormat::INT32);
EXPECT_EQ(converted.format(), AudioFormat::INT32);
EXPECT_EQ(converted.channels(), int16_buffer_->channels());
EXPECT_EQ(converted.frames(), int16_buffer_->frames());
// 验证转换
const int16_t* src_data = int16_buffer_->interleaved_data<int16_t>();
const int32_t* conv_data = converted.interleaved_data<int32_t>();
for (size_t i = 0; i < int16_buffer_->frames() * int16_buffer_->channels(); ++i) {
// INT16到INT32: 左移16位
int32_t expected = static_cast<int32_t>(src_data[i]) << 16;
EXPECT_EQ(conv_data[i], expected) << "at index " << i;
}
}
// 测试INT32到INT16的转换
TEST_F(AudioBufferConversionTest, Int32ToInt16Conversion) {
AudioBuffer converted = int32_buffer_->convert_format(AudioFormat::INT16);
EXPECT_EQ(converted.format(), AudioFormat::INT16);
EXPECT_EQ(converted.channels(), int32_buffer_->channels());
EXPECT_EQ(converted.frames(), int32_buffer_->frames());
// 验证转换
const int32_t* src_data = int32_buffer_->interleaved_data<int32_t>();
const int16_t* conv_data = converted.interleaved_data<int16_t>();
for (size_t i = 0; i < int32_buffer_->frames() * int32_buffer_->channels(); ++i) {
// INT32到INT16: 右移16位并截断
int16_t expected = static_cast<int16_t>(src_data[i] >> 16);
EXPECT_EQ(conv_data[i], expected) << "at index " << i;
}
}
// 测试相同格式间的转换(应该是高效的复制)
TEST_F(AudioBufferConversionTest, SameFormatConversion) {
AudioBuffer converted = float_buffer_->convert_format(AudioFormat::FLOAT32);
EXPECT_EQ(converted.format(), AudioFormat::FLOAT32);
EXPECT_EQ(converted.channels(), float_buffer_->channels());
EXPECT_EQ(converted.frames(), float_buffer_->frames());
// 数据应该完全相同
const float* src_data = float_buffer_->interleaved_data<float>();
const float* conv_data = converted.interleaved_data<float>();
for (size_t i = 0; i < float_buffer_->frames() * float_buffer_->channels(); ++i) {
EXPECT_FLOAT_EQ(conv_data[i], src_data[i]) << "at index " << i;
}
}
// 测试无效格式转换
TEST_F(AudioBufferConversionTest, InvalidFormatConversion) {
// 转换为未知格式应该抛出异常
EXPECT_THROW(float_buffer_->convert_format(AudioFormat::UNKNOWN), common::AudioException);
}
// 测试重采样功能
TEST_F(AudioBufferConversionTest, Resampling) {
// 创建44.1kHz的缓冲区
AudioConfig config;
config.sample_rate = 44100;
config.channels = 2;
config.format = AudioFormat::FLOAT32;
config.frames_per_buffer = 100;
AudioBuffer original(config);
// 填充数据(简单的正弦波)
float* data = original.interleaved_data<float>();
for (size_t i = 0; i < config.frames_per_buffer; ++i) {
float t = static_cast<float>(i) / config.sample_rate;
float sample = std::sin(2.0f * M_PI * 440.0f * t); // 440Hz正弦波
data[i * 2] = sample;
data[i * 2 + 1] = sample;
}
// 重采样到48kHz
uint32_t new_sample_rate = 48000;
AudioBuffer resampled = original.resample(new_sample_rate);
// 检查基本属性
EXPECT_EQ(resampled.sample_rate(), new_sample_rate);
EXPECT_EQ(resampled.channels(), original.channels());
EXPECT_EQ(resampled.format(), original.format());
// 新帧数应该成比例变化
float ratio = static_cast<float>(new_sample_rate) / original.sample_rate();
size_t expected_frames = static_cast<size_t>(original.frames() * ratio);
EXPECT_EQ(resampled.frames(), expected_frames);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}