调音组件
简介
ACOMP Tuner 是 ARCS SDK 的音频调音组件,提供 EQ(均衡器)、DRC(动态范围压缩)和 Limiter(限幅器)等音频处理功能。该组件支持采样率配置、调音参数设置、限幅器参数设置和音量调节,音频数据通过双向流通道(M2R 输入 / R2M 输出)与 AP 核算法引擎交互。
主要特性
EQ/DRC/Limiter:支持均衡器、动态范围压缩和限幅器音频处理
采样率配置:支持设置音频采样率
调音参数设置:支持自定义 EQ/DRC 调音参数
限幅器参数设置:支持独立配置限幅器参数
音量控制:支持设置输出音量系数
使能控制:支持动态开启/关闭调音处理
双向音频流:支持 M2R(输入原始音频)和 R2M(输出处理后音频)双向流通道
事件回调机制:支持状态变更和数据流更新事件通知
跨核通信:基于 IPC 机制实现音频数据的跨核传输
配置选项
基本配置
配置项 |
说明 |
默认值 |
|---|---|---|
|
启用 ACOMP 组件 |
n |
|
启用 ACOMP 组件的调音组件 |
n |
流通道配置
配置项 |
说明 |
默认值 |
|---|---|---|
|
流缓冲区大小(字节) |
2560 |
|
流描述符数量 |
16 |
快速开始
1. 启用组件
在项目的 prj.conf 文件中添加:
# 启用 ACOMP 组件
CONFIG_ACOMP=y
# 启用 ACOMP 组件的调音组件
CONFIG_ACOMP_TUNER=y
2. 初始化调音组件
#include "acomp.h"
#include "tuner/acomp_tuner.h"
int main(int argc, char **argv)
{
// 初始化 ACOMP 框架
acomp_init();
// 初始化调音组件
int ret = acomp_tuner_init();
if (ret != ACOMP_ERR_OK) {
printf("Tuner init failed: %d\n", ret);
return -1;
}
return 0;
}
3. 注册事件回调
#include "tuner/acomp_tuner.h"
void tuner_event_handler(uint32_t event, void *event_data,
uint32_t event_data_len, void *priv)
{
if (event & TUNER_CB_EVENT_STATUS) {
uint32_t status = *(uint32_t *)event_data;
printf("Tuner status: %u\n", status);
} else if (event & TUNER_CB_EVENT_STREAM_UPDATE) {
// 有新的处理后音频数据可读
printf("Tuner stream update\n");
}
}
// 注册回调
int ret = acomp_tuner_add_callback(
TUNER_CB_EVENT_STATUS | TUNER_CB_EVENT_STREAM_UPDATE,
tuner_event_handler,
NULL
);
4. 启动调音服务
void start_tuner_service(void)
{
int ret;
// 1. 启动调音组件
ret = acomp_tuner_start();
if (ret != ACOMP_ERR_OK) {
printf("Tuner start failed: %d\n", ret);
return;
}
// 2. 设置采样率
acomp_tuner_set_samplerate(16000.0f);
// 3. 使能调音处理
acomp_tuner_enable(1);
printf("Tuner service started\n");
}
void stop_tuner_service(void)
{
// 1. 关闭调音处理
acomp_tuner_enable(0);
// 2. 停止调音组件
acomp_tuner_stop();
// 3. 清理资源
acomp_tuner_cleanup();
}
5. 创建双向音频流通道
#include "tuner/acomp_tuner.h"
#define TX_CH_INDEX 0
#define RX_CH_INDEX 1
void setup_tuner_streams(void)
{
// 创建 M2R 流通道(输入原始音频)
acomp_stream_chn_create_desc_t tx_desc = {
.cname = "stream.tuner_in",
.direction = ACOMP_STREAM_DIRECTION_M2R,
.index = TX_CH_INDEX,
.buffer_size = CONFIG_ACOMP_TUNER_STREAM_BUFFER_SIZE,
.num_descs = CONFIG_ACOMP_TUNER_STREAM_NUM_DESCS,
.kick_policy = 1,
};
acomp_tuner_stream_ch_enable(TX_CH_INDEX, &tx_desc);
// 创建 R2M 流通道(输出处理后音频)
acomp_stream_chn_create_desc_t rx_desc = {
.cname = "stream.tuner_out",
.direction = ACOMP_STREAM_DIRECTION_R2M,
.index = RX_CH_INDEX,
.buffer_size = CONFIG_ACOMP_TUNER_STREAM_BUFFER_SIZE,
.num_descs = CONFIG_ACOMP_TUNER_STREAM_NUM_DESCS,
.kick_policy = 1,
};
acomp_tuner_stream_ch_enable(RX_CH_INDEX, &rx_desc);
}
6. 发送音频数据并接收处理结果
void send_audio_to_tuner(uint8_t *audio_data, uint32_t audio_len)
{
uint8_t *buffer;
uint32_t buf_size;
uint16_t desc_idx;
// 分配发送缓冲区
buffer = acomp_tuner_stream_tx_buffer_alloc(TX_CH_INDEX, &buf_size, &desc_idx);
if (buffer && buf_size > 0) {
memcpy(buffer, audio_data, audio_len);
acomp_tuner_stream_tx_buffer_submit(TX_CH_INDEX, buffer, audio_len, desc_idx);
}
}
void receive_processed_audio(void)
{
uint8_t *buffer;
uint32_t len;
uint16_t desc_idx;
// 获取处理后的音频数据
buffer = acomp_tuner_stream_rx_buffer_get(RX_CH_INDEX, &len, &desc_idx);
if (buffer && len > 0) {
// 播放或转发处理后的音频
// play_audio(buffer, len);
// 释放缓冲区
acomp_tuner_stream_rx_buffer_release(RX_CH_INDEX, desc_idx, len, buffer);
}
}
API 参考
生命周期管理
acomp_tuner_init
int acomp_tuner_init(void);
功能:初始化调音组件
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:组件已初始化ACOMP_ERR_NOT_FOUND:设备未找到ACOMP_ERR_CREATE_STREAM_FAILED:创建流失败
acomp_tuner_start
int acomp_tuner_start(void);
功能:启动调音组件
说明:启动后才能使能调音处理或进行流数据交互
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_stop
int acomp_tuner_stop(void);
功能:停止调音组件
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_cleanup
int acomp_tuner_cleanup(void);
功能:清理调音组件资源,注销 IPC 回调并释放流对象及回调链表
说明:若组件尚未初始化,调用该函数也会直接返回成功
返回值:
ACOMP_ERR_OK:成功
参数配置
acomp_tuner_enable
int acomp_tuner_enable(uint8_t en);
功能:使能或关闭调音处理
参数:
en:使能开关,0表示关闭,非0表示开启
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_set_samplerate
int acomp_tuner_set_samplerate(float sr);
功能:设置采样率
参数:
sr:采样率,单位 Hz
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_set_param
int acomp_tuner_set_param(void *param, uint32_t len);
功能:设置调音参数(EQ/DRC 参数)
参数:
param:参数数据缓冲区指针len:参数数据长度(字节)
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_set_limiter
int acomp_tuner_set_limiter(void *param, uint32_t len);
功能:设置限幅器参数
参数:
param:限幅器参数数据缓冲区指针len:限幅器参数数据长度(字节)
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_set_volume
int acomp_tuner_set_volume(float vol);
功能:设置输出音量
参数:
vol:音量系数
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
事件回调
acomp_tuner_add_callback
int acomp_tuner_add_callback(uint32_t events, tuner_event_cb_t cb, void *priv);
功能:添加事件回调函数
参数:
events:事件位掩码,可同时注册多个事件TUNER_CB_EVENT_STATUS:状态变更通知,event_data指向uint32_t状态值TUNER_CB_EVENT_STREAM_UPDATE:数据流更新通知,event_data指向acomp_stream_channel_t
cb:回调函数指针priv:回调函数的私有数据指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_NO_MEM:内存不足ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_remove_callback
int acomp_tuner_remove_callback(tuner_event_cb_t cb);
功能:移除回调函数
参数:
cb:待移除的回调函数
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
音频流管理
acomp_tuner_stream_ch_enable
int acomp_tuner_stream_ch_enable(int chn, acomp_stream_chn_create_desc_t *desc);
功能:使能流通道
参数:
chn:通道索引desc:通道描述符指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误ACOMP_ERR_CREATE_STREAM_FAILED:创建流失败
acomp_tuner_stream_ch_disable
int acomp_tuner_stream_ch_disable(int chn);
功能:禁用流通道
参数:
chn:通道索引
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态ACOMP_ERR_INVALID_ARG:参数错误
acomp_tuner_stream_tx_buffer_alloc
void *acomp_tuner_stream_tx_buffer_alloc(int chn, uint32_t *len, uint16_t *desc_idx);
功能:分配 TX 流缓冲区用于向 AP 核发送音频数据
参数:
chn:通道索引len:可用缓冲区长度指针(输出)desc_idx:描述符索引指针(输出)
返回值:缓冲区指针,失败返回 NULL
acomp_tuner_stream_tx_buffer_submit
int acomp_tuner_stream_tx_buffer_submit(int chn, void *buffer, uint32_t len, uint16_t desc_idx);
功能:提交 TX 流缓冲区发送音频数据到 AP 核
参数:
chn:通道索引buffer:缓冲区指针len:数据长度desc_idx:描述符索引
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_stream_kick
int acomp_tuner_stream_kick(int chn);
功能:主动触发流通道 kick 操作
参数:
chn:通道索引
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
acomp_tuner_stream_rx_buffer_get
void *acomp_tuner_stream_rx_buffer_get(int chn, uint32_t *len, uint16_t *desc_idx);
功能:获取 RX 流缓冲区中处理后的音频数据
参数:
chn:通道索引len:数据长度指针(输出)desc_idx:描述符索引指针(输出)
返回值:缓冲区指针,失败返回 NULL
acomp_tuner_stream_rx_buffer_release
int acomp_tuner_stream_rx_buffer_release(int chn, uint16_t desc_idx, uint32_t len, void *buffer);
功能:释放 RX 流缓冲区
参数:
chn:通道索引desc_idx:描述符索引len:数据长度buffer:缓冲区指针
返回值:
ACOMP_ERR_OK:成功ACOMP_ERR_INVALID_STATE:无效状态
使用示例
完整示例
#include "acomp.h"
#include "tuner/acomp_tuner.h"
#include "lisa_log.h"
#define TAG "tuner_demo"
#define TX_CH 0
#define RX_CH 1
void tuner_event_handler(uint32_t event, void *event_data,
uint32_t event_data_len, void *priv)
{
if (event & TUNER_CB_EVENT_STATUS) {
uint32_t status = *(uint32_t *)event_data;
LISA_LOGI(TAG, "Tuner status: %u", status);
} else if (event & TUNER_CB_EVENT_STREAM_UPDATE) {
// 有新的处理后音频数据
uint32_t len;
uint16_t desc_idx;
void *buffer = acomp_tuner_stream_rx_buffer_get(RX_CH, &len, &desc_idx);
if (buffer && len > 0) {
LISA_LOGI(TAG, "Processed audio received, len: %u", len);
// play_audio(buffer, len);
acomp_tuner_stream_rx_buffer_release(RX_CH, desc_idx, len, buffer);
}
}
}
void tuner_demo(void)
{
int ret;
// 1. 初始化 ACOMP 框架
acomp_init();
// 2. 初始化调音组件
ret = acomp_tuner_init();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Tuner init failed: %d", ret);
return;
}
// 3. 注册事件回调
acomp_tuner_add_callback(
TUNER_CB_EVENT_STATUS | TUNER_CB_EVENT_STREAM_UPDATE,
tuner_event_handler, NULL
);
// 4. 启动调音组件
ret = acomp_tuner_start();
if (ret != ACOMP_ERR_OK) {
LISA_LOGE(TAG, "Tuner start failed: %d", ret);
return;
}
LISA_LOGI(TAG, "Tuner started");
// 5. 创建双向流通道
acomp_stream_chn_create_desc_t tx_desc = {
.cname = "stream.tuner_in",
.direction = ACOMP_STREAM_DIRECTION_M2R,
.index = TX_CH,
.buffer_size = CONFIG_ACOMP_TUNER_STREAM_BUFFER_SIZE,
.num_descs = CONFIG_ACOMP_TUNER_STREAM_NUM_DESCS,
.kick_policy = 1,
};
acomp_tuner_stream_ch_enable(TX_CH, &tx_desc);
acomp_stream_chn_create_desc_t rx_desc = {
.cname = "stream.tuner_out",
.direction = ACOMP_STREAM_DIRECTION_R2M,
.index = RX_CH,
.buffer_size = CONFIG_ACOMP_TUNER_STREAM_BUFFER_SIZE,
.num_descs = CONFIG_ACOMP_TUNER_STREAM_NUM_DESCS,
.kick_policy = 1,
};
acomp_tuner_stream_ch_enable(RX_CH, &rx_desc);
// 6. 配置调音参数
acomp_tuner_set_samplerate(16000.0f);
acomp_tuner_set_volume(1.0f);
// 7. 使能调音处理
acomp_tuner_enable(1);
// 8. 运行一段时间
vTaskDelay(pdMS_TO_TICKS(10000));
// 9. 关闭并清理
acomp_tuner_enable(0);
acomp_tuner_stop();
acomp_tuner_cleanup();
LISA_LOGI(TAG, "Tuner cleaned up");
}
注意事项
初始化顺序:必须先调用
acomp_init()初始化 ACOMP 框架,再调用acomp_tuner_init()无 prepare 步骤:Tuner 组件不需要 prepare 步骤,init 后直接 start 即可
使能控制:调音处理默认关闭,必须调用
acomp_tuner_enable(1)开启双向流通道:Tuner 支持 M2R(输入)和 R2M(输出)双向流通道,分别用于发送原始音频和接收处理后音频
音频流管理:使用音频流接口时,必须成对调用 alloc/submit 和 get/release
事件回调:回调函数在组件内部线程中执行,应避免长时间阻塞操作
cleanup 安全:
acomp_tuner_cleanup()在组件未初始化时也可安全调用
常见问题
Q: 调音组件初始化失败怎么办?
A: 检查以下几点:
确保 ACOMP 框架已正确初始化
检查系统是否有足够的堆内存
确认 AP 核固件已正确烧录
Q: 使能调音后没有音频输出?
A: 检查:
确认 M2R 和 R2M 流通道都已正确创建
确认已调用
acomp_tuner_enable(1)开启调音检查采样率是否正确设置
确认音量系数不为 0
Q: 如何动态调整 EQ 参数?
A: 在运行过程中可以随时调用 acomp_tuner_set_param() 更新 EQ/DRC 参数,参数会实时生效。
依赖项
ACOMP 框架:算法组件框架ACOMP Stream IPC:音频流跨核通信lisa_log:日志系统FreeRTOS:实时操作系统调音算法库:EQ/DRC/Limiter 算法引擎