Files
99_7018_lmx/cpu/br28/audio_capture.c
2025-10-29 13:10:02 +08:00

1081 lines
32 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
****************************************************************************
* Audio Capture Module(AC)
*
*
****************************************************************************
*/
#include "audio_capture.h"
#include "system/includes.h"
#include "media/includes.h"
#include "app_config.h"
#include "tone_player.h"
#include "app_main.h"
#include "user_cfg.h"
#include "online_db_deal.h"
#include "audio_enc.h"
#if TCFG_SMART_VOICE_ENABLE
#include "smart_voice/smart_voice.h"
#endif
extern int spp_data_export(u8 ch, u8 *buf, u16 len);
extern int aec_data_export_init(u8 ch);
#if TCFG_AUDIO_DATA_EXPORT_ENABLE
#define AC_LOG_ENABLE
#ifdef AC_LOG_ENABLE
#define AC_LOG y_printf
#define AC_ERR_LOG r_printf
#else
#define AC_LOG(...)
#define AC_ERR_LOG(...)
#endif/*AC_LOG_ENABLE*/
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#define AudioCapture_CLK (128 * 1000000L)
#define AC_A_MIC 1 //2个模拟mic(Analog)
#define AC_D_MIC 2 //2个PDM mic(Digital)
#define AC_AD_MIC 3 //一个模拟mic、一个PDM mic
#define AC_VAD_MIC 4 //VAD模拟mic
#define AC_MIC_TYPE AC_A_MIC
#define AC_SAMPLE_RATE 16000 //AudioCapture Sample Rate
/**********************LED INDICATE CONFIG*********************/
#define LED_INDICATE_EN 0
#define LED_PORT JL_PORTC
#define LED_PORT_NUM 0
#define LED_DISPLAY_INIT() LED_PORT->DIR &= ~BIT(LED_PORT_NUM)
#define LED_DISPLAY_ON() LED_PORT->OUT |= BIT(LED_PORT_NUM)
#define LED_DISPLAY_OFF() LED_PORT->OUT &= ~BIT(LED_PORT_NUM)
/***************************************************************/
#define DM_2_DAC_EN 0 //双mic的数据输出到DAC播放(debug)
#define PLNK_MIC_CH 2
#define NS_DEMO_EN 0 //降噪模型测试使能
#define DM_RUN_POINT 256 //DualMic运行frame长(points)
#define DM_RUN_SIZE (DM_RUN_POINT * 2) //DualMic运行frame长(bytes)
#define ADC_MIC0_EN 1
#define ADC_MIC1_EN 1
#define ADC_DM_BUF_NUM 2
#if (NS_DEMO_EN || (AC_MIC_TYPE & AC_VAD_MIC))
#define ADC_DM_CH_NUM 1
#else /*使用AC_AD_MIC*/
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
/*开3路ADC*/
#define ADC_DM_CH_NUM 3
#else /*双麦*/
/*开2路ADC*/
#define ADC_DM_CH_NUM 2
#endif /*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
#endif/*NS_DEMO_EN*/
#define ADC_DM_IRQ_POINTS 256
#define ADC_DM_BUFS_SIZE (ADC_DM_BUF_NUM * ADC_DM_IRQ_POINTS * ADC_DM_CH_NUM)
#if (AC_MIC_TYPE == AC_AD_MIC)
#undef PLNK_MIC_CH
#undef ADC_DM_CH_NUM
#undef ADC_DM_BUFS_SIZE
#define PLNK_MIC_CH 1
#define ADC_DM_CH_NUM 1
#define ADC_DM_BUFS_SIZE (ADC_DM_BUF_NUM * ADC_DM_IRQ_POINTS * ADC_DM_CH_NUM)
#endif
/******************SPP_DATA_EXPORT_CONFIG****************************/
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
#define SPP_EXPORT_HEAD 4 /*4 bytes seqn*/
#define SPP_EXPORT_DATA_LEN 640 /*数据包长度*/
#define SPP_EXPORT_MTU (SPP_EXPORT_DATA_LEN + SPP_EXPORT_HEAD)
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
#define SPP_EXPORT_CH 3 /*导出数据通道数*/
#else /*两个通道*/
#define SPP_EXPORT_CH 2 /*导出数据通道数*/
#endif /*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
#define SPP_SEND_BY_TIMER 1 /*通过定时器定时发送*/
#if (SPP_EXPORT_CH == 3)
#define SPP_SEND_INTERVAL 4 //ms
#else
#define SPP_SEND_INTERVAL 6 //ms
#endif
#endif
/******************************************************************/
#define SD_START_BLOCK 50000 // SD卡起始扇区
#define SD_PCM_CHANNLE 1 // PCM数据通道
#define SD_PCM_BUF_SIZE (512 * SD_PCM_CHANNLE) // 每次写的数据长度
#define DE_HEADER_LEN 12 //数据头的长度
#define SD_PCM_BUF_SIZE_H (SD_PCM_BUF_SIZE - DE_HEADER_LEN) // 每次写的数据长度(with packet header)
/*数据导出添加数据头*/
#define DE_PACKET_HEADER_EN 0 //DE:DataExport
extern struct device *force_open_sd(char *sdx);
extern void force_write_sd(u8 *buf, u32 sector, u32 sector_num);
/*Audio Capture state*/
enum {
AC_STATE_INIT,
AC_STATE_START,
AC_STATE_STOP,
};
static u16 mic_ch_sw = 0;
#if DE_PACKET_HEADER_EN
#define DE_HEADER_MAGIC 0x5A
typedef struct {
u8 magic; //标识符0x5A
u8 ch; //通道号:0 1 2 0 1 2
u16 seqn; //序列号:0 1 2 3 4 5
u16 crc; //校验码
u16 len; //数据长度
u32 total_len; //数据累加总长
} de_header;
#endif/*DATA_PACKET_HEADER_EN*/
typedef struct {
u8 state;
u16 sr;
OS_SEM sem;
struct device *sd_hdl;
s16 mic0_buf[ADC_DM_IRQ_POINTS * 4]; // mic0的原始数据buf
s16 mic1_buf[ADC_DM_IRQ_POINTS * 4]; // mic1的原始数据buf
s16 mic2_buf[ADC_DM_IRQ_POINTS * 4]; // mic2的原始数据buf
//s16 out_buf[ADC_DM_IRQ_POINTS * 4]; // dm noise reduce output
cbuffer_t mic0_cb;
cbuffer_t mic1_cb;
cbuffer_t mic2_cb;
//cbuffer_t out_cb;
s16 mic0[DM_RUN_POINT];
s16 mic1[DM_RUN_POINT];
s16 mic2[DM_RUN_POINT];
s16 output[DM_RUN_POINT];
#if (AC_MIC_TYPE & AC_VAD_MIC)
void *vad_mic;
#endif
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
u8 export_buf[SPP_EXPORT_MTU];
#endif
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
u32 sd_write_sector;
OS_SEM sd_sem;
u8 sd_wbuf[SD_PCM_BUF_SIZE]; // 数据导出buf
#if DE_PACKET_HEADER_EN
s16 ch0_buf[ADC_DM_IRQ_POINTS * 3];
s16 ch1_buf[ADC_DM_IRQ_POINTS * 3];
s16 ch2_buf[ADC_DM_IRQ_POINTS * 3];
cbuffer_t ch0_cb;
cbuffer_t ch1_cb;
cbuffer_t ch2_cb;
#endif/*DE_PACKET_HEADER_EN*/
#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
s16 out_buf[ADC_DM_IRQ_POINTS * 6]; // dm noise reduce output
cbuffer_t out_cbuf;
} dual_mic_t;
dual_mic_t dm;
static void led_init()
{
#if LED_INDICATE_EN
LED_DISPLAY_INIT();
LED_DISPLAY_ON();
#endif/*LED_INDICATE_EN*/
}
static void led_run(u16 ms)
{
#if LED_INDICATE_EN
static u16 led_flash_cnt = 2000;
u16 flash_time = ms / 16;
if (led_flash_cnt++ > flash_time) {
LED_DISPLAY_OFF();
if (led_flash_cnt > (flash_time + 30)) {
led_flash_cnt = 0;
LED_DISPLAY_ON();
}
}
#endif/*LED_INDICATE_EN*/
}
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
static int data_export_run(void *dat, u16 len, u8 ch)
{
#if DE_PACKET_HEADER_EN
int wlen = 0;
//printf("export_run:%d",ch);
if (ch == 0) {
wlen = cbuf_write(&dm.ch0_cb, dat, len);
if (wlen != len) {
AC_ERR_LOG("[dm]sd%d buf full\n", ch);
}
} else if (ch == 1) {
wlen = cbuf_write(&dm.ch1_cb, dat, len);
if (wlen != len) {
AC_ERR_LOG("[dm]sd%d buf full\n", ch);
}
} else {
wlen = cbuf_write(&dm.ch2_cb, dat, len);
if (wlen != len) {
AC_ERR_LOG("[dm]sd%d buf full\n", ch);
}
}
os_sem_set(&dm.sd_sem, 0);
os_sem_post(&dm.sd_sem);
#else
int wlen = cbuf_write(&dm.out_cbuf, dat, len);
if (wlen != len) {
AC_ERR_LOG("[dm]sd buf full\n");
}
if (dm.out_cbuf.data_len >= SD_PCM_BUF_SIZE) {
os_sem_set(&dm.sd_sem, 0);
os_sem_post(&dm.sd_sem);
}
#endif
return 0;
}
#if DE_PACKET_HEADER_EN
static void DataExport_Task(void *p)
{
AC_LOG(">>>DataExport_Task[Header]<<<\n");
u8 pend;
u8 wch = 0;
de_header header;
u16 seqn0 = 0;
u16 seqn1 = 0;
u16 seqn2 = 0;
u32 total_len0 = 0;
u32 total_len1 = 0;
u32 total_len2 = 0;
header.magic = DE_HEADER_MAGIC;
while (1) {
pend = 1;
if (wch == 0) {
if (dm.ch0_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度才可以写。
pend = 0;
cbuf_read(&dm.ch0_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.ch = wch;
header.seqn = seqn0++;
header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.len = SD_PCM_BUF_SIZE_H;
total_len0 += header.len;
header.total_len = total_len0;
memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
//y_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
if (dm.sd_hdl) {
putchar('.');
led_run(7000);
force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
dm.sd_write_sector += SD_PCM_CHANNLE;
/* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
}
wch++;
}
} else if (wch == 1) {
if (dm.ch1_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度才可以写。
pend = 0;
cbuf_read(&dm.ch1_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.ch = wch;
header.seqn = seqn1++;
header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.len = SD_PCM_BUF_SIZE_H;
total_len1 += header.len;
header.total_len = total_len1;
memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
//g_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
if (dm.sd_hdl) {
putchar('.');
led_run(7000);
force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
dm.sd_write_sector += SD_PCM_CHANNLE;
/* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
}
wch++;
}
} else if (wch == 2) {
if (dm.ch2_cb.data_len >= SD_PCM_BUF_SIZE_H) { // 每次必须CBUF有足够的数据长度才可以写。
pend = 0;
cbuf_read(&dm.ch2_cb, &dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.ch = wch;
header.seqn = seqn2++;
header.crc = CRC16(&dm.sd_wbuf[DE_HEADER_LEN], SD_PCM_BUF_SIZE_H);
header.len = SD_PCM_BUF_SIZE_H;
total_len2 += header.len;
header.total_len = total_len2;
memcpy(&dm.sd_wbuf, &header, sizeof(de_header));
//g_printf("ch:%d,%d,%x,%d",header.ch,header.seqn,header.crc,header.len);
if (dm.sd_hdl) {
putchar('.');
led_run(7000);
force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
dm.sd_write_sector += SD_PCM_CHANNLE;
/* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
}
wch = 0;
}
}
//printf("wch:%d,pend:%d,len:%d,%d,%d",wch,pend,dm.ch0_cb.data_len,dm.ch1_cb.data_len,dm.ch2_cb.data_len);
if (pend) {
os_sem_pend(&dm.sd_sem, 0);
}
}
}
#else
static void DataExport_Task(void *p)
{
AC_LOG(">>>DataExport_Task<<<\n");
while (1) {
if (dm.out_cbuf.data_len >= SD_PCM_BUF_SIZE) { // 每次必须CBUF有足够的数据长度才可以写。
cbuf_read(&dm.out_cbuf, dm.sd_wbuf, SD_PCM_BUF_SIZE);
if (dm.sd_hdl) {
putchar('.');
led_run(7000);
force_write_sd(dm.sd_wbuf, dm.sd_write_sector, SD_PCM_CHANNLE);
dm.sd_write_sector += SD_PCM_CHANNLE;
/* printf("sd:%d\n",dm.sd_write_sector); //打印当前写的扇区位置。 */
}
} else {
os_sem_pend(&dm.sd_sem, 0);
}
}
}
#endif
#else
static int data_export_run(void *dat, u16 len, u8 ch)
{
return 0;
}
#endif/*TCFG_AUDIO_DATA_EXPORT_ENABLE*/
/*
*数据导出初始化
*/
typedef struct {
u8 ch_idx;
u8 retry;
u16 send_timer;
u32 seqn0;
u32 seqn1;
u32 seqn2;
} data_export_t;
data_export_t de;
int data_export_init()
{
AC_LOG("[dm]data_export_init\n");
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
/*使能板子RT9193供电给sd卡*/
JL_PORTB->DIR &= ~BIT(3);
JL_PORTB->OUT |= BIT(3);
dm.sd_hdl = force_open_sd("sd0");
AC_LOG("sd_hdl:%x\n", dm.sd_hdl);
//os_time_dly(10);
#if DE_PACKET_HEADER_EN
cbuf_init(&dm.ch0_cb, dm.ch0_buf, sizeof(dm.ch0_buf));
cbuf_init(&dm.ch1_cb, dm.ch1_buf, sizeof(dm.ch1_buf));
cbuf_init(&dm.ch2_cb, dm.ch2_buf, sizeof(dm.ch2_buf));
AC_LOG("de packet header size:%d\n", sizeof(de_header));
#else
cbuf_init(&dm.out_cbuf, dm.out_buf, sizeof(dm.out_buf));
#endif/*DE_PACKET_HEADER_EN*/
dm.sd_write_sector = SD_START_BLOCK;
os_sem_create(&dm.sd_sem, 0);
task_create(DataExport_Task, NULL, "data_export");
#endif/*AUDIO_DATA_EXPORT_USE_SD*/
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
aec_data_export_init(SPP_EXPORT_CH);
#endif/*AUDIO_DATA_EXPORT_USE_SPP*/
memset(&de, 0, sizeof(data_export_t));
cbuf_init(&dm.out_cbuf, dm.out_buf, sizeof(dm.out_buf));
return 0;
}
typedef struct {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 adc_buf[ADC_DM_BUFS_SIZE]; //align 4Bytes
s16 mic_tmp_data[ADC_DM_IRQ_POINTS];
s16 mic1_tmp_data[ADC_DM_IRQ_POINTS];
} adc_dm_t;
adc_dm_t *adc_dm = NULL;
void dm_2_dac_open(u16 sr)
{
#if DM_2_DAC_EN
y_printf("%s,sr = %d\n", sr);
audio_dac_set_sample_rate(&dac_hdl, sr);
audio_dac_start(&dac_hdl);
printf("max_sys_vol:%d\n", get_max_sys_vol());
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
printf("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
#endif
}
static void adc_mic_output(void *priv, s16 *data, int len)
{
/* printf("<%x,%x,%d>",adc_dm->adc_buf,data,len); */
u16 wlen;
#if (ADC_DM_CH_NUM == 2)
/*
*这里先把mic0的数据取出来放在临时bufmic1的数据就可以
*放到mic本来的buf了不用再开一个buf放mic1_data
*/
s16 *mic0_data = adc_dm->mic_tmp_data;
s16 *mic1_data = data;
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 2];
mic1_data[i] = data[i * 2 + 1];
}
wlen = cbuf_write(&dm.mic0_cb, mic0_data, len);
if (wlen != len) {
AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, len);
}
#if (TCFG_AUDIO_TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
#if (SPP_EXPORT_CH > 1)
wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
if (wlen != len) {
AC_ERR_LOG("mic1_cbuf full\n");
}
#endif/*SPP_EXPORT_CH == 2*/
#else
wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
if (wlen != len) {
AC_ERR_LOG("mic1_cbuf full\n");
}
#endif/*TCFG_AUDIO_TCFG_AUDIO_DATA_EXPORT_ENABLE*/
os_sem_post(&dm.sem);
#if DM_2_DAC_EN
if (tone_get_status()) {
return;
}
if (mic_ch_sw++ < 300) {
putchar('0');
wlen = audio_dac_write(&dac_hdl, mic0_data, len);
} else {
putchar('1');
wlen = audio_dac_write(&dac_hdl, mic1_data, len);
if (mic_ch_sw >= 600) {
mic_ch_sw = 0;
}
}
#endif/*DM_2_DAC_EN*/
#elif (ADC_DM_CH_NUM == 3)
/*
*这里先把mic0的数据取出来放在临时bufmic1的数据就可以
*放到mic本来的buf了不用再开一个buf放mic1_data
*/
s16 *mic0_data = data;
s16 *mic1_data = adc_dm->mic_tmp_data;
s16 *mic2_data = adc_dm->mic1_tmp_data;
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 3];
mic1_data[i] = data[i * 3 + 1];
mic2_data[i] = data[i * 3 + 2];
}
wlen = cbuf_write(&dm.mic0_cb, mic0_data, len);
if (wlen != len) {
AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, len);
}
wlen = cbuf_write(&dm.mic1_cb, mic1_data, len);
if (wlen != len) {
AC_ERR_LOG("mic1_cbuf full:%d,%d\n", wlen, len);
}
wlen = cbuf_write(&dm.mic2_cb, mic2_data, len);
if (wlen != len) {
AC_ERR_LOG("mic2_cbuf full:%d,%d\n", wlen, len);
}
os_sem_post(&dm.sem);
#if DM_2_DAC_EN
if (tone_get_status()) {
return;
}
if (mic_ch_sw++ < 300) {
putchar('0');
wlen = audio_dac_write(&dac_hdl, mic0_data, len);
} else if (mic_ch_sw++ < 600) {
putchar('1');
wlen = audio_dac_write(&dac_hdl, mic1_data, len);
} else {
putchar('2');
wlen = audio_dac_write(&dac_hdl, mic2_data, len);
if (mic_ch_sw >= 900) {
mic_ch_sw = 0;
}
}
#endif/*DM_2_DAC_EN*/
#else /*单模拟MIC(ADC_DM_CH_NUM == 1)*/
//putchar('m');
wlen = cbuf_write(&dm.mic1_cb, data, len);
if (wlen != len) {
AC_ERR_LOG("mic1_cbuf full\n");
}
os_sem_post(&dm.sem);
#if (DM_2_DAC_EN && (NS_DEMO_EN == 0))
if (mic_ch_sw >= 300) {
mic_ch_sw++;
putchar('1');
wlen = audio_dac_write(&dac_hdl, data, len);
if (mic_ch_sw >= 600) {
mic_ch_sw = 0;
}
}
#endif/*DM_2_DAC_EN*/
#endif/*ADC_DM_CH_NUM*/
}
static u8 dual_mic_idle_query()
{
return 0;
}
REGISTER_LP_TARGET(dual_mic_lp_target) = {
.name = "dual_mic",
.is_idle = dual_mic_idle_query,
};
/*初始化 mic*/
int audio_mic_init(u16 sr)
{
AC_LOG("[dm]audio_mic_init\n");
adc_dm = zalloc(sizeof(*adc_dm));
/*
*range:0(00000:-8dB)~19(1001:30dB)
*step:2dB
*/
u8 mic0_gain = 10;
u8 mic1_gain = 10;
u8 mic2_gain = 10;
u8 mic3_gain = 10;
//使用通话配置的mic增益更加直观反映mic的数据采样情况
mic0_gain = app_var.aec_mic_gain;
mic1_gain = app_var.aec_mic1_gain;
mic2_gain = app_var.aec_mic2_gain;
mic3_gain = app_var.aec_mic3_gain;
AC_LOG("[AC]mic_gain:%d,%d,%d,%d\n", mic0_gain, mic1_gain, mic2_gain, mic3_gain);
if (adc_dm) {
#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_0)
audio_adc_mic_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_adc_mic_set_gain(&adc_dm->mic_ch, app_var.aec_mic_gain);
#endif/*TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_0*/
#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_1)
audio_adc_mic1_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_adc_mic1_set_gain(&adc_dm->mic_ch, app_var.aec_mic1_gain);
#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_1)*/
#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_2)
audio_adc_mic2_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_adc_mic2_set_gain(&adc_dm->mic_ch, app_var.aec_mic2_gain);
#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_2)*/
#if (TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_3)
audio_adc_mic3_open(&adc_dm->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_adc_mic3_set_gain(&adc_dm->mic_ch, app_var.aec_mic3_gain);
#endif/*(TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA & AUDIO_ADC_MIC_3)*/
audio_adc_mic_set_sample_rate(&adc_dm->mic_ch, sr);
audio_adc_mic_set_buffs(&adc_dm->mic_ch, adc_dm->adc_buf, ADC_DM_IRQ_POINTS * 2, ADC_DM_BUF_NUM);
adc_dm->adc_output.handler = adc_mic_output;
audio_adc_add_output_handler(&adc_hdl, &adc_dm->adc_output);
audio_adc_mic_start(&adc_dm->mic_ch);
}
return 0;
}
void audio_mic_close(void)
{
if (adc_dm) {
audio_adc_mic_close(&adc_dm->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &adc_dm->adc_output);
free(adc_dm);
adc_dm = NULL;
}
}
#include "pdm_link.h"
audio_plnk_t *plnk_mic = NULL;
/*
*数据结构:
*单声道ch00 ch01 ch02 ch0n
*双声道ch00 ch01 ch02 ch0n ch10 ch11 ch12 ch1n
*/
static void plnk_mic_output(void *buf, u16 len)
{
s16 *mic0;
s16 *mic1;
/* audio_plnk_t *plnk = priv; */
/* s16 *buf = plnk->buf; */
/* u16 len = plnk->buf_len; */
//ch0
mic0 = (s16 *)buf;
#if (PLNK_MIC_CH == 2)
//ch1
mic1 = (s16 *)buf + len * 2;
#endif/*PLNK_MIC_CH == 2*/
#if 0 //合并两个声道的声音LLLRRR... -> LRLRLR...
for (int cnt = 0; cnt < len; cnt++) {
tmp_buf[cnt * 2] = mic0[cnt];
tmp_buf[cnt * 2 + 1] = mic1[cnt];
}
#endif
u16 olen = len << 1;
u16 wlen;
putchar('o');
//printf("olen:%d,%d",len,olen);
wlen = cbuf_write(&dm.mic0_cb, mic0, olen);
if (wlen != olen) {
AC_ERR_LOG("mic0_cbuf full:%d,%d\n", wlen, olen);
}
#if ((AC_MIC_TYPE == AC_D_MIC) && (PLNK_MIC_CH == 2))
wlen = cbuf_write(&dm.mic1_cb, mic1, olen);
if (wlen != olen) {
AC_ERR_LOG("mic1_cbuf full:%d,%d\n", wlen, olen);
}
#endif
os_sem_post(&dm.sem);
#if DM_2_DAC_EN
#if (AC_MIC_TYPE == AC_D_MIC)
#if (PLNK_MIC_CH == 2)
if (mic_ch_sw++ < 300) {
putchar('0');
wlen = audio_dac_write(&dac_hdl, mic0, olen);
} else {
putchar('1');
wlen = audio_dac_write(&dac_hdl, mic1, olen);
if (mic_ch_sw >= 600) {
mic_ch_sw = 0;
}
}
#else/*单mic数据输出*/
wlen = audio_dac_write(&dac_hdl, mic0, olen);
#endif/*PLNK_MIC_CH*/
#else
if (mic_ch_sw < 300) {
mic_ch_sw++;
putchar('0');
wlen = audio_dac_write(&dac_hdl, mic0, olen);
}
#endif/*AC_MIC_TYPE*/
if (wlen != olen) {
putchar('F');
}
#endif/*DM_2_DAC_EN*/
}
//#define PLNK_SCLK_PIN IO_PORTA_02
//#define PLNK_DAT0_PIN IO_PORTA_01
//#define PLNK_CH_EN PLNK_CH0_EN //(PLNK_CH0_EN | PLNK_CH1_EN)
static int audio_pdm_mic_init(u16 sr)
{
#if 0/*br28目前app层还没有做pdm*/
AC_LOG("[dm]audio_pdm_mic_init:%d\n", sr);
//MIC_PWR0
JL_PORTA->DIR &= ~BIT(2);
JL_PORTA->OUT |= BIT(2);
//6976B PA2 PA3双绑
JL_PORTA->DIR |= BIT(3);
JL_PORTA->PU &= ~BIT(3);
JL_PORTA->PD &= ~BIT(3);
#if (AC_MIC_TYPE == AC_D_MIC)
//MIC_PWR1
JL_PORTB->DIR &= ~BIT(7);
JL_PORTB->OUT |= BIT(7);
#endif
plnk_mic = zalloc(sizeof(audio_plnk_t));
if (plnk_mic) {
plnk_mic->ch_num = PLNK_MIC_CH;
plnk_mic->sr = sr;
plnk_mic->buf_len = 256;
#if (PLNK_CH_EN == PLNK_CH0_EN)/*两个通道复用ch0*/
plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
#elif (PLNK_CH_EN == PLNK_CH1_EN)/*两个通道复用ch1*/
plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#else/*两个通道用两个data ch*/
plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#endif/*PLNK_CH_EN*/
plnk_mic->buf = zalloc(plnk_mic->ch_num * plnk_mic->buf_len * 2 * 2);
ASSERT(plnk_mic->buf);
plnk_mic->output = plnk_mic_output;
plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
audio_plnk_open(plnk_mic);
audio_plnk_start(plnk_mic);
//dm_2_dac_open(plnk_mic->sr);
}
#endif
return 0;
}
static int DualMic_NoiseReduce_run(s16 *dat0, s16 *dat2, s16 *out, u16 points)
{
memcpy(out, dat0, points << 1);
return points;
}
#define SPP_EXPORT_RETRY_EN 0
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SPP)
static void spp_data_export_run()
{
int ret;
int out_points;
if (dm.state != AC_STATE_START) {
return;
}
#if AC_MIC_TYPE == AC_VAD_MIC
de.ch_idx = 1;
#endif
switch (de.ch_idx) {
case 0:
//putchar('0');
if (de.retry == 0) {
ret = cbuf_read(&dm.mic0_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
memcpy(dm.export_buf, &de.seqn0, SPP_EXPORT_HEAD);
} else {
ret = SPP_EXPORT_DATA_LEN;
}
if (ret == SPP_EXPORT_DATA_LEN) {
ret = spp_data_export(0, dm.export_buf, SPP_EXPORT_MTU);
if (ret == SPP_EXPORT_MTU) {
de.seqn0++;
de.ch_idx++;
de.retry = 0;
//putchar('A');
} else if (ret == -1) {
de.retry = SPP_EXPORT_RETRY_EN;
} else {
de.ch_idx++;
de.retry = 0;
}
}
break;
case 1:
//putchar('1');
#if NS_DEMO_EN
ret = cbuf_read(&dm.out_cbuf, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
#else
#if AC_MIC_TYPE == AC_VAD_MIC
if (cbuf_get_data_len(&dm.mic1_cb) < SPP_EXPORT_DATA_LEN) {
break;
}
#endif
ret = cbuf_read(&dm.mic1_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
#endif/*NS_DEMO_EN*/
memcpy(dm.export_buf, &de.seqn1, SPP_EXPORT_HEAD);
if (ret == SPP_EXPORT_DATA_LEN) {
ret = spp_data_export(1, dm.export_buf, SPP_EXPORT_MTU);
if (ret == SPP_EXPORT_MTU) {
de.seqn1++;
de.ch_idx++;
de.retry = 0;
//putchar('B');
} else if (ret == -1) {
de.retry = SPP_EXPORT_RETRY_EN;
} else {
de.ch_idx++;
de.retry = 0;
}
}
break;
case 2:
//putchar('2');
ret = cbuf_read(&dm.mic2_cb, &dm.export_buf[4], SPP_EXPORT_DATA_LEN);
memcpy(dm.export_buf, &de.seqn2, SPP_EXPORT_HEAD);
if (ret == SPP_EXPORT_DATA_LEN) {
//putchar('C');
ret = spp_data_export(2, dm.export_buf, SPP_EXPORT_MTU);
if (ret == SPP_EXPORT_MTU) {
de.seqn2++;
de.ch_idx++;
de.retry = 0;
} else if (ret == -1) {
de.retry = SPP_EXPORT_RETRY_EN;
} else {
de.ch_idx++;
de.retry = 0;
}
}
break;
}
if (de.ch_idx > (SPP_EXPORT_CH - 1)) {
de.ch_idx = 0;
}
}
static void aec_export_timer(void *priv)
{
#if SPP_SEND_BY_TIMER
spp_data_export_run();
#else
os_sem_set(&dm.sem, 0);
os_sem_post(&dm.sem);
#endif
}
#endif
static int audio_ns_open(u16 sr);
int audio_capture_start(void);
static void audio_capture_board_init()
{
led_init();
clk_set("sys", AudioCapture_CLK);
data_export_init();
#if NS_DEMO_EN
audio_ns_open(dm.sr);
#endif /*NS_DEMO_EN*/
/*spp数据导出由spp控制声音捕捉启动;SD数据导出则默认自动启动声音捕捉*/
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
audio_capture_start();
#endif/*AUDIO_DATA_EXPORT_USE_SD*/
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_UART)
audio_capture_start();
aec_uart_init();
#endif/*AUDIO_DATA_EXPORT_USE_SD*/
dm.state = AC_STATE_INIT;
}
int audio_capture_start(void)
{
dm.sr = AC_SAMPLE_RATE;
cbuf_init(&dm.mic0_cb, dm.mic0_buf, sizeof(dm.mic0_buf));
cbuf_init(&dm.mic1_cb, dm.mic1_buf, sizeof(dm.mic1_buf));
cbuf_init(&dm.mic2_cb, dm.mic2_buf, sizeof(dm.mic2_buf));
//cbuf_init(&dm.out_cb, dm.out_buf, sizeof(dm.out_buf));
#if (AC_MIC_TYPE & AC_A_MIC)
audio_mic_pwr_ctl(MIC_PWR_ON);
audio_mic_init(dm.sr);
#endif/*AC_MIC_TYPE*/
#if (AC_MIC_TYPE & AC_D_MIC)
audio_pdm_mic_init(dm.sr);
#endif/*AC_MIC_TYPE*/
#if (AC_MIC_TYPE & AC_VAD_MIC)
/*VAD MIC数据先通过mic1通道导出*/
dm.vad_mic = audio_vad_mic_capture(dm.sr, &dm, adc_mic_output);
#endif /*AC_VAD_MIC*/
memset(&de, 0, sizeof(data_export_t));
#if SPP_SEND_BY_TIMER
de.send_timer = usr_timer_add(NULL, aec_export_timer, SPP_SEND_INTERVAL, 1);
#endif/*SPP_SEND_BY_TIMER*/
dm_2_dac_open(dm.sr);
dm.state = AC_STATE_START;
AC_LOG("DataExport Start\n");
return 0;
}
void audio_capture_stop(void)
{
#if !(AC_MIC_TYPE & AC_VAD_MIC)
audio_mic_pwr_ctl(MIC_PWR_OFF);
audio_mic_close();
#else
audio_vad_mic_stop_capture(dm.vad_mic);
dm.vad_mic = NULL;
#endif
if (de.send_timer) {
usr_timeout_del(de.send_timer);
de.send_timer = 0;
}
dm.state = AC_STATE_STOP;
AC_LOG("DataExport Stop\n");
}
/*Noise Reduction/Suppression*/
#include "commproc_ns.h"
typedef struct {
u16 bypass;
s16 inbuf[DM_RUN_POINT];
s16 outbuf[320];
noise_suppress_param param;
} audio_ns_t;
audio_ns_t *audio_ns = NULL;
static int audio_ns_run(s16 *in, s16 *out, u16 points)
{
int out_points = 0;
if (audio_ns->bypass) {
out_points = points;
memcpy(out, in, (out_points << 1));
} else {
out_points = noise_suppress_run(in, out, points);
//printf(" <%d> ",out_points);
}
return (out_points << 1);
}
static int audio_ns_open(u16 sr)
{
printf("audio_ns_open:%d\n", sr);
extern u32 aec_addr[], aec_begin[], aec_size[];
memcpy(aec_addr, aec_begin, (u32)aec_size) ;
audio_ns = zalloc(sizeof(audio_ns_t));
//audio_ns->bypass = 1;
audio_ns->param.wideband = 1;
audio_ns->param.mode = 1;
audio_ns->param.AggressFactor = 1.25f;
audio_ns->param.MinSuppress = 0.04f;
audio_ns->param.NoiseLevel = 2.2e4f;
noise_suppress_open(&audio_ns->param);
printf("audio_ns_open succ\n");
return 0;
}
static void audio_ns_close(void)
{
if (audio_ns) {
noise_suppress_close();
free(audio_ns);
audio_ns = NULL;
}
}
extern int aec_uart_init();
extern int aec_uart_fill(u8 ch, void *buf, u16 size);
extern void aec_uart_write(void);
extern int aec_uart_close(void);
#define UART_EXPORT_MTU 512
u8 uart_wbuf[UART_EXPORT_MTU];
static void AudioCapture_Task(void *p)
{
int ret = 0;
AC_LOG(">>>AudioCapture_Task<<<\n");
while (tone_get_status()) {
os_time_dly(2);
}
audio_capture_board_init();
#if (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_SD)
while (1) {
if ((dm.mic0_cb.data_len >= DM_RUN_SIZE) && (dm.mic1_cb.data_len >= DM_RUN_SIZE)) {
cbuf_read(&dm.mic0_cb, dm.mic0, DM_RUN_SIZE);
data_export_run(dm.mic0, DM_RUN_SIZE, 0);
cbuf_read(&dm.mic1_cb, dm.mic1, DM_RUN_SIZE);
data_export_run(dm.mic1, DM_RUN_SIZE, 1);
int out_points = DualMic_NoiseReduce_run(dm.mic0, dm.mic1, dm.output, DM_RUN_POINT);
data_export_run(dm.output, (out_points << 1), 2);
} else {
os_sem_pend(&dm.sem, 0);
}
}
#elif (TCFG_AUDIO_DATA_EXPORT_ENABLE == AUDIO_DATA_EXPORT_USE_UART)
AC_LOG(">>>AudioCapture_Task[UART]<<<\n");
while (1) {
if (dm.mic0_cb.data_len >= UART_EXPORT_MTU) {
putchar('w');
ret = cbuf_read(&dm.mic0_cb, uart_wbuf, UART_EXPORT_MTU);
if (ret == UART_EXPORT_MTU) {
aec_uart_fill(0, uart_wbuf, UART_EXPORT_MTU); //主mic数据
putchar('0');
}
ret = cbuf_read(&dm.mic1_cb, uart_wbuf, UART_EXPORT_MTU);
if (ret == UART_EXPORT_MTU) {
aec_uart_fill(1, uart_wbuf, UART_EXPORT_MTU); //主mic数据
putchar('1');
}
ret = cbuf_read(&dm.mic2_cb, uart_wbuf, UART_EXPORT_MTU);
if (ret == UART_EXPORT_MTU) {
aec_uart_fill(2, uart_wbuf, UART_EXPORT_MTU); //主mic数据
putchar('2');
}
aec_uart_write();
} else {
os_sem_pend(&dm.sem, 0);
}
}
#else
while (1) {
os_sem_pend(&dm.sem, 0);
//do ans here:
if (audio_ns) {
if (cbuf_read(&dm.mic1_cb, audio_ns->inbuf, DM_RUN_SIZE) == DM_RUN_SIZE) {
cbuf_write(&dm.mic0_cb, audio_ns->inbuf, DM_RUN_SIZE);
int out_size = audio_ns_run(audio_ns->inbuf, audio_ns->outbuf, DM_RUN_POINT);
#if DM_2_DAC_EN
ret = audio_dac_write(&dac_hdl, audio_ns->outbuf, out_size);
#endif /*DM_2_DAC_EN*/
ret = cbuf_write(&dm.out_cbuf, audio_ns->outbuf, out_size);
if (ret != out_size) {
AC_LOG("NS output full\n");
}
}
}
#if (SPP_SEND_BY_TIMER == 0)
spp_data_export_run();
#endif
}
#endif
}
int audio_capture_init(void)
{
AC_LOG("Audio Capture init\n");
os_sem_create(&dm.sem, 0);
task_create(AudioCapture_Task, NULL, "aud_capture");
return 0;
}
int audio_capture_exit()
{
return 0;
}
#endif