调音组件

简介

ACOMP Tuner 是 ARCS SDK 的音频调音组件,提供 EQ(均衡器)、DRC(动态范围压缩)和 Limiter(限幅器)等音频处理功能。该组件支持采样率配置、调音参数设置、限幅器参数设置和音量调节,音频数据通过双向流通道(M2R 输入 / R2M 输出)与 AP 核算法引擎交互。

主要特性

  • EQ/DRC/Limiter:支持均衡器、动态范围压缩和限幅器音频处理

  • 采样率配置:支持设置音频采样率

  • 调音参数设置:支持自定义 EQ/DRC 调音参数

  • 限幅器参数设置:支持独立配置限幅器参数

  • 音量控制:支持设置输出音量系数

  • 使能控制:支持动态开启/关闭调音处理

  • 双向音频流:支持 M2R(输入原始音频)和 R2M(输出处理后音频)双向流通道

  • 事件回调机制:支持状态变更和数据流更新事件通知

  • 跨核通信:基于 IPC 机制实现音频数据的跨核传输

配置选项

基本配置

配置项

说明

默认值

CONFIG_ACOMP

启用 ACOMP 组件

n

CONFIG_ACOMP_TUNER

启用 ACOMP 组件的调音组件

n

流通道配置

配置项

说明

默认值

CONFIG_ACOMP_TUNER_STREAM_BUFFER_SIZE

流缓冲区大小(字节)

2560

CONFIG_ACOMP_TUNER_STREAM_NUM_DESCS

流描述符数量

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");
}

注意事项

  1. 初始化顺序:必须先调用 acomp_init() 初始化 ACOMP 框架,再调用 acomp_tuner_init()

  2. 无 prepare 步骤:Tuner 组件不需要 prepare 步骤,init 后直接 start 即可

  3. 使能控制:调音处理默认关闭,必须调用 acomp_tuner_enable(1) 开启

  4. 双向流通道:Tuner 支持 M2R(输入)和 R2M(输出)双向流通道,分别用于发送原始音频和接收处理后音频

  5. 音频流管理:使用音频流接口时,必须成对调用 alloc/submit 和 get/release

  6. 事件回调:回调函数在组件内部线程中执行,应避免长时间阻塞操作

  7. 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 算法引擎