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

1370 lines
42 KiB
Markdown
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.
# 音频引擎使用指南
## 目录
- [音频引擎使用指南](#音频引擎使用指南)
- [目录](#目录)
- [概述](#概述)
- [音频配置与格式](#音频配置与格式)
- [音频格式](#音频格式)
- [音频配置](#音频配置)
- [常见配置场景](#常见配置场景)
- [音频缓冲区管理](#音频缓冲区管理)
- [创建音频缓冲区](#创建音频缓冲区)
- [内存对齐与SIMD优化](#内存对齐与simd优化)
- [交错与非交错格式](#交错与非交错格式)
- [格式转换](#格式转换)
- [实时音频处理](#实时音频处理)
- [处理回调设计](#处理回调设计)
- [延迟考量](#延迟考量)
- [环形缓冲区](#环形缓冲区)
- [高级功能](#高级功能)
- [多声道处理](#多声道处理)
- [采样率转换](#采样率转换)
- [音频混合](#音频混合)
- [性能优化](#性能优化)
- [缓冲区大小选择](#缓冲区大小选择)
- [SIMD加速](#simd加速)
- [内存管理](#内存管理)
- [完整示例](#完整示例)
- [音频播放器](#音频播放器)
- [实时处理器](#实时处理器)
- [格式转换器](#格式转换器)
- [跨平台考虑](#跨平台考虑)
- [Windows 平台](#windows-平台)
- [Linux 平台](#linux-平台)
- [macOS 平台](#macos-平台)
## 概述
音频引擎是Audio Backend系统的核心组件提供了高性能、低延迟的音频处理功能。音频引擎的主要目标是提供统一的音频缓冲区管理、音频格式转换和实时音频处理能力同时通过SIMD指令集优化提供卓越的性能。
核心功能:
- **高性能音频缓冲区**:支持多种格式、对齐内存和零拷贝操作
- **格式转换**:在不同音频格式之间无缝转换
- **实时处理**:低延迟音频处理,适用于实时应用
- **多声道支持**:灵活的声道配置,支持交错和非交错格式
- **SIMD优化**利用现代CPU的SIMD指令集加速音频处理
音频引擎架构:
```
┌─────────────────────┐
│ 应用程序 │
└───────────┬─────────┘
┌───────────▼─────────┐
│ 音频引擎接口 │
└───────────┬─────────┘
┌───────────▼─────────┐
│ 音频缓冲区管理 │◄────┐
└───────────┬─────────┘ │
│ │
┌───────────▼─────────┐ │
│ 格式转换 │ │
└───────────┬─────────┘ │
│ │
┌───────────▼─────────┐ │
│ 实时处理 │ │
└───────────┬─────────┘ │
│ │
┌───────────▼─────────┐ │
│ SIMD优化 │─────┘
└─────────────────────┘
```
## 音频配置与格式
### 音频格式
音频引擎支持多种常见的音频格式,适用于不同的场景和需求:
```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位 | [-32768, 32767] | 中等 | 音频文件存储、网络传输 |
| INT24 | 24位 | [-8388608, 8388607] | 高 | 高质量音频录制 |
| INT32 | 32位 | [-2147483648, 2147483647] | 非常高 | 专业音频处理 |
| FLOAT32 | 32位 | [-1.0, 1.0] | 高 | 实时处理、音效 |
| FLOAT64 | 64位 | [-1.0, 1.0] | 极高 | 精确计算、主音频总线 |
获取格式字节大小:
```cpp
// 获取音频格式的字节大小
inline size_t get_format_byte_size(AudioFormat format) {
switch (format) {
case AudioFormat::INT16: return 2;
case AudioFormat::INT24: return 3;
case AudioFormat::INT32: return 4;
case AudioFormat::FLOAT32: return 4;
case AudioFormat::FLOAT64: return 8;
default: return 0;
}
}
```
### 音频配置
`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;
};
```
### 常见配置场景
以下是几种常见的音频配置场景:
1. **低延迟实时处理**
```cpp
AudioConfig low_latency_config;
low_latency_config.sample_rate = 48000;
low_latency_config.channels = 2;
low_latency_config.format = AudioFormat::FLOAT32;
low_latency_config.frames_per_buffer = 128; // 2.67ms @ 48kHz
```
2. **高质量音频处理**
```cpp
AudioConfig high_quality_config;
high_quality_config.sample_rate = 96000;
high_quality_config.channels = 2;
high_quality_config.format = AudioFormat::FLOAT32;
high_quality_config.frames_per_buffer = 1024; // 10.67ms @ 96kHz
```
3. **多声道环绕声**
```cpp
AudioConfig surround_config;
surround_config.sample_rate = 48000;
surround_config.channels = 8; // 7.1声道
surround_config.format = AudioFormat::FLOAT32;
surround_config.frames_per_buffer = 512; // 10.67ms @ 48kHz
```
4. **网络流传输**
```cpp
AudioConfig network_stream_config;
network_stream_config.sample_rate = 44100;
network_stream_config.channels = 2;
network_stream_config.format = AudioFormat::INT16; // 节省带宽
network_stream_config.frames_per_buffer = 441; // 10ms @ 44.1kHz
```
## 音频缓冲区管理
### 创建音频缓冲区
`AudioBuffer`类是音频引擎的核心,提供了灵活的音频数据管理:
```cpp
// 创建音频缓冲区
AudioConfig config;
config.sample_rate = 48000;
config.channels = 2;
config.format = AudioFormat::FLOAT32;
config.frames_per_buffer = 512;
// 方法1: 使用配置创建
AudioBuffer buffer(config);
// 方法2: 使用单独参数创建
AudioBuffer buffer2(512, // 帧数
2, // 声道数
AudioFormat::FLOAT32, // 格式
true); // 交错格式
```
基本操作:
```cpp
// 清空缓冲区(填充零)
buffer.clear();
// 重新分配缓冲区
buffer.allocate(1024, 2, AudioFormat::FLOAT32, false);
// 释放内存
buffer.release();
```
### 内存对齐与SIMD优化
音频引擎使用内存对齐技术确保SIMD指令能高效执行
```cpp
// 检查缓冲区是否对齐
if (buffer.is_aligned()) {
// 可以安全地使用SIMD指令
// ...
} else {
// 回退到非SIMD版本
// ...
}
```
AudioBuffer内部使用AlignedBuffer确保内存按SIMD要求对齐
```cpp
// AudioBuffer内部实现片段
simd::AlignedBuffer<uint8_t, simd::ALIGNMENT_AVX> data_;
```
### 交错与非交错格式
音频引擎支持两种主要的数据布局:
1. **交错格式**LRLRLR...
- 优点:缓存友好,适合顺序访问
- 缺点:单声道处理不方便
- 适用音频文件IO硬件接口
2. **非交错格式**LLLL...RRRR...
- 优点:单声道处理方便
- 缺点:多声道同时处理效率较低
- 适用单声道效果处理某些DSP算法
示例:
```cpp
// 创建交错格式缓冲区
AudioBuffer interleaved_buffer(config, true); // true = 交错
// 创建非交错格式缓冲区
AudioBuffer non_interleaved_buffer(config, false); // false = 非交错
// 访问交错格式数据
float* interleaved_data = interleaved_buffer.interleaved_data<float>();
interleaved_data[0] = 0.5f; // 第一个样本,左声道
interleaved_data[1] = 0.5f; // 第一个样本,右声道
// 访问非交错格式数据
float* left_channel = non_interleaved_buffer.channel_data<float>(0);
float* right_channel = non_interleaved_buffer.channel_data<float>(1);
left_channel[0] = 0.5f; // 左声道第一个样本
right_channel[0] = 0.5f; // 右声道第一个样本
```
格式转换:
```cpp
// 交错格式转换为非交错格式
AudioBuffer non_interleaved = interleaved_buffer.to_non_interleaved();
// 非交错格式转换为交错格式
AudioBuffer interleaved = non_interleaved_buffer.to_interleaved();
```
### 格式转换
音频引擎支持在不同格式之间无缝转换:
```cpp
// 从FLOAT32转换为INT16
AudioBuffer float_buffer(config);
// ... 填充float_buffer ...
AudioBuffer int16_buffer = float_buffer.convert_format(AudioFormat::INT16);
// 从INT16转换为FLOAT32
AudioConfig int16_config = config;
int16_config.format = AudioFormat::INT16;
AudioBuffer int16_buffer(int16_config);
// ... 填充int16_buffer ...
AudioBuffer float_buffer2 = int16_buffer.convert_format(AudioFormat::FLOAT32);
```
## 实时音频处理
### 处理回调设计
实时音频处理通常基于回调函数,以下是推荐的回调设计模式:
```cpp
// 音频处理回调函数类型
using AudioProcessCallback = std::function<void(
const AudioBuffer& input_buffer,
AudioBuffer& output_buffer,
void* user_data
)>;
// 在应用中实现回调
void my_audio_callback(const AudioBuffer& input, AudioBuffer& output, void* user_data) {
// 处理每个样本
for (uint32_t i = 0; i < input.frames(); ++i) {
for (uint16_t ch = 0; ch < input.channels(); ++ch) {
// 在这里执行音频处理
// 例如:应用增益
float sample = input.channel_data<float>(ch)[i];
output.channel_data<float>(ch)[i] = sample * 0.8f;
}
}
}
// 注册回调
audio_engine.set_process_callback(my_audio_callback, user_context);
```
重要的回调设计原则:
1. **效率**:回调必须高效执行,避免阻塞
2. **确定性**:处理时间应该可预测
3. **无分配**:不应在回调中分配/释放内存
4. **无锁**:避免使用互斥锁等阻塞操作
5. **无IO**避免文件、网络或其他IO操作
### 延迟考量
音频引擎中的延迟主要来源:
1. **缓冲区大小**:较大的缓冲区增加延迟
```cpp
// 计算缓冲区引入的延迟
double latency_ms = config.get_latency_ms();
```
2. **处理链延迟**:效果和处理算法可能引入延迟
3. **硬件延迟**:音频设备本身的延迟
延迟预算管理:
```cpp
// 低延迟场景游戏、VoIP
// 总延迟预算:<20ms
AudioConfig low_latency;
low_latency.sample_rate = 48000;
low_latency.frames_per_buffer = 256; // 5.33ms @ 48kHz
// 音乐制作场景
// 总延迟预算:<30ms
AudioConfig music_production;
music_production.sample_rate = 48000;
music_production.frames_per_buffer = 512; // 10.67ms @ 48kHz
// 流媒体场景
// 总延迟预算:<100ms
AudioConfig streaming;
streaming.sample_rate = 44100;
streaming.frames_per_buffer = 1024; // 23.22ms @ 44.1kHz
```
### 环形缓冲区
`RingBuffer`类为音频流提供线程安全的缓冲能力:
```cpp
// 创建环形缓冲区
RingBuffer<float> ring_buffer(48000); // 容量为48000样本
// 生产者线程(例如,音频捕获)
void producer_thread() {
float samples[256];
// ... 填充samples ...
// 写入环形缓冲区
size_t written = ring_buffer.write(samples, 256);
if (written < 256) {
// 缓冲区已满,处理溢出...
}
}
// 消费者线程(例如,音频回放)
void consumer_thread() {
float samples[256];
// 从环形缓冲区读取
size_t read = ring_buffer.read(samples, 256);
if (read < 256) {
// 缓冲区不足,处理饥饿...
}
// ... 处理samples ...
}
```
环形缓冲区关键操作:
```cpp
// 检查可用数据量
size_t available = ring_buffer.available();
// 检查可写空间
size_t space = ring_buffer.space();
// 清空缓冲区
ring_buffer.clear();
// 调整大小(会清空现有数据)
ring_buffer.resize(96000);
```
## 高级功能
### 多声道处理
处理多声道音频的技术:
1. **声道遍历**
```cpp
// 遍历所有声道
for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
float* channel_data = buffer.channel_data<float>(ch);
// 处理单个声道...
}
```
2. **声道操作**
```cpp
// 不同声道处理
float* left = buffer.channel_data<float>(0);
float* right = buffer.channel_data<float>(1);
for (uint32_t i = 0; i < buffer.frames(); ++i) {
// 左右声道处理不同
left[i] *= 0.8f; // 左声道衰减
right[i] *= 1.2f; // 右声道增益
}
```
3. **声道路由**
```cpp
// 2声道到5.1声道映射
void stereo_to_5point1(const AudioBuffer& stereo, AudioBuffer& surround) {
float* stereo_left = stereo.channel_data<float>(0);
float* stereo_right = stereo.channel_data<float>(1);
float* front_left = surround.channel_data<float>(0);
float* front_right = surround.channel_data<float>(1);
float* center = surround.channel_data<float>(2);
float* lfe = surround.channel_data<float>(3);
float* rear_left = surround.channel_data<float>(4);
float* rear_right = surround.channel_data<float>(5);
for (uint32_t i = 0; i < stereo.frames(); ++i) {
front_left[i] = stereo_left[i];
front_right[i] = stereo_right[i];
center[i] = (stereo_left[i] + stereo_right[i]) * 0.5f;
lfe[i] = (stereo_left[i] + stereo_right[i]) * 0.3f;
rear_left[i] = stereo_left[i] * 0.4f;
rear_right[i] = stereo_right[i] * 0.4f;
}
}
```
### 采样率转换
基本采样率转换:
```cpp
// 将48kHz转换为44.1kHz
AudioConfig src_config;
src_config.sample_rate = 48000;
src_config.channels = 2;
src_config.frames_per_buffer = 480; // 10ms @ 48kHz
AudioBuffer src_buffer(src_config);
// ... 填充src_buffer ...
// 执行转换
AudioBuffer dst_buffer = src_buffer.resample(44100);
// dst_buffer.frames() 约为 441 (10ms @ 44.1kHz)
```
注意:
1. 内置的resample方法使用简单的线性插值
2. 对于高质量转换,应考虑使用专业的重采样库
3. 降采样时,应先进行抗混叠滤波
### 音频混合
混合多个音频源:
```cpp
// 混合两个缓冲区
void mix_buffers(const AudioBuffer& buffer1,
const AudioBuffer& buffer2,
AudioBuffer& output,
float gain1 = 1.0f,
float gain2 = 1.0f) {
// 确保格式兼容
assert(buffer1.channels() == buffer2.channels());
assert(buffer1.format() == buffer2.format());
assert(buffer1.frames() == buffer2.frames());
// 准备输出缓冲区
if (output.empty() ||
output.channels() != buffer1.channels() ||
output.frames() != buffer1.frames()) {
output.allocate(buffer1.frames(), buffer1.channels(), buffer1.format());
}
// 混合每个声道
for (uint16_t ch = 0; ch < buffer1.channels(); ++ch) {
const float* in1 = buffer1.channel_data<float>(ch);
const float* in2 = buffer2.channel_data<float>(ch);
float* out = output.channel_data<float>(ch);
for (uint32_t i = 0; i < buffer1.frames(); ++i) {
out[i] = in1[i] * gain1 + in2[i] * gain2;
// 简单限制以防止削波
if (out[i] > 1.0f) out[i] = 1.0f;
if (out[i] < -1.0f) out[i] = -1.0f;
}
}
}
```
使用内置混合方法:
```cpp
// 假设已有两个缓冲区
AudioBuffer buffer1(config);
AudioBuffer buffer2(config);
// ... 填充buffer1和buffer2 ...
// 复制第一个缓冲区到输出
AudioBuffer output = buffer1.clone();
// 混合第二个缓冲区到输出应用0.8的增益
output.mix_from(buffer2, 0.8f);
```
## 性能优化
### 缓冲区大小选择
缓冲区大小是延迟和CPU使用率的权衡
| 缓冲区大小 | 延迟 (@48kHz) | CPU使用率 | 适用场景 |
|------------|--------------|-----------|----------|
| 64帧 | 1.33ms | 很高 | 乐器演奏,超低延迟要求 |
| 128帧 | 2.67ms | 高 | 游戏音效,语音通话 |
| 256帧 | 5.33ms | 中高 | 实时音乐应用 |
| 512帧 | 10.67ms | 中 | 音乐制作,多轨混音 |
| 1024帧 | 21.33ms | 低 | 音频渲染,流媒体 |
| 2048帧+ | 42.67ms+ | 很低 | 批量处理,非实时应用 |
选择策略:
```cpp
// 根据应用场景选择缓冲区大小
AudioConfig config;
config.sample_rate = 48000;
config.channels = 2;
config.format = AudioFormat::FLOAT32;
// 场景选择
enum class ApplicationType {
INSTRUMENT, // 实时乐器
GAME, // 游戏音效
MUSIC_CREATION, // 音乐制作
STREAMING, // 音频流
BATCH_PROCESS // 批处理
};
// 根据应用类型设置缓冲区大小
void configure_for_application(AudioConfig& config, ApplicationType type) {
switch (type) {
case ApplicationType::INSTRUMENT:
config.frames_per_buffer = 128;
break;
case ApplicationType::GAME:
config.frames_per_buffer = 256;
break;
case ApplicationType::MUSIC_CREATION:
config.frames_per_buffer = 512;
break;
case ApplicationType::STREAMING:
config.frames_per_buffer = 1024;
break;
case ApplicationType::BATCH_PROCESS:
config.frames_per_buffer = 4096;
break;
}
}
```
### SIMD加速
音频引擎集成了SIMD优化自动选择最佳实现
```cpp
// 使用SIMD优化的音频处理
#include "simd/audio_processing.h"
void apply_simd_processing(AudioBuffer& buffer) {
// 确保缓冲区是FLOAT32格式
if (buffer.format() != AudioFormat::FLOAT32) {
buffer = buffer.convert_format(AudioFormat::FLOAT32);
}
// 应用音量变化使用SIMD
for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
float* data = buffer.channel_data<float>(ch);
// 自动选择最佳SIMD实现
simd::CALL_SIMD_AUDIO_FUNCTION(
apply_gain_f32,
data, // 输入
0.8f, // 增益
data, // 输出(原地操作)
buffer.frames() // 样本数
);
}
}
```
SIMD优化的音频函数
- **音频混合**`mix_audio_f32``mix_audio_multi_f32`
- **音量控制**`apply_gain_f32``apply_gain_ramp_f32`
- **格式转换**`convert_i16_to_f32``convert_f32_to_i16`
- **向量操作**`vector_add_f32``vector_multiply_f32`
- **分析函数**`calculate_rms_f32``calculate_peak_f32`
### 内存管理
音频处理中的内存管理最佳实践:
1. **预分配缓冲区**
```cpp
// 在初始化时预分配所有缓冲区
AudioBuffer input_buffer(config);
AudioBuffer output_buffer(config);
AudioBuffer temp_buffer(config);
```
2. **重用缓冲区**
```cpp
// 重用同一缓冲区进行多次处理
void process_chain(AudioBuffer& buffer) {
// 所有处理原地进行,避免分配新内存
apply_gain(buffer);
apply_filter(buffer);
apply_effect(buffer);
}
```
3. **避免频繁分配/释放**
```cpp
// 错误示例:每次调用都创建临时缓冲区
void bad_process(const AudioBuffer& input) {
// 每次调用都分配新内存,造成内存碎片和性能下降
AudioBuffer temp(input.frames(), input.channels(), input.format());
// ...处理...
}
// 正确示例:使用成员变量保存缓冲区
class AudioProcessor {
private:
AudioBuffer temp_buffer_;
public:
void process(const AudioBuffer& input) {
// 只在需要时重新分配
if (temp_buffer_.empty() ||
temp_buffer_.frames() != input.frames() ||
temp_buffer_.channels() != input.channels()) {
temp_buffer_.allocate(input.frames(), input.channels(), input.format());
}
// ...处理...
}
};
```
4. **对齐内存**
```cpp
// AudioBuffer已经内部使用对齐内存
// 如果需要自定义分配使用AlignedBuffer
simd::AlignedBuffer<float, simd::ALIGNMENT_AVX> aligned_data(1024);
```
## 完整示例
### 音频播放器
以下是一个简单音频播放器的示例:
```cpp
#include "audio_buffer.h"
#include "simd/audio_processing.h"
#include <iostream>
#include <vector>
using namespace audio_backend;
class SimplePlayer {
private:
engine::AudioBuffer buffer_;
engine::AudioConfig config_;
size_t position_;
bool playing_;
float volume_;
public:
SimplePlayer() : position_(0), playing_(false), volume_(1.0f) {
// 设置默认配置
config_.sample_rate = 44100;
config_.channels = 2;
config_.format = engine::AudioFormat::FLOAT32;
config_.frames_per_buffer = 512;
}
// 加载音频数据
bool load_audio_data(const float* data, size_t frames, uint16_t channels) {
config_.frames_per_buffer = frames;
config_.channels = channels;
// 分配缓冲区并复制数据
buffer_.allocate(config_, true); // 交错格式
std::memcpy(buffer_.interleaved_data<float>(),
data,
frames * channels * sizeof(float));
position_ = 0;
return true;
}
// 开始播放
void play() {
playing_ = true;
}
// 暂停播放
void pause() {
playing_ = false;
}
// 停止播放并重置位置
void stop() {
playing_ = false;
position_ = 0;
}
// 设置音量
void set_volume(float volume) {
volume_ = volume;
}
// 处理回调用于音频API回调
void process(float* output, size_t frames) {
if (!playing_ || buffer_.empty()) {
// 如果没在播放或无数据,输出静音
std::memset(output, 0, frames * config_.channels * sizeof(float));
return;
}
// 计算可用帧数
size_t available_frames = buffer_.frames() - position_;
size_t frames_to_copy = std::min(available_frames, frames);
if (frames_to_copy > 0) {
// 复制音频数据
const float* input = buffer_.interleaved_data<float>() +
position_ * config_.channels;
std::memcpy(output, input, frames_to_copy * config_.channels * sizeof(float));
// 应用音量
simd::CALL_SIMD_AUDIO_FUNCTION(
apply_gain_f32,
output, // 输入
volume_, // 增益
output, // 输出
frames_to_copy * config_.channels // 样本数
);
position_ += frames_to_copy;
}
// 如果需要,用静音填充剩余部分
if (frames_to_copy < frames) {
std::memset(
output + frames_to_copy * config_.channels,
0,
(frames - frames_to_copy) * config_.channels * sizeof(float)
);
// 如果到达末尾,循环或停止
if (position_ >= buffer_.frames()) {
// 这里实现循环播放
position_ = 0;
// 或停止播放
// playing_ = false;
}
}
}
// 获取当前状态
bool is_playing() const { return playing_; }
float get_volume() const { return volume_; }
size_t get_position() const { return position_; }
size_t get_duration() const { return buffer_.frames(); }
};
// 使用示例
int main() {
// 创建播放器
SimplePlayer player;
// 生成测试音频数据1秒的440Hz正弦波
const size_t sample_rate = 44100;
const size_t frames = sample_rate;
const uint16_t channels = 2;
std::vector<float> test_data(frames * channels);
for (size_t i = 0; i < frames; ++i) {
float sample = 0.5f * std::sin(2.0f * 3.14159f * 440.0f * i / sample_rate);
for (uint16_t c = 0; c < channels; ++c) {
test_data[i * channels + c] = sample;
}
}
// 加载音频数据
player.load_audio_data(test_data.data(), frames, channels);
// 设置音量并播放
player.set_volume(0.8f);
player.play();
// 在实际应用中这里会连接到音频API的回调
// 示例:创建一个输出缓冲区并处理一些帧
const size_t buffer_size = 512;
std::vector<float> output_buffer(buffer_size * channels);
std::cout << "开始播放..." << std::endl;
// 模拟处理多个缓冲区
for (size_t i = 0; i < 10; ++i) {
player.process(output_buffer.data(), buffer_size);
// 在实际应用中,这里会将数据发送到音频设备
std::cout << "处理缓冲区 " << i << ", 位置: "
<< player.get_position() << "/" << player.get_duration() << std::endl;
}
// 暂停播放
player.pause();
std::cout << "播放已暂停" << std::endl;
// 停止并重置
player.stop();
std::cout << "播放已停止" << std::endl;
return 0;
}
```
### 实时处理器
以下是一个实时音频处理器示例:
```cpp
#include "audio_buffer.h"
#include "simd/audio_processing.h"
#include <iostream>
#include <vector>
#include <array>
using namespace audio_backend;
// 简单的延迟效果处理器
class DelayProcessor {
private:
engine::AudioConfig config_;
std::vector<float> delay_buffer_;
size_t delay_length_; // 延迟长度(样本)
size_t write_pos_; // 写位置
float feedback_; // 反馈量
float dry_mix_; // 干信号混合比例
float wet_mix_; // 湿信号混合比例
public:
DelayProcessor(uint32_t sample_rate = 44100,
uint16_t channels = 2,
float delay_time_ms = 500.0f,
float feedback = 0.3f,
float dry_mix = 0.7f,
float wet_mix = 0.3f)
: delay_length_(static_cast<size_t>(sample_rate * delay_time_ms / 1000.0f)),
write_pos_(0),
feedback_(feedback),
dry_mix_(dry_mix),
wet_mix_(wet_mix) {
// 设置配置
config_.sample_rate = sample_rate;
config_.channels = channels;
config_.format = engine::AudioFormat::FLOAT32;
config_.frames_per_buffer = 512; // 默认值
// 分配延迟缓冲区(每个声道一个)
delay_buffer_.resize(delay_length_ * channels, 0.0f);
}
// 设置延迟时间
void set_delay_time(float delay_time_ms) {
size_t new_delay_length = static_cast<size_t>(
config_.sample_rate * delay_time_ms / 1000.0f);
if (new_delay_length != delay_length_) {
delay_length_ = new_delay_length;
delay_buffer_.resize(delay_length_ * config_.channels, 0.0f);
write_pos_ = 0;
}
}
// 设置反馈量
void set_feedback(float feedback) {
feedback_ = feedback;
}
// 设置混合比例
void set_mix(float dry_mix, float wet_mix) {
dry_mix_ = dry_mix;
wet_mix_ = wet_mix;
}
// 处理音频
void process(engine::AudioBuffer& buffer) {
// 确保格式正确
if (buffer.format() != engine::AudioFormat::FLOAT32) {
throw std::runtime_error("DelayProcessor只支持FLOAT32格式");
}
// 更新配置(如果必要)
if (buffer.channels() != config_.channels ||
buffer.sample_rate() != config_.sample_rate) {
config_.channels = buffer.channels();
config_.sample_rate = buffer.sample_rate();
delay_buffer_.resize(delay_length_ * config_.channels, 0.0f);
}
// 创建临时缓冲区用于原始输入
engine::AudioBuffer input_copy = buffer.clone();
// 对每一帧进行处理
for (uint32_t i = 0; i < buffer.frames(); ++i) {
for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
// 读取输入样本
float input_sample = input_copy.channel_data<float>(ch)[i];
// 计算延迟缓冲区读取位置
size_t read_pos = (write_pos_ - delay_length_ * config_.channels +
ch + delay_buffer_.size()) % delay_buffer_.size();
// 获取延迟样本
float delayed_sample = delay_buffer_[read_pos];
// 计算输出样本(干/湿混合)
float output_sample = input_sample * dry_mix_ + delayed_sample * wet_mix_;
buffer.channel_data<float>(ch)[i] = output_sample;
// 更新延迟缓冲区(输入 + 反馈)
delay_buffer_[(write_pos_ + ch) % delay_buffer_.size()] =
input_sample + delayed_sample * feedback_;
}
// 更新写入位置
write_pos_ = (write_pos_ + config_.channels) % delay_buffer_.size();
}
}
};
// 使用示例
int main() {
// 创建音频配置
engine::AudioConfig config;
config.sample_rate = 44100;
config.channels = 2;
config.format = engine::AudioFormat::FLOAT32;
config.frames_per_buffer = 512;
// 创建延迟处理器
DelayProcessor delay_processor(
config.sample_rate,
config.channels,
300.0f, // 300ms延迟
0.4f, // 40%反馈
0.6f, // 60%干信号
0.4f // 40%湿信号
);
// 创建测试音频数据
engine::AudioBuffer test_buffer(config);
// 生成测试音频440Hz正弦波逐渐衰减
for (uint32_t i = 0; i < test_buffer.frames(); ++i) {
float amplitude = 0.8f * (1.0f - static_cast<float>(i) / test_buffer.frames());
float sample = amplitude * std::sin(2.0f * 3.14159f * 440.0f * i / config.sample_rate);
for (uint16_t ch = 0; ch < test_buffer.channels(); ++ch) {
test_buffer.channel_data<float>(ch)[i] = sample;
}
}
std::cout << "原始音频峰值: " <<
simd::CALL_SIMD_AUDIO_FUNCTION(
calculate_peak_f32,
test_buffer.channel_data<float>(0),
test_buffer.frames()
) << std::endl;
// 处理音频
delay_processor.process(test_buffer);
std::cout << "处理后音频峰值: " <<
simd::CALL_SIMD_AUDIO_FUNCTION(
calculate_peak_f32,
test_buffer.channel_data<float>(0),
test_buffer.frames()
) << std::endl;
// 改变处理参数再次处理
delay_processor.set_delay_time(500.0f); // 500ms延迟
delay_processor.set_feedback(0.6f); // 60%反馈
delay_processor.set_mix(0.5f, 0.5f); // 50/50混合
delay_processor.process(test_buffer);
std::cout << "再次处理后音频峰值: " <<
simd::CALL_SIMD_AUDIO_FUNCTION(
calculate_peak_f32,
test_buffer.channel_data<float>(0),
test_buffer.frames()
) << std::endl;
return 0;
}
```
### 格式转换器
以下是一个音频格式转换器示例:
```cpp
#include "audio_buffer.h"
#include "simd/audio_processing.h"
#include <iostream>
#include <iomanip>
#include <chrono>
using namespace audio_backend;
// 音频格式转换器类
class FormatConverter {
public:
// 转换采样率
static engine::AudioBuffer convert_sample_rate(
const engine::AudioBuffer& input,
uint32_t new_sample_rate) {
return input.resample(new_sample_rate);
}
// 转换格式
static engine::AudioBuffer convert_format(
const engine::AudioBuffer& input,
engine::AudioFormat new_format) {
return input.convert_format(new_format);
}
// 转换声道数(简单混合/复制)
static engine::AudioBuffer convert_channels(
const engine::AudioBuffer& input,
uint16_t new_channels) {
if (input.channels() == new_channels) {
return input.clone();
}
// 创建新的缓冲区
engine::AudioConfig new_config = input.config();
new_config.channels = new_channels;
engine::AudioBuffer output(new_config, input.is_interleaved());
if (input.channels() == 1 && new_channels > 1) {
// 单声道到多声道:复制到所有声道
const float* mono = input.channel_data<float>(0);
for (uint16_t ch = 0; ch < new_channels; ++ch) {
float* out = output.channel_data<float>(ch);
std::memcpy(out, mono, input.frames() * sizeof(float));
}
}
else if (input.channels() > 1 && new_channels == 1) {
// 多声道到单声道:混合所有声道
float* mono = output.channel_data<float>(0);
std::memset(mono, 0, output.frames() * sizeof(float));
float scale = 1.0f / input.channels();
for (uint16_t ch = 0; ch < input.channels(); ++ch) {
const float* in = input.channel_data<float>(ch);
for (uint32_t i = 0; i < input.frames(); ++i) {
mono[i] += in[i] * scale;
}
}
}
else if (input.channels() > new_channels) {
// 多声道到少声道保留前N个声道
for (uint16_t ch = 0; ch < new_channels; ++ch) {
float* out = output.channel_data<float>(ch);
const float* in = input.channel_data<float>(ch);
std::memcpy(out, in, input.frames() * sizeof(float));
}
}
else {
// 少声道到多声道复制现有声道其余设为0
for (uint16_t ch = 0; ch < input.channels(); ++ch) {
float* out = output.channel_data<float>(ch);
const float* in = input.channel_data<float>(ch);
std::memcpy(out, in, input.frames() * sizeof(float));
}
for (uint16_t ch = input.channels(); ch < new_channels; ++ch) {
float* out = output.channel_data<float>(ch);
std::memset(out, 0, output.frames() * sizeof(float));
}
}
return output;
}
// 完整转换
static engine::AudioBuffer convert(
const engine::AudioBuffer& input,
uint32_t new_sample_rate,
uint16_t new_channels,
engine::AudioFormat new_format) {
// 按顺序执行转换
engine::AudioBuffer temp = input;
// 先转换采样率
if (new_sample_rate != input.sample_rate()) {
temp = convert_sample_rate(temp, new_sample_rate);
}
// 再转换声道数
if (new_channels != temp.channels()) {
temp = convert_channels(temp, new_channels);
}
// 最后转换格式
if (new_format != temp.format()) {
temp = convert_format(temp, new_format);
}
return temp;
}
};
// 使用示例
int main() {
// 创建测试音频数据
engine::AudioConfig source_config;
source_config.sample_rate = 48000;
source_config.channels = 2;
source_config.format = engine::AudioFormat::FLOAT32;
source_config.frames_per_buffer = 1000;
engine::AudioBuffer source_buffer(source_config);
// 生成测试音频数据
for (uint16_t ch = 0; ch < source_buffer.channels(); ++ch) {
float* data = source_buffer.channel_data<float>(ch);
for (uint32_t i = 0; i < source_buffer.frames(); ++i) {
data[i] = 0.5f * std::sin(2.0f * 3.14159f * 440.0f * i / source_config.sample_rate);
}
}
std::cout << "源音频配置:" << std::endl;
std::cout << " 采样率: " << source_buffer.sample_rate() << " Hz" << std::endl;
std::cout << " 声道数: " << source_buffer.channels() << std::endl;
std::cout << " 格式: " << engine::get_format_name(source_buffer.format()) << std::endl;
std::cout << " 帧数: " << source_buffer.frames() << std::endl;
std::cout << " 大小: " << source_buffer.size_bytes() << " 字节" << std::endl;
// 测量格式转换性能
auto start = std::chrono::high_resolution_clock::now();
// 转换到不同格式
engine::AudioBuffer int16_buffer = FormatConverter::convert_format(
source_buffer, engine::AudioFormat::INT16);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\n转换到INT16:" << std::endl;
std::cout << " 大小: " << int16_buffer.size_bytes() << " 字节" << std::endl;
std::cout << " 转换时间: " << duration.count() << " 微秒" << std::endl;
// 转换到单声道
start = std::chrono::high_resolution_clock::now();
engine::AudioBuffer mono_buffer = FormatConverter::convert_channels(
source_buffer, 1);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\n转换到单声道:" << std::endl;
std::cout << " 声道数: " << mono_buffer.channels() << std::endl;
std::cout << " 转换时间: " << duration.count() << " 微秒" << std::endl;
// 转换到44.1kHz
start = std::chrono::high_resolution_clock::now();
engine::AudioBuffer resampled_buffer = FormatConverter::convert_sample_rate(
source_buffer, 44100);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\n转换到44.1kHz:" << std::endl;
std::cout << " 采样率: " << resampled_buffer.sample_rate() << " Hz" << std::endl;
std::cout << " 帧数: " << resampled_buffer.frames() << std::endl;
std::cout << " 转换时间: " << duration.count() << " 微秒" << std::endl;
// 完整转换
start = std::chrono::high_resolution_clock::now();
engine::AudioBuffer converted_buffer = FormatConverter::convert(
source_buffer,
44100, // 新采样率
1, // 新声道数
engine::AudioFormat::INT16 // 新格式
);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\n完整转换:" << std::endl;
std::cout << " 采样率: " << converted_buffer.sample_rate() << " Hz" << std::endl;
std::cout << " 声道数: " << converted_buffer.channels() << std::endl;
std::cout << " 格式: " << engine::get_format_name(converted_buffer.format()) << std::endl;
std::cout << " 帧数: " << converted_buffer.frames() << std::endl;
std::cout << " 大小: " << converted_buffer.size_bytes() << " 字节" << std::endl;
std::cout << " 总转换时间: " << duration.count() << " 微秒" << std::endl;
return 0;
}
```
## 跨平台考虑
音频引擎设计为跨平台工作,但在不同平台上仍有一些考虑因素:
### Windows 平台
- 内存对齐Windows API提供`_aligned_malloc`/`_aligned_free`
- SIMD支持广泛支持SSE/AVX系列指令集
- 编译器MSVC对SIMD有良好支持但语法与GCC/Clang有差异
```cpp
#ifdef _WIN32
// Windows特定代码
#include <malloc.h>
void* aligned_memory = _aligned_malloc(size, alignment);
_aligned_free(aligned_memory);
#endif
```
### Linux 平台
- 内存对齐POSIX API提供`posix_memalign`
- SIMD支持现代发行版广泛支持但较老系统可能不支持AVX+
- 编译器GCC/Clang支持丰富的SIMD内联汇编
```cpp
#ifdef __linux__
// Linux特定代码
void* aligned_memory = nullptr;
if (posix_memalign(&aligned_memory, alignment, size) != 0) {
// 错误处理
}
free(aligned_memory);
#endif
```
### macOS 平台
- 内存对齐POSIX API同Linux
- SIMD支持Intel Mac支持SSE/AVXApple Silicon支持NEON
- 编译器Clang默认编译器苹果特定扩展
```cpp
#ifdef __APPLE__
// macOS特定代码
#include <TargetConditionals.h>
#if TARGET_CPU_ARM64
// Apple SiliconARM代码
// 使用NEON指令
#else
// Intel Mac代码
// 使用SSE/AVX指令
#endif
#endif
```
跨平台构建策略:
1. **统一接口**AudioBuffer提供统一接口隐藏平台差异
2. **运行时检测**使用CPU特性检测选择适当实现
3. **条件编译**:为特定平台提供优化实现
4. **内存管理抽象**使用AlignedBuffer隐藏平台特定内存管理
```cpp
// 跨平台音频处理示例
void process_audio_cross_platform(engine::AudioBuffer& buffer) {
// 使用通用接口,内部会选择最佳平台特定实现
for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
float* data = buffer.channel_data<float>(ch);
// 自动选择最佳实现SSE/AVX/NEON/标量)
simd::CALL_SIMD_AUDIO_FUNCTION(
apply_gain_f32,
data,
0.8f,
data,
buffer.frames()
);
}
}