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

42 KiB
Raw Permalink Blame History

音频引擎使用指南

目录

概述

音频引擎是Audio Backend系统的核心组件提供了高性能、低延迟的音频处理功能。音频引擎的主要目标是提供统一的音频缓冲区管理、音频格式转换和实时音频处理能力同时通过SIMD指令集优化提供卓越的性能。

核心功能:

  • 高性能音频缓冲区:支持多种格式、对齐内存和零拷贝操作
  • 格式转换:在不同音频格式之间无缝转换
  • 实时处理:低延迟音频处理,适用于实时应用
  • 多声道支持:灵活的声道配置,支持交错和非交错格式
  • SIMD优化利用现代CPU的SIMD指令集加速音频处理

音频引擎架构:

┌─────────────────────┐
│   应用程序          │
└───────────┬─────────┘
            │
┌───────────▼─────────┐
│   音频引擎接口      │
└───────────┬─────────┘
            │
┌───────────▼─────────┐
│   音频缓冲区管理    │◄────┐
└───────────┬─────────┘     │
            │               │
┌───────────▼─────────┐     │
│   格式转换          │     │
└───────────┬─────────┘     │
            │               │
┌───────────▼─────────┐     │
│   实时处理          │     │
└───────────┬─────────┘     │
            │               │
┌───────────▼─────────┐     │
│   SIMD优化          │─────┘
└─────────────────────┘

音频配置与格式

音频格式

音频引擎支持多种常见的音频格式,适用于不同的场景和需求:

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] 极高 精确计算、主音频总线

获取格式字节大小:

// 获取音频格式的字节大小
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结构包含了所有音频处理所需的基本配置参数:

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. 低延迟实时处理

    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. 高质量音频处理

    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. 多声道环绕声

    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. 网络流传输

    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类是音频引擎的核心,提供了灵活的音频数据管理:

// 创建音频缓冲区
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);   // 交错格式

基本操作:

// 清空缓冲区(填充零)
buffer.clear();

// 重新分配缓冲区
buffer.allocate(1024, 2, AudioFormat::FLOAT32, false);

// 释放内存
buffer.release();

内存对齐与SIMD优化

音频引擎使用内存对齐技术确保SIMD指令能高效执行

// 检查缓冲区是否对齐
if (buffer.is_aligned()) {
    // 可以安全地使用SIMD指令
    // ...
} else {
    // 回退到非SIMD版本
    // ...
}

AudioBuffer内部使用AlignedBuffer确保内存按SIMD要求对齐

// AudioBuffer内部实现片段
simd::AlignedBuffer<uint8_t, simd::ALIGNMENT_AVX> data_;

交错与非交错格式

音频引擎支持两种主要的数据布局:

  1. 交错格式LRLRLR...

    • 优点:缓存友好,适合顺序访问
    • 缺点:单声道处理不方便
    • 适用音频文件IO硬件接口
  2. 非交错格式LLLL...RRRR...

    • 优点:单声道处理方便
    • 缺点:多声道同时处理效率较低
    • 适用单声道效果处理某些DSP算法

示例:

// 创建交错格式缓冲区
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; // 右声道第一个样本

格式转换:

// 交错格式转换为非交错格式
AudioBuffer non_interleaved = interleaved_buffer.to_non_interleaved();

// 非交错格式转换为交错格式
AudioBuffer interleaved = non_interleaved_buffer.to_interleaved();

格式转换

音频引擎支持在不同格式之间无缝转换:

// 从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);

实时音频处理

处理回调设计

实时音频处理通常基于回调函数,以下是推荐的回调设计模式:

// 音频处理回调函数类型
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. 缓冲区大小:较大的缓冲区增加延迟

    // 计算缓冲区引入的延迟
    double latency_ms = config.get_latency_ms();
    
  2. 处理链延迟:效果和处理算法可能引入延迟

  3. 硬件延迟:音频设备本身的延迟

延迟预算管理:

// 低延迟场景游戏、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类为音频流提供线程安全的缓冲能力:

// 创建环形缓冲区
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 ...
}

环形缓冲区关键操作:

// 检查可用数据量
size_t available = ring_buffer.available();

// 检查可写空间
size_t space = ring_buffer.space();

// 清空缓冲区
ring_buffer.clear();

// 调整大小(会清空现有数据)
ring_buffer.resize(96000);

高级功能

多声道处理

处理多声道音频的技术:

  1. 声道遍历

    // 遍历所有声道
    for (uint16_t ch = 0; ch < buffer.channels(); ++ch) {
        float* channel_data = buffer.channel_data<float>(ch);
        // 处理单个声道...
    }
    
  2. 声道操作

    // 不同声道处理
    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. 声道路由

    // 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;
        }
    }
    

采样率转换

基本采样率转换:

// 将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. 降采样时,应先进行抗混叠滤波

音频混合

混合多个音频源:

// 混合两个缓冲区
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;
        }
    }
}

使用内置混合方法:

// 假设已有两个缓冲区
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+ 很低 批量处理,非实时应用

选择策略:

// 根据应用场景选择缓冲区大小
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优化自动选择最佳实现

// 使用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_f32mix_audio_multi_f32
  • 音量控制apply_gain_f32apply_gain_ramp_f32
  • 格式转换convert_i16_to_f32convert_f32_to_i16
  • 向量操作vector_add_f32vector_multiply_f32
  • 分析函数calculate_rms_f32calculate_peak_f32

内存管理

音频处理中的内存管理最佳实践:

  1. 预分配缓冲区

    // 在初始化时预分配所有缓冲区
    AudioBuffer input_buffer(config);
    AudioBuffer output_buffer(config);
    AudioBuffer temp_buffer(config);
    
  2. 重用缓冲区

    // 重用同一缓冲区进行多次处理
    void process_chain(AudioBuffer& buffer) {
        // 所有处理原地进行,避免分配新内存
        apply_gain(buffer);
        apply_filter(buffer);
        apply_effect(buffer);
    }
    
  3. 避免频繁分配/释放

    // 错误示例:每次调用都创建临时缓冲区
    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. 对齐内存

    // AudioBuffer已经内部使用对齐内存
    // 如果需要自定义分配使用AlignedBuffer
    simd::AlignedBuffer<float, simd::ALIGNMENT_AVX> aligned_data(1024);
    

完整示例

音频播放器

以下是一个简单音频播放器的示例:

#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;
}

实时处理器

以下是一个实时音频处理器示例:

#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;
}

格式转换器

以下是一个音频格式转换器示例:

#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有差异
#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内联汇编
#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默认编译器苹果特定扩展
#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隐藏平台特定内存管理
// 跨平台音频处理示例
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()
        );
    }
}