28 KiB
音频引擎API参考
目录
概述
音频引擎模块是音频后端系统的核心组件,负责高效处理和管理音频数据。该模块采用SIMD优化设计,支持多种音频格式和声道配置,并提供线程安全的音频流处理功能。
核心特性:
- 支持多种音频格式(16/24/32位整数,32/64位浮点数)
- 支持交错和非交错(平面)音频数据布局
- SIMD指令集优化(SSE/AVX/AVX-512/NEON)
- 零拷贝数据传输
- 线程安全的环形缓冲区实现
- 高性能混音和格式转换
核心类型
AudioFormat
AudioFormat枚举定义了系统支持的音频采样格式。
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] | 高精度计算,避免累积误差 |
辅助函数:
// 获取音频格式的字节大小
size_t get_format_byte_size(AudioFormat format);
// 获取音频格式名称
const char* get_format_name(AudioFormat format);
AudioConfig
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;
// 比较操作符
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(): 计算基于当前缓冲区大小和采样率的理论处理延迟,单位毫秒
常见配置示例:
// 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是音频引擎的核心类,用于存储和处理音频数据。它支持交错和非交错(平面)格式,并提供各种音频处理功能。
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支持两种内存布局:
-
交错格式 (Interleaved): 样本按帧组织,每个帧包含所有声道的样本。布局为:
LRLRLRLR...(立体声)内存布局:[L0 R0 L1 R1 L2 R2 ... Ln Rn] -
非交错格式 (Non-interleaved/Planar): 样本按声道组织,每个声道的样本连续存储。布局为:
LLLL...RRRR...(立体声)内存布局:[L0 L1 L2 ... Ln R0 R1 R2 ... Rn]
选择合适的布局:
-
交错格式适合:
- 与传统音频API集成(大多数API使用交错格式)
- 顺序访问所有声道(如文件I/O或网络传输)
-
非交错格式适合:
- SIMD向量化处理(可以处理单个声道的连续样本)
- 需要单独处理声道的场景(如中置声道独立处理)
- 复杂的DSP算法实现
格式转换
AudioBuffer提供了多种格式转换功能:
// 转换内存布局
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]范围将映射到相应整数格式的最大范围
- 较低位深度到较高位深度转换:保留原有精度,向上扩展
- 较高位深度到较低位深度转换:会损失精度,可能引入截断和量化错误
- 重采样操作会改变缓冲区大小,但声道数和格式保持不变
混音和增益
// 应用增益(音量调整)
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实现了两种处理策略:
- 限幅 (Clipping):将超出范围的值限制在有效范围内
- 软限幅 (Soft Clipping):应用非线性曲线,在接近极限值时逐渐压缩动态范围
环形缓冲区
RingBuffer类
RingBuffer是一个模板类,用于实时音频流处理,提供线程安全的生产者-消费者模型。
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)确保多线程正确性
并发模型:
- 一个线程作为生产者(写入数据)
- 一个线程作为消费者(读取数据)
- 生产者和消费者可以独立运行,不需要额外同步
// 生产者线程代码
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));
}
}
}
实现示例
基本音频处理
以下示例展示了基本的音频处理流程:
#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实现实时音频流处理:
#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进行多声道混音处理:
#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() {
// 创建混音器(48kHz,512帧缓冲)
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个样本
// 源1:440Hz正弦波
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; // 立体声相同
}
// 源2:880Hz正弦波
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函数示例:
// 不同指令集的实现示例(仅示意)
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指令的性能:
// 对齐的内存分配
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)对对齐的要求更严格
零拷贝技术
系统使用多种技术最小化不必要的内存复制:
-
移动语义:使用C++移动构造函数和移动赋值运算符避免不必要的复制
// 移动构造和赋值 AudioBuffer(AudioBuffer&& other) noexcept; AudioBuffer& operator=(AudioBuffer&& other) noexcept; -
引用传递:通过引用传递大型缓冲区,而不是通过值传递
// 通过引用传递大型缓冲区 void process_audio(const AudioBuffer& input, AudioBuffer& output); -
原位处理:尽可能在原地修改数据,避免创建临时缓冲区
// 原位增益应用(不创建新缓冲区) 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
字节序
在处理原始音频数据时需考虑字节序(尤其是整数格式):
- 大多数音频格式要求特定字节序(通常为小端序)
- 跨平台时需确保一致的字节序处理