Files
AC707N/SDK/audio/CVP/audio_cvp_demo.c
T
2025-12-03 11:12:34 +08:00

417 lines
13 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".audio_cvp_demo.data.bss")
#pragma data_seg(".audio_cvp_demo.data")
#pragma const_seg(".audio_cvp_demo.text.const")
#pragma code_seg(".audio_cvp_demo.text")
#endif
/*
****************************************************************
* AUDIO_CVP_DEMO
* Brief : CVP模块使用范例
* Notes :清晰语音测试使用,请不要修改本demo,如有需求,请拷贝副
* 本,自行修改!
* Usage :
*(1)测试单mic降噪和双mic降噪
*(2)支持监听:监听原始数据/处理后的数据(MONITOR)
* MIC ---------> CVP ---------->SPK
* | |
* monitor probe monitor post
*(3)调用audio_cvp_test()即可测试cvp模块
****************************************************************
*/
#include "cpu/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "audio_cvp.h"
#include "app_main.h"
#include "audio_config.h"
#include "overlay_code.h"
//#define AUDIO_CVP_DEMO
#ifdef AUDIO_CVP_DEMO
#define CVP_LOG_ENABLE
#ifdef CVP_LOG_ENABLE
#define CVP_LOG(x, ...) y_printf("[cvp_demo]" x " ", ## __VA_ARGS__)
#else
#define CVP_LOG(...)
#endif/*CVP_LOG_ENABLE*/
extern struct adc_platform_data adc_data;
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#if TCFG_AUDIO_DUAL_MIC_ENABLE
#define MIC_CH_NUM 2
#else
#define MIC_CH_NUM 1
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
#define MIC_BUF_NUM 2
#define MIC_IRQ_POINTS 256
#define MIC_BUFS_SIZE (MIC_BUF_NUM * MIC_IRQ_POINTS * MIC_CH_NUM)
#define CVP_MIC_SR 16000 //采样率
#define CVP_MIC_GAIN 10 //增益
#define CVP_MONITOR_DIS 0 //监听关闭
#define CVP_MONITOR_PROBE 1 //监听处理前数据
#define CVP_MONITOR_POST 2 //监听处理后数据
//默认监听选择
#define CVP_MONITOR_SEL CVP_MONITOR_POST
typedef struct {
u8 monitor;
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 tmp_buf[MIC_IRQ_POINTS];
s16 mic_buf[MIC_BUFS_SIZE];
#if (TCFG_DAC_NODE_ENABLE && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))//双声道数据结构
s16 tmp_buf_1[320 * 2];
#endif
} audio_cvp_t;
audio_cvp_t *cvp_demo = NULL;
/*监听输出:默认输出到dac*/
static int cvp_monitor_output(s16 *data, int len)
{
#if TCFG_DAC_NODE_ENABLE
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)//双声道数据结构
int i = 0;
for (i = 0; i < (len / 2); i++) {
cvp_demo->tmp_buf_1[i * 2] = data[i];
cvp_demo->tmp_buf_1[i * 2 + 1] = data[i];
}
int wlen = audio_dac_write(&dac_hdl, cvp_demo->tmp_buf_1, len * 2);
if (wlen != (len * 2)) {
CVP_LOG("monitor output full\n");
}
#else //单声道数据结构
int wlen = audio_dac_write(&dac_hdl, data, len);
if (wlen != len) {
CVP_LOG("monitor output full\n");
}
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
return wlen;
#else
return len;
#endif/*TCFG_DAC_NODE_ENABLE*/
}
/*监听使能*/
static int cvp_monitor_en(u8 en, int sr)
{
CVP_LOG("cvp_monitor_en:%d,sr:%d\n", en, sr);
if (en) {
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, app_audio_volume_max_query(AppVol_BT_MUSIC), NULL);
CVP_LOG("cur_vol:%d,max_sys_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC), app_audio_volume_max_query(AppVol_BT_MUSIC));
audio_dac_set_volume(&dac_hdl, app_audio_volume_max_query(AppVol_BT_MUSIC));
audio_dac_set_sample_rate(&dac_hdl, sr);
audio_dac_start(&dac_hdl);
audio_dac_channel_start(NULL);
} else {
audio_dac_stop(&dac_hdl);
audio_dac_close(&dac_hdl);
}
return 0;
}
/*mic adc原始数据输出*/
static void mic_output(void *priv, s16 *data, int len)
{
putchar('.');
audio_cvp_phase_align();
#if (MIC_CH_NUM == 2)/*DualMic*/
s16 *mic0_data = data;
s16 *mic1_data = cvp_demo->tmp_buf;
s16 *mic1_data_pos = data + (len / 2);
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
/*分离出两个mic通道的数据*/
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 2];
mic1_data[i] = data[i * 2 + 1];
}
memcpy(mic1_data_pos, mic1_data, len);
if (cvp_demo->monitor == CVP_MONITOR_PROBE) {
cvp_monitor_output(data, len);
}
#if 0 /*debug*/
static u16 mic_cnt = 0;
if (mic_cnt++ > 300) {
putchar('1');
audio_aec_inbuf(mic1_data_pos, len);
if (mic_cnt > 600) {
mic_cnt = 0;
}
} else {
putchar('0');
audio_aec_inbuf(mic0_data, len);
}
#else
#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
audio_aec_inbuf_ref(mic1_data_pos, len);
audio_aec_inbuf(data, len);
#else
audio_aec_inbuf_ref(data, len);
audio_aec_inbuf(mic1_data_pos, len);
#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
#endif/*debug end*/
#else /*SingleMic*/
if (cvp_demo->monitor == CVP_MONITOR_PROBE) {
cvp_monitor_output(data, len);
}
audio_aec_inbuf(data, len);
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
}
static void mic_open(u8 ch, u8 gain0, u8 gain1, u8 gain2, u8 gain3, int sr)
{
CVP_LOG("mic_open\n");
if (cvp_demo) {
#if 0 // use config file
extern void audio_adc_file_init(void);
extern int adc_file_mic_open(struct adc_mic_ch * mic, int ch);
audio_adc_file_init();
if (ch & AUDIO_ADC_MIC_0) {
adc_file_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_0);
}
if (ch & AUDIO_ADC_MIC_1) {
adc_file_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_1);
}
if (ch & AUDIO_ADC_MIC_2) {
adc_file_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_2);
}
if (ch & AUDIO_ADC_MIC_3) {
adc_file_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_3);
}
#else
struct mic_open_param mic_param = {0};
if (ch & AUDIO_ADC_MIC_0) {
mic_param.mic_mode = AUDIO_MIC_CAP_MODE;
mic_param.mic_ain_sel = AUDIO_MIC0_CH0;
mic_param.mic_bias_sel = AUDIO_MIC_BIAS_CH0;
mic_param.mic_bias_rsel = 4;
mic_param.mic_dcc = 8;
audio_adc_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl, &mic_param);
audio_adc_mic_set_gain(&cvp_demo->mic_ch, AUDIO_ADC_MIC_0, gain0);
audio_adc_mic_gain_boost(AUDIO_ADC_MIC_0, 1);
}
if (ch & AUDIO_ADC_MIC_1) {
mic_param.mic_mode = AUDIO_MIC_CAP_MODE;
mic_param.mic_ain_sel = AUDIO_MIC1_CH0;
mic_param.mic_bias_sel = AUDIO_MIC_BIAS_CH1;
mic_param.mic_bias_rsel = 4;
mic_param.mic_dcc = 8;
audio_adc_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl, &mic_param);
audio_adc_mic_set_gain(&cvp_demo->mic_ch, AUDIO_ADC_MIC_1, gain1);
audio_adc_mic_gain_boost(AUDIO_ADC_MIC_1, 1);
}
if (ch & AUDIO_ADC_MIC_2) {
mic_param.mic_mode = AUDIO_MIC_CAP_MODE;
mic_param.mic_ain_sel = AUDIO_MIC2_CH0;
mic_param.mic_bias_sel = AUDIO_MIC_BIAS_CH2;
mic_param.mic_bias_rsel = 4;
mic_param.mic_dcc = 8;
audio_adc_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl, &mic_param);
audio_adc_mic_set_gain(&cvp_demo->mic_ch, AUDIO_ADC_MIC_2, gain2);
audio_adc_mic_gain_boost(AUDIO_ADC_MIC_2, 1);
}
if (ch & AUDIO_ADC_MIC_3) {
mic_param.mic_mode = AUDIO_MIC_CAP_MODE;
mic_param.mic_ain_sel = AUDIO_MIC3_CH0;
mic_param.mic_bias_sel = AUDIO_MIC_BIAS_CH3;
mic_param.mic_bias_rsel = 4;
mic_param.mic_dcc = 8;
audio_adc_mic_open(&cvp_demo->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl, &mic_param);
audio_adc_mic_set_gain(&cvp_demo->mic_ch, AUDIO_ADC_MIC_3, gain3);
audio_adc_mic_gain_boost(AUDIO_ADC_MIC_3, 1);
}
#endif
audio_adc_mic_set_sample_rate(&cvp_demo->mic_ch, sr);
audio_adc_mic_set_buffs(&cvp_demo->mic_ch, cvp_demo->mic_buf, MIC_IRQ_POINTS * 2, MIC_BUF_NUM);
cvp_demo->adc_output.handler = mic_output;
audio_adc_add_output_handler(&adc_hdl, &cvp_demo->adc_output);
audio_adc_mic_start(&cvp_demo->mic_ch);
}
CVP_LOG("mic_open succ\n");
}
static void mic_close(void)
{
if (cvp_demo) {
audio_adc_mic_close(&cvp_demo->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &cvp_demo->adc_output);
}
}
/*清晰语音数据输出*/
static int cvp_output_hdl(s16 *data, u16 len)
{
putchar('o');
if (cvp_demo->monitor == CVP_MONITOR_POST) {
cvp_monitor_output(data, len);
}
return len;
}
/*清晰语音测试模块*/
int audio_cvp_test(void)
{
if (cvp_demo == NULL) {
cvp_demo = zalloc(sizeof(audio_cvp_t));
ASSERT(cvp_demo);
cvp_demo->monitor = CVP_MONITOR_SEL;
if (cvp_demo->monitor) {
cvp_monitor_en(1, CVP_MIC_SR);
}
struct audio_aec_init_param_t init_param;
init_param.sample_rate = CVP_MIC_SR;
init_param.ref_sr = 0;
#if TCFG_AUDIO_DUAL_MIC_ENABLE
mic_open(AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_SR);
audio_aec_open(&init_param, (ANS_EN | ENC_EN), cvp_output_hdl);
#else
mic_open(AUDIO_ADC_MIC_0, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_GAIN, CVP_MIC_SR);
audio_aec_open(&init_param, (ANS_EN), cvp_output_hdl);
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
CVP_LOG("cvp_test open\n");
} else {
mic_close();
if (cvp_demo->monitor) {
cvp_monitor_en(0, CVP_MIC_SR);
}
audio_aec_close();
free(cvp_demo);
cvp_demo = NULL;
CVP_LOG("cvp_test close\n");
}
return 0;
}
static u8 audio_cvp_idle_query()
{
return (cvp_demo == NULL) ? 1 : 0;
}
REGISTER_LP_TARGET(audio_cvp_lp_target) = {
.name = "audio_cvp",
.is_idle = audio_cvp_idle_query,
};
#if 0
/*
*********************************************************************
* KSR Echo Cancellation
*
* Description: 语音识别回音消除,用来消除语音识别中,mic从speaker中拾
* 取到的回音,提高语音识别率
* Note(s) : KSR = Keyword Speech Recognition
*********************************************************************
*/
#define KSR_MIC_BUF_NUM 2
#define KSR_MIC_IRQ_POINTS 256
#define KSR_MIC_BUFS_SIZE (KSR_MIC_BUF_NUM * KSR_MIC_IRQ_POINTS)
struct KSR_mic_var {
u16 in_sr;
u16 ref_sr;
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 mic_buf[KSR_MIC_BUFS_SIZE];
};
struct KSR_mic_var *KSR_mic = NULL;
/*ADC mic采样数据输出*/
static void KSR_mic_output(void *priv, s16 *data, int len)
{
putchar('o');
audio_aec_inbuf(data, len);
}
/*回音消除后的数据输出*/
static int KSR_mic_aec_output(s16 *data, u16 len)
{
putchar('O');
return len;
}
int KSR_aec_open(u16 in_sr, u16 ref_sr)
{
u16 mic_sr = 16000;
u8 mic_gain = 10;
int err = 0;
printf("KSR_aec_open\n");
if (KSR_mic == NULL) {
KSR_mic = zalloc(sizeof(struct KSR_mic_var));
KSR_mic->in_sr = in_sr;
KSR_mic->ref_sr = ref_sr;
/*根据资源情况,配置AEC模块使能*/
u16 aec_enablebit = NLP_EN;
//u16 aec_enablebit = AEC_EN;
//u16 aec_enablebit = AEC_EN | NLP_EN;
struct audio_aec_init_param_t init_param;
init_param.sample_rate = mic_sr;
init_param.ref_sr = 0;
err = audio_aec_open(&init_param, aec_enablebit, KSR_mic_aec_output);
if (err) {
printf("KSR aec open err:%d\n", err);
return -1;
}
audio_adc_mic_open(&KSR_mic->mic_ch, AUDIO_ADC_MIC_CH, &adc_hdl);
audio_adc_mic_set_sample_rate(&KSR_mic->mic_ch, mic_sr);
audio_adc_mic_set_gain(&KSR_mic->mic_ch, mic_gain);
audio_adc_mic_set_buffs(&KSR_mic->mic_ch, KSR_mic->mic_buf, KSR_MIC_IRQ_POINTS * 2, KSR_MIC_BUF_NUM);
KSR_mic->adc_output.handler = KSR_mic_output;
audio_adc_add_output_handler(&adc_hdl, &KSR_mic->adc_output);
audio_adc_mic_start(&KSR_mic->mic_ch);
printf("KSR aec open succ\n");
}
return 0;
}
int KSR_aec_info(u8 idx)
{
if (KSR_mic == NULL) {
return -1;
}
switch (idx) {
case 0:
return KSR_mic->in_sr;
case 1:
return KSR_mic->ref_sr;
}
return -1;
}
void KSR_aec_close(void)
{
printf("KSR_aec_close\n");
if (KSR_mic) {
/*关闭adc_mic采样*/
audio_adc_del_output_handler(&adc_hdl, &KSR_mic->adc_output);
audio_adc_mic_close(&KSR_mic->mic_ch);
free(KSR_mic);
KSR_mic = NULL;
/*关闭aec模块*/
audio_aec_close();
}
}
#endif
#endif/*AUDIO_CVP_DEMO*/