Files
Alicho/docs/api/engine.md
2025-10-28 10:27:49 +08:00

884 lines
28 KiB
Markdown
Raw Permalink 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.
# 音频引擎API参考
## 目录
- [概述](#概述)
- [核心类型](#核心类型)
- [AudioFormat](#audioformat)
- [AudioConfig](#audioconfig)
- [音频缓冲区](#音频缓冲区)
- [AudioBuffer类](#audiobuffer类)
- [内存布局](#内存布局)
- [格式转换](#格式转换)
- [混音和增益](#混音和增益)
- [环形缓冲区](#环形缓冲区)
- [RingBuffer类](#ringbuffer类)
- [线程安全性](#线程安全性)
- [实现示例](#实现示例)
- [基本音频处理](#基本音频处理)
- [实时音频流处理](#实时音频流处理)
- [多声道混音示例](#多声道混音示例)
- [性能优化策略](#性能优化策略)
- [SIMD优化](#simd优化)
- [内存对齐](#内存对齐)
- [零拷贝技术](#零拷贝技术)
- [跨平台考虑](#跨平台考虑)
## 概述
音频引擎模块是音频后端系统的核心组件负责高效处理和管理音频数据。该模块采用SIMD优化设计支持多种音频格式和声道配置并提供线程安全的音频流处理功能。
核心特性:
- 支持多种音频格式16/24/32位整数32/64位浮点数
- 支持交错和非交错(平面)音频数据布局
- SIMD指令集优化SSE/AVX/AVX-512/NEON
- 零拷贝数据传输
- 线程安全的环形缓冲区实现
- 高性能混音和格式转换
## 核心类型
### AudioFormat
`AudioFormat`枚举定义了系统支持的音频采样格式。
```cpp
enum class AudioFormat {
UNKNOWN = 0,
INT16, // 16位有符号整数 [-32768, 32767]
INT24, // 24位有符号整数包在int32中[-8388608, 8388607]
INT32, // 32位有符号整数
FLOAT32, // 32位浮点数 [-1.0, 1.0]
FLOAT64 // 64位浮点数 [-1.0, 1.0]
};
```
**格式说明:**
| 格式 | 描述 | 位深度 | 数值范围 | 典型用途 |
|------|------|--------|----------|----------|
| `INT16` | 16位有符号整数 | 16位 | [-32768, 32767] | 兼容性最广,适用于存储和传输 |
| `INT24` | 24位有符号整数 | 24位 | [-8388608, 8388607] | 专业音频录制,高动态范围需求 |
| `INT32` | 32位有符号整数 | 32位 | [-2^31, 2^31-1] | 高精度处理,中间计算格式 |
| `FLOAT32` | 32位IEEE浮点数 | 32位 | [-1.0, 1.0] | 标准处理格式,良好的精度和性能平衡 |
| `FLOAT64` | 64位IEEE浮点数 | 64位 | [-1.0, 1.0] | 高精度计算,避免累积误差 |
**辅助函数:**
```cpp
// 获取音频格式的字节大小
size_t get_format_byte_size(AudioFormat format);
// 获取音频格式名称
const char* get_format_name(AudioFormat format);
```
### AudioConfig
`AudioConfig`结构定义了音频处理的配置参数,包括采样率、声道数、格式和缓冲区大小。
```cpp
struct AudioConfig {
uint32_t sample_rate = 48000; // 采样率Hz
uint16_t channels = 2; // 声道数
AudioFormat format = AudioFormat::FLOAT32; // 音频格式
uint32_t frames_per_buffer = 512; // 每个缓冲区的帧数
// 验证配置有效性
bool is_valid() const;
// 计算缓冲区大小(字节)
size_t get_buffer_size_bytes() const;
// 计算缓冲区大小(样本数)
size_t get_buffer_size_samples() const;
// 计算延迟(毫秒)
double get_latency_ms() const;
// 比较操作符
bool operator==(const AudioConfig& other) const;
bool operator!=(const AudioConfig& other) const;
};
```
**成员说明:**
- **sample_rate**: 音频采样率单位Hz。常见值: 44100 (CD质量), 48000 (专业音频), 96000/192000 (高分辨率)
- **channels**: 音频声道数。1=单声道, 2=立体声, >2=多声道
- **format**: 音频数据格式,参见 `AudioFormat` 枚举
- **frames_per_buffer**: 每个处理缓冲区包含的帧数影响延迟和CPU负载
**辅助方法:**
- `is_valid()`: 检查配置参数是否在有效范围内
- `get_buffer_size_bytes()`: 计算缓冲区的总字节数 (= frames_per_buffer × channels × 每样本字节数)
- `get_buffer_size_samples()`: 计算缓冲区的总样本数 (= frames_per_buffer × channels)
- `get_latency_ms()`: 计算基于当前缓冲区大小和采样率的理论处理延迟,单位毫秒
**常见配置示例:**
```cpp
// CD质量立体声配置
AudioConfig cd_quality;
cd_quality.sample_rate = 44100;
cd_quality.channels = 2;
cd_quality.format = AudioFormat::INT16;
cd_quality.frames_per_buffer = 1024;
// 专业音频配置(低延迟)
AudioConfig pro_audio_low_latency;
pro_audio_low_latency.sample_rate = 96000;
pro_audio_low_latency.channels = 2;
pro_audio_low_latency.format = AudioFormat::FLOAT32;
pro_audio_low_latency.frames_per_buffer = 128; // 低延迟
// 环绕声配置
AudioConfig surround;
surround.sample_rate = 48000;
surround.channels = 6; // 5.1声道
surround.format = AudioFormat::FLOAT32;
surround.frames_per_buffer = 512;
```
## 音频缓冲区
### AudioBuffer类
`AudioBuffer`是音频引擎的核心类,用于存储和处理音频数据。它支持交错和非交错(平面)格式,并提供各种音频处理功能。
```cpp
class AudioBuffer {
public:
// 构造函数
AudioBuffer();
explicit AudioBuffer(const AudioConfig& config, bool interleaved = false);
AudioBuffer(uint32_t frames, uint16_t channels, AudioFormat format, bool interleaved = false);
// 移动构造和赋值
AudioBuffer(AudioBuffer&& other) noexcept;
AudioBuffer& operator=(AudioBuffer&& other) noexcept;
// 禁止拷贝使用clone方法显式拷贝
AudioBuffer(const AudioBuffer&) = delete;
AudioBuffer& operator=(const AudioBuffer&) = delete;
// 显式拷贝
AudioBuffer clone() const;
// 重新分配缓冲区
void allocate(const AudioConfig& config, bool interleaved = false);
void allocate(uint32_t frames, uint16_t channels, AudioFormat format, bool interleaved = false);
// 释放缓冲区
void release();
// 清空缓冲区(填充零)
void clear();
// 获取配置
const AudioConfig& config() const;
// 访问器
uint32_t frames() const;
uint16_t channels() const;
AudioFormat format() const;
uint32_t sample_rate() const;
bool is_interleaved() const;
// 数据访问(非交错格式)
template<typename T>
T* channel_data(uint16_t channel);
template<typename T>
const T* channel_data(uint16_t channel) const;
// 数据访问(交错格式)
template<typename T>
T* interleaved_data();
template<typename T>
const T* interleaved_data() const;
// 原始数据访问
uint8_t* data();
const uint8_t* data() const;
size_t size_bytes() const;
bool empty() const;
// 转换为交错/非交错格式
AudioBuffer to_interleaved() const;
AudioBuffer to_non_interleaved() const;
// 格式转换
AudioBuffer convert_format(AudioFormat new_format) const;
// 重采样(简单的线性插值,用于格式转换)
AudioBuffer resample(uint32_t new_sample_rate) const;
// 复制数据到另一个缓冲区
void copy_to(AudioBuffer& dest) const;
// 从另一个缓冲区复制数据
void copy_from(const AudioBuffer& src);
// 混音(加法混合)
void mix_from(const AudioBuffer& src, float gain = 1.0f);
// 应用增益
void apply_gain(float gain);
// 检查缓冲区是否正确对齐
bool is_aligned() const;
};
```
### 内存布局
AudioBuffer支持两种内存布局
1. **交错格式 (Interleaved)**
样本按帧组织,每个帧包含所有声道的样本。布局为:`LRLRLRLR...`(立体声)
```
内存布局:[L0 R0 L1 R1 L2 R2 ... Ln Rn]
```
2. **非交错格式 (Non-interleaved/Planar)**
样本按声道组织,每个声道的样本连续存储。布局为:`LLLL...RRRR...`(立体声)
```
内存布局:[L0 L1 L2 ... Ln R0 R1 R2 ... Rn]
```
**选择合适的布局:**
- **交错格式**适合:
- 与传统音频API集成大多数API使用交错格式
- 顺序访问所有声道如文件I/O或网络传输
- **非交错格式**适合:
- SIMD向量化处理可以处理单个声道的连续样本
- 需要单独处理声道的场景(如中置声道独立处理)
- 复杂的DSP算法实现
### 格式转换
AudioBuffer提供了多种格式转换功能
```cpp
// 转换内存布局
AudioBuffer interleaved_buffer = non_interleaved_buffer.to_interleaved();
AudioBuffer planar_buffer = interleaved_buffer.to_non_interleaved();
// 转换采样格式
AudioBuffer float_buffer = int_buffer.convert_format(AudioFormat::FLOAT32);
AudioBuffer int_buffer = float_buffer.convert_format(AudioFormat::INT16);
// 重采样
AudioBuffer resampled = original.resample(96000); // 从原始采样率转到96kHz
```
**格式转换的注意事项:**
- 整数到浮点转换:整数范围将映射到[-1.0, 1.0]浮点范围
- 浮点到整数转换:[-1.0, 1.0]范围将映射到相应整数格式的最大范围
- 较低位深度到较高位深度转换:保留原有精度,向上扩展
- 较高位深度到较低位深度转换:会损失精度,可能引入截断和量化错误
- 重采样操作会改变缓冲区大小,但声道数和格式保持不变
### 混音和增益
```cpp
// 应用增益(音量调整)
buffer.apply_gain(0.5f); // 将音量降低到50%
// 混合两个缓冲区
dest_buffer.mix_from(src_buffer, 0.7f); // 以70%的音量混合src_buffer到dest_buffer
```
**混音算法:**
混音操作对每个样本执行以下计算:
```
dest[i] = dest[i] + (src[i] * gain)
```
对于FLOAT32格式直接相加可能导致值超出[-1.0, 1.0]范围。AudioBuffer实现了两种处理策略
1. **限幅 (Clipping)**:将超出范围的值限制在有效范围内
2. **软限幅 (Soft Clipping)**:应用非线性曲线,在接近极限值时逐渐压缩动态范围
## 环形缓冲区
### RingBuffer类
`RingBuffer`是一个模板类,用于实时音频流处理,提供线程安全的生产者-消费者模型。
```cpp
template<typename T>
class RingBuffer {
public:
// 构造函数
explicit RingBuffer(size_t capacity = 0);
// 重新分配容量
void resize(size_t new_capacity);
// 写入数据
size_t write(const T* data, size_t count);
// 读取数据
size_t read(T* data, size_t count);
// 清空缓冲区
void clear();
// 获取可用数据量
size_t available() const;
// 获取可写空间
size_t space() const;
// 获取容量
size_t capacity() const;
// 检查是否为空
bool empty() const;
// 检查是否已满
bool full() const;
};
```
RingBuffer适用于
- 音频捕获和播放之间的缓冲
- 网络音频流的抖动缓冲
- 音频处理线程和UI线程之间的数据传输
- 多速率系统中的采样率转换缓冲
### 线程安全性
RingBuffer实现了完整的线程安全保障
- 使用`std::mutex`保护关键部分
- 使用`std::atomic`变量跟踪读写位置和可用数据量
- 内存顺序memory ordering确保多线程正确性
**并发模型:**
- 一个线程作为生产者(写入数据)
- 一个线程作为消费者(读取数据)
- 生产者和消费者可以独立运行,不需要额外同步
```cpp
// 生产者线程代码
void producer_thread(RingBuffer<float>& buffer, const AudioSource& source) {
float temp_buffer[256];
while (running) {
size_t samples = source.read(temp_buffer, 256);
size_t written = buffer.write(temp_buffer, samples);
if (written < samples) {
// 缓冲区已满,处理溢出情况
log_overflow(samples - written);
}
}
}
// 消费者线程代码
void consumer_thread(RingBuffer<float>& buffer, AudioOutput& output) {
float temp_buffer[256];
while (running) {
size_t available = buffer.available();
if (available >= 256) {
buffer.read(temp_buffer, 256);
output.play(temp_buffer, 256);
} else {
// 缓冲区数据不足,处理饥饿情况
log_underflow(256 - available);
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
}
```
## 实现示例
### 基本音频处理
以下示例展示了基本的音频处理流程:
```cpp
#include "audio_backend/engine.h"
using namespace audio_backend::engine;
// 基本音频处理流程
void process_audio_file(const std::string& input_file, const std::string& output_file) {
// 创建音频配置
AudioConfig config;
config.sample_rate = 48000;
config.channels = 2;
config.format = AudioFormat::FLOAT32;
config.frames_per_buffer = 1024;
// 加载音频文件到缓冲区仅用于示例实际实现需要文件I/O
AudioBuffer input_buffer(config);
load_audio_file(input_file, input_buffer);
// 创建处理缓冲区
AudioBuffer output_buffer(config);
// 应用音频处理
input_buffer.copy_to(output_buffer); // 首先复制原始数据
output_buffer.apply_gain(0.8f); // 将音量降低到80%
// 添加简单的回声效果
AudioBuffer delay_buffer = input_buffer.clone();
delay_buffer.apply_gain(0.4f); // 回声音量为40%
output_buffer.mix_from(delay_buffer); // 混合回声
// 保存处理后的音频仅用于示例实际实现需要文件I/O
save_audio_file(output_file, output_buffer);
}
// 示例辅助函数实际实现需要替换为真实的文件I/O代码
void load_audio_file(const std::string& filename, AudioBuffer& buffer) {
// 此处应为实际的文件加载代码
buffer.clear(); // 先清空缓冲区
// 填充测试数据(正弦波)
float* data = buffer.interleaved_data<float>();
const float frequency = 440.0f; // A4音符频率
const float sample_rate = buffer.sample_rate();
for (uint32_t i = 0; i < buffer.frames(); ++i) {
float sample = std::sin(2.0f * M_PI * frequency * i / sample_rate);
// 对于立体声,填充两个声道
for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
data[i * buffer.channels() + ch] = sample;
}
}
}
void save_audio_file(const std::string& filename, const AudioBuffer& buffer) {
// 此处应为实际的文件保存代码
std::cout << "Saving audio to: " << filename << std::endl;
std::cout << " Sample rate: " << buffer.sample_rate() << " Hz" << std::endl;
std::cout << " Channels: " << buffer.channels() << std::endl;
std::cout << " Format: " << get_format_name(buffer.format()) << std::endl;
std::cout << " Frames: " << buffer.frames() << std::endl;
std::cout << " Duration: " << (buffer.frames() / (float)buffer.sample_rate()) << " seconds" << std::endl;
}
```
### 实时音频流处理
以下示例展示如何使用RingBuffer实现实时音频流处理
```cpp
#include "audio_backend/engine.h"
#include <thread>
#include <atomic>
#include <chrono>
using namespace audio_backend::engine;
using namespace std::chrono_literals;
class AudioStreamer {
public:
AudioStreamer(uint32_t sample_rate, uint16_t channels, uint32_t buffer_ms = 100)
: config_(), ring_buffer_(0), running_(false) {
config_.sample_rate = sample_rate;
config_.channels = channels;
config_.format = AudioFormat::FLOAT32;
config_.frames_per_buffer = 512;
// 计算环形缓冲区大小(基于毫秒)
size_t buffer_samples = (sample_rate * channels * buffer_ms) / 1000;
ring_buffer_.resize(buffer_samples);
}
~AudioStreamer() {
stop();
}
void start() {
if (running_) return;
running_ = true;
producer_thread_ = std::thread(&AudioStreamer::producer_loop, this);
consumer_thread_ = std::thread(&AudioStreamer::consumer_loop, this);
}
void stop() {
if (!running_) return;
running_ = false;
if (producer_thread_.joinable()) producer_thread_.join();
if (consumer_thread_.joinable()) consumer_thread_.join();
}
private:
AudioConfig config_;
RingBuffer<float> ring_buffer_;
std::atomic<bool> running_;
std::thread producer_thread_;
std::thread consumer_thread_;
void producer_loop() {
// 创建用于生成音频的缓冲区
AudioBuffer source_buffer(config_);
float* source_data = source_buffer.interleaved_data<float>();
// 采样计数器(用于生成连续正弦波)
uint64_t sample_count = 0;
const float frequency = 440.0f; // A4音符频率
const float pi2 = 2.0f * 3.14159265358979323846f;
while (running_) {
// 生成音频数据(正弦波)
for (uint32_t i = 0; i < source_buffer.frames(); ++i) {
float t = static_cast<float>(sample_count++) / config_.sample_rate;
float sample = std::sin(pi2 * frequency * t);
// 对于立体声,填充两个声道
for (uint16_t ch = 0; ch < config_.channels; ++ch) {
source_data[i * config_.channels + ch] = sample;
}
}
// 写入环形缓冲区
size_t samples_to_write = source_buffer.frames() * config_.channels;
size_t written = ring_buffer_.write(source_data, samples_to_write);
if (written < samples_to_write) {
// 缓冲区溢出
std::cout << "Buffer overflow: dropped " << (samples_to_write - written) << " samples" << std::endl;
}
// 模拟生成音频的处理时间
std::this_thread::sleep_for(10ms);
}
}
void consumer_loop() {
// 创建用于播放音频的缓冲区
AudioBuffer output_buffer(config_);
float* output_data = output_buffer.interleaved_data<float>();
// 计算每个缓冲区的持续时间(毫秒)
float buffer_duration_ms = (config_.frames_per_buffer * 1000.0f) / config_.sample_rate;
while (running_) {
// 从环形缓冲区读取数据
size_t samples_to_read = output_buffer.frames() * config_.channels;
size_t read = ring_buffer_.read(output_data, samples_to_read);
if (read < samples_to_read) {
// 缓冲区下溢
std::cout << "Buffer underflow: missing " << (samples_to_read - read) << " samples" << std::endl;
// 用零填充剩余部分
memset(output_data + read, 0, (samples_to_read - read) * sizeof(float));
}
// 这里应该将数据发送到音频输出设备
// audio_device.play(output_data, samples_to_read);
// 模拟实际播放的时间
std::this_thread::sleep_for(std::chrono::duration<float, std::milli>(buffer_duration_ms));
}
}
};
// 使用示例
void run_audio_streaming() {
// 创建音频流处理器48kHz立体声100ms缓冲
AudioStreamer streamer(48000, 2, 100);
// 启动处理
streamer.start();
// 运行5秒
std::this_thread::sleep_for(5s);
// 停止处理
streamer.stop();
}
```
### 多声道混音示例
以下示例演示如何使用AudioBuffer进行多声道混音处理
```cpp
#include "audio_backend/engine.h"
#include <vector>
using namespace audio_backend::engine;
// 多声道混音处理器
class MultiChannelMixer {
public:
MultiChannelMixer(uint32_t sample_rate, uint32_t frames_per_buffer)
: sample_rate_(sample_rate),
frames_per_buffer_(frames_per_buffer),
output_config_(),
output_buffer_() {
// 配置输出缓冲区立体声32位浮点
output_config_.sample_rate = sample_rate;
output_config_.channels = 2;
output_config_.format = AudioFormat::FLOAT32;
output_config_.frames_per_buffer = frames_per_buffer;
// 分配输出缓冲区
output_buffer_.allocate(output_config_, true); // 交错格式
}
// 添加输入源返回源ID
int add_source() {
AudioConfig source_config;
source_config.sample_rate = sample_rate_;
source_config.channels = 2; // 假设所有源都是立体声
source_config.format = AudioFormat::FLOAT32;
source_config.frames_per_buffer = frames_per_buffer_;
input_buffers_.emplace_back(source_config, true); // 交错格式
volumes_.push_back(1.0f); // 默认音量为100%
return static_cast<int>(input_buffers_.size() - 1);
}
// 设置源的音量
void set_source_volume(int source_id, float volume) {
if (source_id >= 0 && source_id < static_cast<int>(volumes_.size())) {
volumes_[source_id] = volume;
}
}
// 提供源数据(例如从文件或网络读取)
void provide_source_data(int source_id, const float* data, size_t samples) {
if (source_id >= 0 && source_id < static_cast<int>(input_buffers_.size())) {
// 确保没有超出缓冲区大小
size_t max_samples = input_buffers_[source_id].frames() * input_buffers_[source_id].channels();
size_t copy_samples = std::min(samples, max_samples);
// 复制数据到源缓冲区
float* dest = input_buffers_[source_id].interleaved_data<float>();
std::memcpy(dest, data, copy_samples * sizeof(float));
}
}
// 执行混音处理
const AudioBuffer& process() {
// 清空输出缓冲区
output_buffer_.clear();
// 混合所有输入源
for (size_t i = 0; i < input_buffers_.size(); ++i) {
// 使用各自的音量设置混合
output_buffer_.mix_from(input_buffers_[i], volumes_[i]);
}
return output_buffer_;
}
private:
uint32_t sample_rate_;
uint32_t frames_per_buffer_;
std::vector<AudioBuffer> input_buffers_; // 输入源缓冲区
std::vector<float> volumes_; // 每个源的音量
AudioConfig output_config_; // 输出配置
AudioBuffer output_buffer_; // 输出缓冲区
};
// 使用示例
void mix_audio_channels() {
// 创建混音器48kHz512帧缓冲
MultiChannelMixer mixer(48000, 512);
// 添加两个音频源
int source1 = mixer.add_source();
int source2 = mixer.add_source();
// 设置音量
mixer.set_source_volume(source1, 0.7f); // 70%音量
mixer.set_source_volume(source2, 0.5f); // 50%音量
// 生成测试数据(这里只是示例)
std::vector<float> test_data1(1024, 0.0f); // 1024个样本
std::vector<float> test_data2(1024, 0.0f); // 1024个样本
// 源1440Hz正弦波
float freq1 = 440.0f;
for (int i = 0; i < 512; ++i) { // 512帧
float sample = std::sin(2.0f * M_PI * freq1 * i / 48000.0f);
test_data1[i*2] = test_data1[i*2+1] = sample; // 立体声相同
}
// 源2880Hz正弦波
float freq2 = 880.0f;
for (int i = 0; i < 512; ++i) { // 512帧
float sample = std::sin(2.0f * M_PI * freq2 * i / 48000.0f);
test_data2[i*2] = test_data2[i*2+1] = sample; // 立体声相同
}
// 提供数据
mixer.provide_source_data(source1, test_data1.data(), test_data1.size());
mixer.provide_source_data(source2, test_data2.data(), test_data2.size());
// 执行混音
const AudioBuffer& mixed = mixer.process();
// 在实际应用中现在可以播放或处理mixed缓冲区
std::cout << "混音完成: " << mixed.frames() << " 帧,"
<< mixed.channels() << " 声道,"
<< "格式: " << get_format_name(mixed.format()) << std::endl;
}
```
## 性能优化策略
### SIMD优化
音频引擎对大多数处理操作都实现了SIMD优化版本支持以下指令集
- x86/x64: SSE2, SSE3, SSE4, AVX, AVX2, AVX-512
- ARM: NEON (32位和64位)
SIMD优化适用的操作
- 格式转换(整数到浮点,浮点到整数)
- 混合和增益应用
- 声道转换(单声道到立体声,立体声到单声道)
- 各种数学运算(加、减、乘、平方根等)
关键SIMD函数示例
```cpp
// 不同指令集的实现示例(仅示意)
namespace audio_backend::simd {
// SIMD版本选择标记
struct SSE2Tag {};
struct AVX2Tag {};
struct AVX512Tag {};
struct NEONTag {};
// 混音函数的SSE2实现
void mix_audio_f32_impl(const float* input1, const float* input2, float* output,
size_t samples, SSE2Tag) {
// 使用SSE2指令集实现
}
// 混音函数的AVX2实现
void mix_audio_f32_impl(const float* input1, const float* input2, float* output,
size_t samples, AVX2Tag) {
// 使用AVX2指令集实现
}
// 调度函数
void mix_audio_f32(const float* input1, const float* input2, float* output, size_t samples) {
// 根据当前支持的最高指令集动态选择实现
if (cpu_features.has_avx512) {
mix_audio_f32_impl(input1, input2, output, samples, AVX512Tag{});
} else if (cpu_features.has_avx2) {
mix_audio_f32_impl(input1, input2, output, samples, AVX2Tag{});
} else if (cpu_features.has_sse2) {
mix_audio_f32_impl(input1, input2, output, samples, SSE2Tag{});
} else {
mix_audio_f32_scalar(input1, input2, output, samples); // 回退到标量实现
}
}
} // namespace audio_backend::simd
```
### 内存对齐
AudioBuffer使用内存对齐技术以优化SIMD指令的性能
```cpp
// 对齐的内存分配
template<typename T, size_t Alignment>
class AlignedBuffer {
public:
AlignedBuffer() = default;
explicit AlignedBuffer(size_t size) {
allocate(size);
}
void allocate(size_t size) {
// 分配对齐的内存
}
// ... 其他方法
};
// 在AudioBuffer中的使用
simd::AlignedBuffer<uint8_t, simd::ALIGNMENT_AVX> data_;
```
内存对齐的重要性:
- SIMD指令通常要求数据对齐到16字节SSE或32字节AVX边界
- 未对齐的内存访问可能导致性能下降或特定平台上的异常
- 更高级的指令集如AVX-512对对齐的要求更严格
### 零拷贝技术
系统使用多种技术最小化不必要的内存复制:
1. **移动语义**使用C++移动构造函数和移动赋值运算符避免不必要的复制
```cpp
// 移动构造和赋值
AudioBuffer(AudioBuffer&& other) noexcept;
AudioBuffer& operator=(AudioBuffer&& other) noexcept;
```
2. **引用传递**:通过引用传递大型缓冲区,而不是通过值传递
```cpp
// 通过引用传递大型缓冲区
void process_audio(const AudioBuffer& input, AudioBuffer& output);
```
3. **原位处理**:尽可能在原地修改数据,避免创建临时缓冲区
```cpp
// 原位增益应用(不创建新缓冲区)
buffer.apply_gain(0.8f);
```
## 跨平台考虑
音频引擎设计为在所有主要平台Windows、Linux、macOS上以相同方式工作但需注意以下平台特定差异
### 内存对齐
不同平台的对齐要求可能不同:
- Windows: 通常使用`_aligned_malloc`和`_aligned_free`
- Linux/macOS: 通常使用`posix_memalign`或`aligned_alloc`
### SIMD指令集
平台支持的SIMD指令集不同
- Intel/AMD处理器支持SSE/AVX指令集
- ARM处理器支持NEON指令集
- 特定指令可能在不同CPU代之间有可用性差异
### 线程模型
线程优先级和实时音频策略在不同平台实现方式不同:
- Windows使用`SetThreadPriority`
- Linux使用SCHED_FIFO或SCHED_RR策略
- macOS使用`thread_policy_set`
### 字节序
在处理原始音频数据时需考虑字节序(尤其是整数格式):
- 大多数音频格式要求特定字节序(通常为小端序)
- 跨平台时需确保一致的字节序处理