#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".audio_capture.data.bss") #pragma data_seg(".audio_capture.data") #pragma const_seg(".audio_capture.text.const") #pragma code_seg(".audio_capture.text") #endif /* **************************************************************************** * 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_config.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_DEFINE && \ ((TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_SPP) \ || (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_SD))) #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_DEFINE == AUDIO_DATA_EXPORT_VIA_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_DEFINE == AUDIO_DATA_EXPORT_VIA_SPP) u8 export_buf[SPP_EXPORT_MTU]; #endif #if (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_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_DEFINE*/ 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_DEFINE == AUDIO_DATA_EXPORT_VIA_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_DEFINE*/ /* *数据导出初始化 */ 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_DEFINE == AUDIO_DATA_EXPORT_VIA_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_VIA_SD*/ #if (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_SPP) aec_data_export_init(SPP_EXPORT_CH); #endif/*AUDIO_DATA_EXPORT_VIA_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", app_audio_volume_max_query(AppVol_BT_MUSIC)); app_audio_state_switch(APP_AUDIO_STATE_MUSIC, app_audio_volume_max_query(AppVol_BT_MUSIC)); 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; /*len = 1ch adc data len*/ #if (ADC_DM_CH_NUM == 2) /* *这里先把mic0的数据取出来放在临时buf,mic1的数据就可以 *放到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_DEFINE == AUDIO_DATA_EXPORT_VIA_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_DEFINE*/ 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的数据取出来放在临时buf,mic1的数据就可以 *放到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) { u8 ch = TCFG_SPP_DATA_EXPORT_ADC_MIC_CHA; #if 1 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(&adc_dm->mic_ch, AUDIO_ADC_MIC_0); } if (ch & AUDIO_ADC_MIC_1) { adc_file_mic_open(&adc_dm->mic_ch, AUDIO_ADC_MIC_1); } if (ch & AUDIO_ADC_MIC_2) { adc_file_mic_open(&adc_dm->mic_ch, AUDIO_ADC_MIC_2); } if (ch & AUDIO_ADC_MIC_3) { adc_file_mic_open(&adc_dm->mic_ch, AUDIO_ADC_MIC_3); } #else /*0*/ 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(&adc_dm->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl, &mic_param); audio_adc_mic_set_gain(&adc_dm->mic_ch, AUDIO_ADC_MIC_0, mic0_gain); 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(&adc_dm->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl, &mic_param); audio_adc_mic_set_gain(&adc_dm->mic_ch, AUDIO_ADC_MIC_1, mic1_gain); 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(&adc_dm->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl, &mic_param); audio_adc_mic_set_gain(&adc_dm->mic_ch, AUDIO_ADC_MIC_2, mic2_gain); 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(&adc_dm->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl, &mic_param); audio_adc_mic_set_gain(&adc_dm->mic_ch, AUDIO_ADC_MIC_3, mic3_gain); audio_adc_mic_gain_boost(AUDIO_ADC_MIC_3, 1); } #endif /*1/0*/ 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 "audio_dai/audio_pdm.h" static PLNK_PARM *pdm_mic = NULL; extern int pdm_mic_file_param_init(PLNK_PARM *pdm_mic); /* *数据结构: *单声道:ch00 ch01 ch02 ch0n *双声道:ch00 ch01 ch02 ch0n ch10 ch11 ch12 ch1n */ static void plnk_mic_output(void *priv, void *buf, u32 len) { s16 *mic0; s16 *mic1; PLNK_PARM *plnk = (PLNK_PARM *)priv; u8 ch_num = plnk->ch_num; //ch0 mic0 = (s16 *)buf; if (ch_num == 2) { //ch1 mic1 = (s16 *)buf + (len / 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; 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) if (ch_num == 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 (ch_num == 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 { wlen = audio_dac_write(&dac_hdl, mic0, olen); } #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*/ } static int audio_pdm_mic_init(u16 sr) { AC_LOG("[dm]audio_pdm_mic_init:%d\n", sr); pdm_mic = zalloc(sizeof(PLNK_PARM)); if (pdm_mic) { pdm_mic->sr = sr; pdm_mic->dma_len = 512; pdm_mic->isr_cb = plnk_mic_output; pdm_mic->private_data = pdm_mic; //保存私有指针 int len = pdm_mic_file_param_init(pdm_mic); pdm_mic = plnk_init(pdm_mic); plnk_start(pdm_mic); } return 0; } static int audio_pdm_mic_exit() { if (pdm_mic) { plnk_uninit(pdm_mic); free(pdm_mic); pdm_mic = NULL; } 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_DEFINE == AUDIO_DATA_EXPORT_VIA_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(); data_export_init(); #if NS_DEMO_EN audio_ns_open(dm.sr); #endif /*NS_DEMO_EN*/ /*spp数据导出,由spp控制声音捕捉启动;SD数据导出,则默认自动启动声音捕捉*/ #if (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_SD) audio_capture_start(); #endif/*AUDIO_DATA_EXPORT_VIA_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)); audio_mic_pwr_ctl(MIC_PWR_ON); #if (AC_MIC_TYPE & AC_A_MIC) 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) { audio_mic_pwr_ctl(MIC_PWR_OFF); #if (AC_MIC_TYPE & AC_A_MIC) audio_mic_close(); #endif #if (AC_MIC_TYPE & AC_D_MIC) audio_pdm_mic_exit(); #endif/*AC_MIC_TYPE*/ #if (AC_MIC_TYPE & AC_VAD_MIC) 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 "cvp_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; } } static void AudioCapture_Task(void *p) { AC_LOG(">>>AudioCapture_Task<<<\n"); /* while (tone_get_status()) { */ /* os_time_dly(2); */ /* } */ audio_capture_board_init(); #if (TCFG_AUDIO_DATA_EXPORT_DEFINE == AUDIO_DATA_EXPORT_VIA_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); } } #else int ret = 0; 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