Files
99_7018_lmx/cpu/br28/audio_capture.c

1081 lines
32 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
/*
****************************************************************************
* 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