第三方音效算法接入介绍_20230712.01
第三方音效算法接入介绍
珠海市杰理科技股份有限公司
Zhuhai Jieli Technology Co.,LTD
版权所有,未经许可,禁止外传
http://www.zh-jieli.com/
修改记录
| 版本 | 更新日期 | 描述 |
|---|---|---|
| V1 .0 | 2023/7/6 | SDK第三方音效算法接入介绍 |
| 更新: | ● 建立初始版本 |
目录
Chapter 1 使用说明.........................................................................................................................4
- 1编写目的.............................................................................................................................. 4
Chapter2 第三方算法接入介绍........................................................................................................5 - 1 earphone SDK 音乐播放音效算法.................................................................................... 5
2.2 soundbox SDK音乐播放音效算法.................................................................................... 7
2.3 算法移植FAQ ................................................................................................................... 13
2.3. 1 log输出配置........................................................................................................... 13
2.3.2 资源跟踪................................................................................................................ 13
2.3.3 硬件加速模块........................................................................................................ 14
2.3.4 动态操作音效bypass/enable 问题....................................................................... 14
2.3.5 运行开销问题........................................................................................................ 15
2.3.6 算法运行时间估算................................................................................................ 15
2.3.7 代码异常(exception) .........................................................................................15
Chapter 1 使用说明
1. 1编写目的
该文档主要描述了杰理现有的 AC897N/AD697N 系列 earphone SDK、 AC700N 系列 earphone SDK、 AC701N系列 earphone SDK 以及AC695N系列 soundbox SDK、 AC701N系列 soundbox SDK上由于第三方音效算法接入的说明。
| 系列 | SDK类型 | 备注 |
|---|---|---|
| AC695N | soundbox | |
| AC897N/AD697N | earphone | |
| AC700N | earphone | |
| AC701N | earphone | |
| soundbox |
介绍说明了表述了如何第三方算法如何接入到杰理平台的代码路径以及具体接口代码,以及常见问题排查与常用硬件加速模块的使用介绍。
Chapter2 第三方算法接入介绍
2. 1 earphone SDK 音乐播放音效算法
音乐播放,主要是蓝牙高级音频(A2DP)的音效算法接入到SDK流程分三步处理。
1、 使能第三方音效算法开发
宏定义主要用于控制音效算法接入的代码块打开与裁剪,通常将宏定义设置在板级头文件中,例如:board_ac700n_demo_cfg.h
2、 音效算法实现接口
AC700N、 AC897N/AD697N系列蓝牙高级音频(A2DP)的主流程打开(初始化)、关闭以及效果处理代码位于 cpu/br36/audio/audio_dec.c、 cpu/br30/audio_dec.c 文件中, AC701N 1.5.0版本后的蓝牙高级音频(A2DP)的主流程代码位于cpu/br28/a2dp_dec.c 文件中。
AC700N 系 列 第 三 方 音 效 算 法 位 于 cpu/br36/audio/audio_effect_develop.c, AC897N/AD697N 系列存放于 cpu/br30/audio_effect_develop.c, AC701N 系列存放于 cpu/br28/audio_effect_develop.c。
| 系列 | 开发路径 |
|---|---|
| AC897N/AD697N | cpu/br30/audio_effect_develop.c |
| AC700N | cpu/br36/audio/audio_effect_develop.c |
| AC701N | cpu/br28/audio_effect_develop.c |
高级音频的a2dp_dec_start()函数集成解码初始化/打开和音效模块初始化/打开,第三方音效算法在其中的调用示例为:
(1)算法初始化
8. a2dp_effect_develop_setup(dec) ;
9.
10. a2dp_drop_frame_stop();
11. dec->remain = 0 ;
12. a2dp_decoder_match_system_clock (dec) ;
13. /* dec->state = A2DP_STREAM_START; */
14. err = audio_decoder_start(&dec->decoder) ; 15.
16. }
(2)音效关闭
- static int a2dp_audio_ res_close (void)

(3)音效算法处理函数
音效算法的主流程通常在a2dp_dec_output_handler()函数中处理,数据同步进出的添加示例为(仅截取上下文部分参考):
(4)A2DP 中关于第三方算法的调用
- static int a2dp_effect_develop_setup( struct a2dp_dec_hdl *dec)
- {
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
- dec->effect_develop = audio_effect_develop_open(dec->sample_rate, dec- > c h, 16) ;
- #endif
- return 0 ;
- } 8.
- static void a2dp_effect_develop_close( struct a2dp_dec_hdl *dec)
- {
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
- if (dec->effect_develop) {
[13.](13. audio_effect_develop_close)[ audio_effect_develop_close](13. audio_effect_develop_close)(dec->effect_develop); - dec->effect_develop = NULL;
- }

- #endif 17. }
AC701N 系列 1.5.0 版本及之后的版本与 AC700N 调用方法稍有不同,无需要将 audio_effect_develop_data_handler()放到解码输出的流程显式调用,仅需要在打开音效位置配置其加入到stream 的节点即可,其调用方法为:
- static int a2dp_effect_develop_setup( struct a2dp_dec_hdl *dec)
- {
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
- dec->effect_develop = audio_effect_develop_open(dec->sample_rate, dec- > ch, 16) ;
- a2dp_stream_node_add(dec, dec->effect_develop, audio_effect_develop_data_handler, NULL, NULL, 0);
- #endif
2.2 soundbox SDK音乐播放音效算法
1、 使能第三方音效算法开发
与 earphone 系列 SDK 添加方法类似,宏定义仍然放在板级的头文件中,例如: board_jl701n_demo_cfg.h

2、 音乐播放通路的音效接口添加
| 系列 | 开发路径 |
|---|---|
| AC695N | cpu/br23/audio_effect/audio_effect_develop.c |
| JL701N | cpu/br28/audio_effect/audio_effect_develop.c |
audio_effect_develop 中通过audio_effect_develop_open()、 audio_effect_develop_close()函数抽象了播放流程的调用方法,仅需要在此实现具体的算法接入即可。以下提供了音乐播放通路添加对于第三方音效算法接口调用的实例。
(1)蓝牙音频播放调用示例:
蓝牙音频的调用添加需要在 audio_dec_bt.c 增加几项调用处理, 首先 include audio_effect_develop.h头文件:
- #include "audio_effect_develop .h "
a2dp_dec_hdl 中需要添加如下成员:
audio_effect_develop 的打开应在a2dp_dec_start()中调用,示例如下:
- static int a2dp_dec_start(void)
- {
- #if AUDIO_VBASS_CONFIG
- if (dec->vbass_prev_gain ) {
- entries [entry_cnt++] = &dec->vbass_prev_gain->entry; 7. }
- if (dec->ns_gate) {
- entries [entry_cnt++] = &dec->ns_gate->entry;
- }
- if (dec->vbass) {
- entries [entry_cnt++] = &dec->vbass->entry; 13. }
- #endif
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
- dec->effect_develop_entry = audio_effect_develop_open(fmt->sample_rate, ch_num, global_bit_wide ) ;
- if (dec->effect_develop_entry) {
- entries [entry_cnt++] = dec->effect_develop_entry;
- }
- #endif

- #if defined (TCFG_MUSIC_HARMONIC_EXCITER_ENABLE) &&TCFG_MUSIC_HARMONIC_EXCITE R ENABLE
- if (dec->harmonic_exciter) {
- entries [entry_cnt++] = &dec->harmonic_exciter->entry; 25. }
- #endif 27.
- }
audio_effect_develop 的关闭应在a2dp_audio_res_close()中调用,示例如下:
| 1. 2. 3. 4. | stat { | ic . | void a2dp_audio_ res_close(void) DIO_VBASS_CONFIG | ||
|---|---|---|---|---|---|
| #if | AU | ||||
| 5. | au | dio_gain_close_demo(bt_a2dp_dec->v bass_prev_gain ) ; | |||
| 6. | ![]() | au | dio_noisegate_close_demo(bt_a2dp_dec->ns_gate) ; | ||
| 7. | au | dio_v bass_close_demo(bt_a2dp_dec->vbass) ; | |||
| 8. | #end | if | ![]() | ||
| 9. | co | nvet_data_close(bt_a2dp_dec->convert_16_to_ 32) ; | |||
| 10. | ![]() | co | nvet_data_close(bt_a2dp_dec->convert_32_to_16) ; | ||
| 11. | |||||
| 12. | ![]() #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE) | ||||
| 13. | audio_effect_develop_close(dec->effect_develop_entry) ; | ||||
| 14. | ![]() #endif | ||||
| 15. #if defined (TCFG_MUSIC_HARMONIC_EXCITER_ENABLE) R ENABLE | &&TCFG_MUSIC_HARMONIC_EXCITE | ||||
| 16. | ![]() audio_harmonic_exciter_close_api (bt_a2dp_dec->harmonic_exciter) ; | ||||
| 17. | #endif | ||||
| 18. | ![]() . . . . . . | ||||
| 19. } |








(2)文件音频播放调用示例:
文件音频播放的调用在audio_dec_file.c 中增加,第三方算法 entry 成员变量添加及 include头文件需要在 audio_dec_file.h 中添加,其中成员变量需要添加在struct file_dec_hdl 中:
audio_effect_develop的打开应在audio_dec_file.c 中的file_dec_start()中调用,示例如下:
- static int file_dec_start(v。id)
- { 3.
- #if AUDIO_VBASS_CONFIG
- if (dec->vbass_prev_gain ) {
- entries [entry_cnt++] = &dec->vbass_prev_gain->entry;
- }
- if (dec->ns_gate) {
- entries [entry_cnt++] = &dec->ns_gate->entry;
- }
- if (dec->vbass) {
- entries [entry_cnt++] = &dec->vbass->entry;
- }
- #endif 16.
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
- dec->effect_devel。p_entry = audi。effect_devel。p。pen(dec->file_dec . sample_rate, dec->file_dec .。utput_ch_num, gl。bal_bit_wide ) ;
- if (dec->effect_devel。p_entry) {
- entries [entry_cnt++] = dec->effect_develop_entry;
- }
- #endif
- #if defined (TCFG_MUSIC_HARMONIC_EXCITER_ENABLE) &&TCFG_MUSIC_HARMONIC_EXCITE R_ENABLE
- if (dec->harmonic_exciter) {
- entries [entry_cnt++] = &dec->harmonic_exciter->entry;
- }
- #endif
- }
audio_effect_develop的打开应在audio_dec_file.c中的file_dec_close()中调用,示例如下: - void file_dec_close (void)

- { 3.
- #if AUDIO_VBASS_CONFIG
[5.](5. audio_gain_close_demo)[ audio_gain_close_demo](5. audio_gain_close_demo)(file_dec->vbass_prev_gain);
[6.](6. audio_noisegate_close_demo)[ audio_noisegate_close_demo](6. audio_noisegate_close_demo)(file_dec->ns_gate);
[7.](7. audio_vbass_close_demo)[ audio_vbass_close_demo](7. audio_vbass_close_demo)(file_dec->vbass); - #endif
- convet_data_close(file_dec->convert_16_to_32) ;
- convet_data_close(file_dec->convert_ 32_to_16) ;
- #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
[13.](13. audio_effect_develop_close)[ audio_effect_develop_close](13. audio_effect_develop_close)(file_dec->effect_develop_entry); - #endif
- #if defined (TCFG_MUSIC_HARMONIC_EXCITER_ENABLE) &&TCFG_MUSIC_HARMONIC_EXCITE R_ENABLE
[17.](17. audio_harmonic_exciter_close_api)[ audio_harmonic_exciter_close_api](17. audio_harmonic_exciter_close_api)(file_dec->harmonic_exciter); - #endif
- }
(3)在混合通道之后调用示例:
如果有将音效处理集成在多个音源混合之后处理的需求,则需要在 audio_dec.c 的 audio_dec_init()函数集中处理,需要注意的是相同音效集成在混合通道之后,无需在其他音乐播放中调用,否则会引入二次处理和不必要的听感问题。音效算法在audio_dec_init()中调用示例如下:
[1.](1. int)[ int](1. int) audio_dec_init()
2. {
3.
4. #if AUDIO_SPECTRUM_CONFIG
5. if ( spec_hdl) {
6. entries [entry_cnt++] = &spec_hdl->entry; 7. }
8. #endif
9.
10. #if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
11. entries[entry_cnt++] = audio_effect_develop_open( sr, channel_num, global_bit_wide ) ;
12. #endif
13.
14. #if AUDIO_VOCAL_REMOVE_EN
15. if (vocal_remove_mix_ch_switch) {
16. entries [entry_cnt++] = &vocal_remove_mix_ch_switch->entry; 17. }
18. #endif 19.
20. }
2.3 算法移植FAQ
2.3. 1 log输出配置
备注:这里以jl701n_soundbox_release_v1 .4.0为例
(1)通过board_config.h确认使用的板级
- /*

- 板级配置选择
- */

- #define CONFIG_BOARD_JL701N_DEMO

- // #define CONFIG_BOARD_JL701N_SOUNDCARD
- // #define CONFIG_BOARD_JL701N_A90

- // #define CONFIG_BOARD_JL701N_BTEMITTER //该板级暂不支持
- // #define CONFIG_BOARD_JL701N_SMARTBOX
- // #define CONFIG_BOARD_JL701N_TWS_BOX
- // #define CONFIG_BOARD_JL701N_UNISOUND_BOX
- // #define CONFIG_BOARD_JL701N_WIRELESS_ 1TN
- // #define CONFIG_BOARD_JL701N_WIRELESS_ 2T1_DUPLEX
- // #define CONFIG_BOARD_JL701N_TEST
(2)通过board_jl701n_demo_cfg.h确认uart IO配置
| 1. 2. 3. | ////// UART配置 // //*// | ||
|---|---|---|---|
| 4. | #define TCFG_UART0_ENABLE | ENABLE THIS MOUDLE | ![]() //串口打印模块使能 |
| 5. | #define TCFG UART0 RX PORT 印可以选择NO_CONFIG_PORT) | NO CONFIG PORT | //串口接收脚配置(用于打 |
| 6. | #define TCFG UART0 TX PORT | IO PORTA 04 | ![]() //串口发送脚配置 |
| 7. | #define TCFG_UART0_BAUDRATE | 1000000 | //串口波特率配置 |






2.3.2 资源跟踪
(1)内存跟踪接口
1 . mem_ stats ();
(2)CPU运行频率跟踪接口
- printf ( "clk_freq : %d\n " , clk_get ( " sys " ) ) ;
2.3.3 硬件加速模块
(1)FFT加速器
| 系列 | 使用范例路径 |
|---|---|
| AC897N/AD697N | cpu\br30\audio\audio_demo\audio_fft_demo .c |
| AC700N | cpu\br36\audio\audio_demo\audio_fft_demo .c |
| AC701N earphone JL701N soundbox | cpu\br28\audio_demo\audio_fft_demo .c |
| AC695N soundbox | cpu\br23\audio_demo\audio_fft_demo .c |
注意1:如果对应系列SDK找不到对应的文件,请使用最新版本的SDK
注意2:不支持浮点,仅支持定点运算
(2)数学函数加速
| 系列 | 引用路径 |
|---|---|
| AC897N/AD697N | include_lib/media/media_new/media/MathFunc_fix .h include_lib/media/media_new/media/MathFunc_float .h 备注:如遇提示重复定义,请将函数定义成static |
| AC700N | include_lib\system\math\cpu\br36\asm\math_fast_function .h |
| AC701N earphone JL701N soundbox | include_lib\system\math\cpu\br28\asm\math_fast_function .h |
| AC695N soundbox | include_lib/media/media_develop/media/cpu/br23/asm/hw_math . h |
注意:如果引用路径里面包含asm 目录,引用示例如下:
1 . # include "asm/math_fast_function .h "
2.3.4 动态操作音效bypass/enable 问题
使用APP层的按键或其他命令方式对效果进行bypass或enable, 由音效算法接口模块内部提供enable/disable接口的,无需在播歌流程中增加其他处理,防止引入歧义; 由外部变量控制enable/disable 的,仅需在effect_develop_data_handler()中处理即可,例如:
- if (dec->effect_develop_enable ) {
- effect_develop_run();
- }
2.3.5 运行开销问题
当音效算法运行时,CPU在当前时钟满载或超载后,音频播放通路必然会发生欠载,即数据流速达不到DAC播放速度,通常会报underrun错误或蓝牙buffer接收满的错误,打印信息为 uuuu (即under run, DAC欠载)、 FFFF(即full,输入溢出)。
此时需要检查算法的运行效率,是否CPU算力满足,当检查算法消耗mips未超过CPU 设计标准负荷,且CPU满载,则有可能为播歌+算法的运行开销处于当前系统时钟(频率)的边界值,那么需要提高系统时钟以确保正常运行。提升系统时钟可以在a2dp_dec_start()函数中的如下位置进行设置:
2.3.6 算法运行时间估算

2.3.7 代码异常(exception)
音效算法运行出现CPU异常,有几种情况需要注意:
1)watch_dog异常:通常由于算法执行了CPU设计标志之外的mips开销导致CPU超载导致异常;
2)cpu read/write mmu异常:通常为算法内部中对数据处理读/写越界









