总结
自己定义算法要添加在hifi工程里
hifi工程在wiki上可以下载,名字叫做project
在main.c里添加了自己的算法,算法的执行涉及到通道与effect_id
编译hifi项目需要安装 XtensaTool 与hifi4 configuration file
编译成功后移植bin文件
通过hifi4_effect_audio_process调用hifi里的算法.
hifi工程总结
hifi与riscv的数据通信是通过共享内存与软中断tx.
RISCV 将准备好的数据-> HFMEM->软中断->HIFI4 读取 RISCV 放的数据进行处理->软中断-> RISCV 程序拿回处理之后的数据。
895x 中编解码,混响降噪等音效函数都是通过hifi算法处理
hifi4_effect_audio_process是app用来向hifi传输数据的,参数cpu1t0_idx 代表通道数x,
例如cpu1t0_idx =0 , 通道0处理 ,即cpu1_sw0_process中处理
下载hifi工程原包project
原包在BT895X 领夹麦/无线话筒SDK
hifi4编译环境搭建
参考BT895X HIFI4开发指南
主要是下面三步
安装 xtensa
需要去找蓝讯申请激活码
Configuration Package 安装
在参考链接BT895X HIFI4开发指南下载HIFI4_win32_redist-ID636799.tgz
设置Code Blocks的 HIFI4 Compiler 配置
hifi4编译环境配置好之后,就可以打开hifi工程,修改代码编译
添加自定义算法在hifi工程里
添加增益算法的效果是对音频效果添加gain
- 在project原包的main.c中添加增益算法xt_music_effects_process,
xt_music_effects_process设置增益值,判断样点是否是24位,如果是16位调用pcm_soft_vol_process对音频流增益.
//参数: ptr:指向16位有符号整数音频数据的指针 gain:Q15格式的增益值 samples:需要处理的采样点数
void pcm_soft_vol_process(s16 *ptr, int gain, int samples)//16位音频音量调节
{my_printf("soft_vol_16bits\n");int i, val;ae_int32x2 d0, d2, d3;//32位×2的SIMD寄存器ae_int16x4 d1; //16位×4的SIMD寄存器(核心优化单元)ae_int64 fa0, fa1, fa2, fa3;//64位扩展精度寄存器ae_int16x4 * restrict p_x = (ae_int16x4 *)ptr;//将输入指针转换为AE SIMD访问指针ae_int16x4 * restrict p_y = (ae_int16x4 *)ptr;//restrict关键字:向编译器保证指针不重叠,每次处理4个16位采样点(SIMD宽度)int shift = 32 - 15;//32位中间精度 - 15位增益精度 = 17位右移量d0 = AE_MOVDA32(gain);//将标量增益值加载到SIMD寄存器,增益值被广播到所有通道for (i = 0; i < samples / 4; i++) {AE_L16X4_IP(d1, p_x, sizeof(ae_int16x4));//从内存加载4个16位值到d1fa0 = AE_MUL32X16_L0(d0, d1);//d0低32位 × d1第0通道(16位)fa1 = AE_MUL32X16_L1(d0, d1);//d0低32位 × d1第1通道fa2 = AE_MUL32X16_H2(d0, d1);//d0高32位 × d1第2通道fa3 = AE_MUL32X16_H3(d0, d1);//d0高32位 × d1第3通道,//结果存储在64位寄存器(防止溢出)d2 = AE_TRUNCA32X2F64S(fa1, fa0, shift);//将两个64位结果截断为32位d3 = AE_TRUNCA32X2F64S(fa3, fa2, shift);//应用17位右移(32-15=17),组合为ae_int32x2寄存器(d2和d3)d1 = AE_SAT16X4(d3, d2);//将两个32位×2寄存器饱和到16位范围,确保结果在-32768到32767之间,组合为ae_int16x4寄存器(d1)AE_S16X4_IP(d1, p_y, sizeof(ae_int16x4));//将处理结果存储回内存,}
}void xt_music_effects_process(xt_ipc_cb_t *pcm)
{u32 in_nch = pcm->nchannel;//音频通道数u32 samples = pcm->samples;//每个通道采样点数u32 is_24bit = pcm->in_24bits;//24位标志int gain = 0x7800;//Q15格式增益值(0x7800 约等于 0.9375)if (is_24bit) {my_printf("soft_vol_24bits\n");} else {pcm_soft_vol_process((s16 *)pcm->buf, gain, samples * in_nch);}// alg_user_process((u8*)pcm->buf, pcm->samples, pcm->nchannel, pcm->in_24bits); //鐢ㄦ埛绠楁硶process//调用用户定义的音频处理函数,传递 PCM 缓冲区、采样信息等参数,在音量调整后应用用户算法 (如均衡器、混响等)
}
- 设置算法调用条件
app层想调用hifi算法,需要通过通道数与effect_id,类似于通过通道数与effect_id给hifi编号,然后app层根据编号调用
例如设置通道1且effect_id=21时调用xt_music_effects_process
//通道1处理
AT(.text.isr) OPTIMIZE_SIZE
void cpu1_sw1_process(void)
{...} else if (ipc_pcm->effect_id == 21) {xt_music_effects_process(ipc_pcm);} else {
...
}
写好代码后,编译项目,把编译结果移到app层
编译成功后移植bin文件
工程文件会在编译后自动运行 postbuild.bat,生成iram.bin、dram.bin、sram.bin三个文件。HIFI4 编译完成之后,复制 3 个 HIFI4 的 bin 文件到app\projects\earphone\Output\bin\res\hifi4 目录下.app层就能调用hifi4中的算法了.
app层调用hifi4算法
app层通过hifi4_effect_audio_process函数调用hifi算法,hifi4_effect_audio_process的参数cpu1t0_idx为通道数,参数effect_id为ipc_pcm->effect_id
#define hifi_xt_music_process(ibuf, samples, pcm_info, obuf) hifi4_effect_audio_process(CPU0T1_DEC_IDX, 21, ibuf, samples, pcm_info, obuf);
hifi_xt_music_process与hifi的通道1 effect_id=21的hifi算法绑定.
定义在音频流中运行的函数,在该函数内调用hifi4_effect_audio_process
hifi_echo_mic_cfg_t hifi_echo_mic_cfg AT(.buf.hifi_echo);
void hifi_echo_mic_audio_input1(u8 *ptr, u32 samples, int ch_mode, void *params)
{u32 pcm_info = (0<<28) | ((0&0x0f)<<24) | (0<<16) | ch_mode;hifi_xt_music_process((u8*)ptr, samples, pcm_info,(u8*)ptr);//输出到下一级if (hifi_echo_mic_cfg.callback) {hifi_echo_mic_cfg.callback((void *)ptr, samples, ch_mode, params);}
}AT(.text.hifi_echo_set)WEAK
void hifi_echo_mic_output_callback_set1(audio_callback_t callback)
{hifi_echo_mic_cfg.callback = callback;
}AT(.text.hifi_echo_init)WEAK
void hifi_echo_mic_init1(u8 sample_rate, u16 samples, u8 channel)
{// memset(&echo_cfg,0,sizeof(echo_cfg));
}
在音频流中添加hifi_echo_mic_audio_input1
static ws_link_list_t adapter_mic_rx_cfg_tbl[] = {
/* 模块类型, 使能, 初始化, 输入接口, 设置输出*/{DECODER_PRIO_TRANS_TYPE, 1, decoder_prio_trans_init, NULL, decoder_prio_trans_audio_output_callback_set},{HIFI_ECHO_TYPE, 1, hifi_echo_mic_init1, hifi_echo_mic_audio_input1, hifi_echo_mic_output_callback_set1}, //ECHO#if ADAPTER_DAC_OUTPUT_EN{DAC0_OUT_TYPE, 1, dac0_out_init, dac0_out_audio_input, dac0_out_audio_output_callback_set}, //DAC输出
#endif};