Files
99_7018_lmx/apps/earphone/audio_enc_mpt_self.c
2025-10-29 13:10:02 +08:00

435 lines
12 KiB
C
Raw 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 Enc Mass production test self
* File : audio_enc_mpt_self.c
* note : 自研ENC产测 声学频响测试
************************************************************/
#include "hw_fft.h"
#include "app_config.h"
#include "audio_enc_mpt_self.h"
#include "generic/list.h"
#include "system/task.h"
#if 0
#define encmpt_log(x, ...) printf("[enc_mpt]" x " ", ## __VA_ARGS__)
#else
#define encmpt_log(...)
#endif/*log_en*/
#if AUDIO_ENC_MPT_SELF_ENABLE
void anc_HpEst_psd(s16 *input0, float *out0_sum, int len, int *cnt);
void anc_HpEst_psd_out(float *out0_sum, int flen, int cnt);
//输出数据类型
typedef float ENC_OUT_TYPE;
/* typedef short ENC_OUT_TYPE; */
typedef struct {
struct list_head entry;
u16 id; //对应数据通道id
u16 len; //长度
int cnt; //计算次数
s16 *in; //输入地址
ENC_OUT_TYPE *out; //输出地址
} enc_freres_bulk;
typedef struct {
u16 version;
u16 cnt;
u8 dat[0]; //小心double访问非对齐异常
} enc_freres_file_t;
typedef struct {
u32 id;
u32 offset;
u32 len;
} enc_freres_file_head_t;
typedef struct {
volatile u8 state; //状态
u8 run_busy;
u8 inbuf_busy;
u16 ch; //目标通道
/* enc_freres_bulk bulk[5];//链表最长支持5段 */
enc_freres_bulk *bulk;//链表,动态申请不定长
u8 *file_data; //输出文件
int file_len; //输出文件长度
int in_packet_len;
struct list_head head;
} audio_fre_respone_t;
static audio_fre_respone_t *hdl;
#if 0 //输入数据连续性验证
u8 *data1;
u8 *data2;
u8 *data3;
#define ENC_CHECK_LEN 8192
static u8 ainit = 0;
static u16 offset1 = 0;
static u16 offset2 = 0;
static u16 offset3 = 0;
void audio_enc_mpt_inbuf_check(u16 id, s16 *buf, int len)
{
if (!ainit) {
ainit = 1;
data1 = zalloc(ENC_CHECK_LEN);
data2 = zalloc(ENC_CHECK_LEN);
data3 = zalloc(ENC_CHECK_LEN);
}
if (id & AUDIO_ENC_MPT_FF_MIC) {
if ((offset1 + len) > ENC_CHECK_LEN) {
offset1 = 0;
}
memcpy(data1 + offset1, (u8 *)buf, len);
offset1 += len;
}
if (id & AUDIO_ENC_MPT_TALK_MIC) {
if ((offset2 + len) > ENC_CHECK_LEN) {
offset2 = 0;
}
memcpy(data2 + offset2, (u8 *)buf, len);
offset2 += len;
}
if (id & AUDIO_ENC_MPT_CVP_OUT) {
if ((offset3 + len) > ENC_CHECK_LEN) {
offset3 = 0;
}
memcpy(data3 + offset3, (u8 *)buf, len);
offset3 += len;
}
}
void audio_enc_mpt_inbuf_printf(void)
{
int i = 0;
s16 *dat1 = (s16 *)data1;
s16 *dat2 = (s16 *)data2;
s16 *dat3 = (s16 *)data3;
encmpt_log("ff");
for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
printf("%d\n", dat1[i]);
}
encmpt_log("TALK");
for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
printf("%d\n", dat2[i]);
}
encmpt_log("cvp");
for (i = 0; i < ENC_CHECK_LEN / 2; i++) {
printf("%d\n", dat3[i]);
}
}
#endif/*默认关闭*/
//id = 0 计算链表所有满足长度的节点;
static void audio_enc_mpt_fre_response_process(u16 id)
{
/* return; */
enc_freres_bulk *bulk;
if (hdl->state != ENC_FRE_RES_STATE_RUN) {
return;
}
hdl->run_busy = 1;
list_for_each_entry(bulk, &hdl->head, entry) {
//原始数据指针、目标输出指针、计算长度
if ((!id) || id == bulk->id) {
if (bulk->len >= hdl->in_packet_len) {
anc_HpEst_psd(bulk->in, bulk->out, AUDIO_ENC_MPT_FRERES_POINT, &bulk->cnt);
bulk->len -= (hdl->in_packet_len >> 1);
/* encmpt_log("process id 0X%x len %d\n", bulk->id, bulk->len); */
if (bulk->len) { //overlap
memcpy(bulk->in, bulk->in + (hdl->in_packet_len >> 2), bulk->len);
}
}
}
}
hdl->run_busy = 0;
}
static void audio_enc_mpt_fre_resonpse_task(void *p)
{
int res;
int msg[16];
u32 pend_timeout = portMAX_DELAY;
encmpt_log(">>>audio_fre_res_task<<<\n");
while (1) {
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
if (res == OS_TASKQ) {
switch (msg[1]) {
case ENC_FRE_RESPONE_MSG_RUN:
audio_enc_mpt_fre_response_process((u16)msg[2]);
break;
}
} else {
encmpt_log("res:%d,%d", res, msg[1]);
}
}
}
//初始化链表以及的通道内容
static void audio_enc_mpt_fre_response_bulk_init(enc_freres_file_t *file, u8 cnt, u16 id)
{
u8 *data_home;
enc_freres_file_head_t *file_head = file->dat;
/* if (cnt > 4) { */
/* encmpt_log("ERR:Audio enc Fre bulk full!!!\n"); */
/* return; */
/* } */
data_home = file->dat + (file->cnt * 12);
//file初始化head
file_head[cnt].id = id;
//len(byte)
file_head[cnt].len = AUDIO_ENC_MPT_FRERES_POINT / 2 * sizeof(ENC_OUT_TYPE);
if (cnt) {
file_head[cnt].offset = file_head[cnt - 1].len + file_head[cnt - 1].offset;
} else {
file_head[cnt].offset = 0;
}
hdl->bulk[cnt].id = id;
hdl->bulk[cnt].out = (ENC_OUT_TYPE *)(data_home + file_head[cnt].offset);
hdl->bulk[cnt].in = (s16 *)malloc(AUDIO_ENC_MPT_FRERES_POINT * sizeof(short));
encmpt_log("hdl %x file %x, out %x, data_home %x, inbuf_len %d\n", (int)hdl->file_data, (int)file, \
(int)hdl->bulk[cnt].out, (int)data_home, AUDIO_ENC_MPT_FRERES_POINT * sizeof(short));
//len(byte)
hdl->bulk[cnt].len = 0;
/* hdl->bulk[cnt].len = AUDIO_ENC_MPT_FRERES_POINT * sizeof(short); */
list_add_tail(&hdl->bulk[cnt].entry, &hdl->head);
}
//文件内存申请,结构初始化
static enc_freres_file_t *audio_enc_mpt_fre_response_file_init(int cnt)
{
enc_freres_file_t *file;
//4byte(vesion + cnt) + cnt * (12byte (id + offset + len) + outdata)
//以目标file文件组成结构申请空间
//data => 复数取平方和, 因此POINT/2
hdl->file_len = 4 + cnt * (12 + AUDIO_ENC_MPT_FRERES_POINT / 2 * sizeof(ENC_OUT_TYPE));
#if 0
//评估内存是否满足当前需求
extern size_t xPortGetPhysiceMemorySize(void);
int cur_mem_size = xPortGetPhysiceMemorySize();
if (cur_mem_size < hdl->file_len + 2000) { //至少余量多2000byte 才可使用该功能
printf("ERR!!!MIC_FFT debug_buf:%lu + 2000,free_mem:%d\n", hdl->file_len, cur_mem_size);
return NULL;
}
#endif
encmpt_log("file init len %d\n", hdl->file_len);
hdl->file_data = zalloc(hdl->file_len);
file = (enc_freres_file_t *) hdl->file_data;
file->cnt = cnt;
return file;
}
//音频测试频响计算启动, ch 对应目标的通道
void audio_enc_mpt_fre_response_start(u16 ch)
{
enc_freres_file_t *file;
int cnt = 0;
int shift_det = 0;
u16 det_ch = ch;
int det_cnt = 0;
encmpt_log("%s, ch 0x%x\n", __func__, ch);
if (!ch) {
return;
}
if (hdl) {
//支持重入
hdl->state = ENC_FRE_RES_STATE_START;
audio_enc_mpt_fre_response_release();
encmpt_log("enc_fre start again\n");
}
#if AUDIO_ENC_MPT_FRERES_ASYNC
task_create(audio_enc_mpt_fre_resonpse_task, NULL, "enc_mpt_self");
#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
hdl = zalloc(sizeof(audio_fre_respone_t));
hdl->ch = ch;
hdl->in_packet_len = AUDIO_ENC_MPT_FRERES_POINT * sizeof(short);
while (det_ch) {
if (det_ch & BIT(0)) {
det_cnt++;
}
det_ch >>= 1;
}
file = audio_enc_mpt_fre_response_file_init(det_cnt);
if (!file) {
free(hdl);
return;
}
//链表初始化
INIT_LIST_HEAD(&hdl->head);
//申请链表空间
hdl->bulk = zalloc(sizeof(enc_freres_bulk) * det_cnt);
encmpt_log("det_cnt %d, list bulk size %d\n", det_cnt, sizeof(enc_freres_bulk) * det_cnt);
while (ch) {
if (ch & BIT(0)) {
audio_enc_mpt_fre_response_bulk_init(file, cnt, BIT(shift_det));
encmpt_log("list init %x\n", BIT(shift_det));
cnt++;
}
shift_det++;
ch >>= 1;
}
hdl->state = ENC_FRE_RES_STATE_RUN;
}
//更新目标通道输入buf、len
void audio_enc_mpt_fre_response_inbuf(u16 id, s16 *buf, int len)
{
//len(byte)
if (!hdl) {
goto __err1;
/* return; */
}
if (hdl->state != ENC_FRE_RES_STATE_RUN) {
goto __err1;
/* return; */
}
enc_freres_bulk *bulk;
hdl->inbuf_busy = 1;
list_for_each_entry(bulk, &hdl->head, entry) {
if (id & bulk->id) {
/* bulk->id = id; */
if ((bulk->len + len) <= hdl->in_packet_len) {
/* encmpt_log("inbuf id 0X%x, len %d, %d\n", id, bulk->len, len); */
memcpy(((u8 *)bulk->in) + bulk->len, (u8 *)buf, len);
bulk->len += len;
} else if (bulk->len < hdl->in_packet_len) {
encmpt_log("id 0X%x, inbuf soon be full\n", id);
memcpy(bulk->in + (bulk->len >> 1), buf, hdl->in_packet_len - bulk->len);
bulk->len = hdl->in_packet_len;
} else {
encmpt_log("id 0X%x, inbuf full\n", id);
}
#if AUDIO_ENC_MPT_FRERES_ASYNC
if (bulk->len >= hdl->in_packet_len) {
audio_enc_mpt_fre_response_post_run(bulk->id);
}
#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
}
}
hdl->inbuf_busy = 0;
return;
__err1:
/* encmpt_log("inbuf err\n"); */
int i = 0;
while (id) {
if (id & BIT(0)) {
putchar('0' + i);
}
id >>= 1;
i++;
}
}
//音频测试频响计算运行
void audio_enc_mpt_fre_response_post_run(u16 id)
{
if (!hdl) {
return;
}
if (hdl->state != ENC_FRE_RES_STATE_RUN) {
return;
}
#if AUDIO_ENC_MPT_FRERES_ASYNC
os_taskq_post_msg("enc_mpt_self", 2, ENC_FRE_RESPONE_MSG_RUN, id);
#else
audio_enc_mpt_fre_response_process(0);
#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
}
//音频测试频响计算停止
void audio_enc_mpt_fre_response_stop(void)
{
if (!hdl) {
return;
}
encmpt_log("%s \n", __func__);
enc_freres_bulk *bulk;
hdl->state = ENC_FRE_RES_STATE_STOP;
while (hdl->inbuf_busy || hdl->run_busy) {
os_time_dly(1);
};
list_for_each_entry(bulk, &hdl->head, entry) {
if (bulk->cnt) {
//数据只有实部,因此 point >> 1
anc_HpEst_psd_out(bulk->out, AUDIO_ENC_MPT_FRERES_POINT >> 1, bulk->cnt);
/* encmpt_log("cnt %d \n", bulk->cnt); */
}
}
encmpt_log("%s ok\n", __func__);
}
//工具获取数据文件
int audio_enc_mpt_fre_response_file_get(u8 **buf)
{
if (!hdl) {
return 0;
}
encmpt_log("%s, len %d\n", __func__, hdl->file_len);
*buf = hdl->file_data;
/* audio_enc_mpt_inbuf_printf(); */
/* put_buf(hdl->file_data + 40, hdl->file_len - 40); */
#if 0//debug
enc_freres_bulk *bulk;
int point = AUDIO_ENC_MPT_FRERES_POINT / 2;
list_for_each_entry(bulk, &hdl->head, entry) {
encmpt_log("bulk id 0X%x\n", bulk->id);
for (int i = 0; i < point; i++) {
printf("%d\n", (int)(bulk->out[i] * 10000));
}
}
#endif
return hdl->file_len;
}
//数据获取结束,释放内存
void audio_enc_mpt_fre_response_release(void)
{
if (!hdl) {
return;
}
//mic_close
encmpt_log("%s\n", __func__);
while (hdl->inbuf_busy || hdl->run_busy) {
os_time_dly(1);
};
#if AUDIO_ENC_MPT_FRERES_ASYNC
task_kill("enc_mpt_self");
#endif/*AUDIO_ENC_MPT_FRERES_ASYNC*/
enc_freres_bulk *bulk;
list_for_each_entry(bulk, &hdl->head, entry) {
free(bulk->in);
}
free(hdl->file_data);
free(hdl->bulk);
free(hdl);
hdl = NULL;
encmpt_log("%s ok\n", __func__);
}
#endif/*AUDIO_ENC_MPT_SELF_ENABLE*/