KDocs 研发资料库
  • 音频技术应用文档入口汇总
  • 杰理WINDOWS环境安装及其他事项
  • LINUX安装和编译
  • Linux环境编译SDK教程(ubuntu18.04)
  • 音频类补丁汇总表
  • 认证资料获取汇总(最新资料后台会更新)
  • 《Hi-Res申请指南v1.0》
  • FreeRTOS 开源协议版本
  • uCOS 开源协议版本信息
  • 各个模块关键资料汇总
  • 软件调试方法
  • Makefile编译
  • 提bug的规范
  • 常规设备使用指导
  • 对外特别发布开发注意点信息汇总
  • AD697X软件问题整理
  • AC700N软件问题整理
  • AC701X耳机软件问题整理
  • 951&961软件问题整理
  • AC104X软件问题整理
  • AC128N问题整理文档
  • 可视化工具调试问题整理
  • 耳机资料汇总
  • AC704N、 AC705N相关应用
  • AC695N&AC696N&AC608N音箱问题整理
  • JL701N音箱问题整理
  • AC692X软件问题整理
  • AC706N音箱问题整理
  • JL701N音箱问题整理(可视化工具SDK)
  • JL703N音箱问题整理
  • JL709N(JL689N)音箱问题整理
  • JL7094系列-入门到进阶开发指导
  • AC210N音箱问题整理
  • 无线麦系列版本支持指南
  • AW32N无线麦问题整理
  • lAD697X&JL701X 无线麦软件共性问题整理
  • AC706N无线麦问题整理
  • AW36N无线麦问题整理
  • AC710X无线麦问题整理
  • 唤醒源获取及唤醒IO设置
  • 电源
  • LVD
  • 长按复位配置方法
  • 低功耗应用
  • TIMER
  • UART
  • SPI
  • 内部FLASH空间添加用户自定义区域
  • IIC
  • GPIO
  • MCPWM
  • SD&U盘
  • 时钟&晶振
  • GPCNT
  • IO口crossbar映射功能
  • 文件系统使用总结
  • 复用应用
  • LINEIN_AUX相关应用
  • IIS音频接口应用
  • SPDIF模式相关(HDMI_ARC、光纤、同轴)
  • PDM LINK
  • 外设相关应用
  • 蓝牙相关
  • 杰理蓝牙距离调试文档
  • TWS耳机配对方式使用及生产把控指南
  • GFP谷歌快连及其认证流程指引
  • 蓝牙发射器(bt_emitter)相关
  • BLE应用
  • 关于提升BLE传输速率说明
  • BLE测试数据
  • MUSIC 模式相关应用
  • MIDI音乐实现
  • PC相关应用
  • FM相关应用
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20250107
  • fm应用详细设计说明书
  • 杰理FM硬件指南-20230315
  • ADC模块
  • AUDIO相关应用
  • 新Tools的音效调试使用
  • 混响应用使用说明
  • 音效调式
  • 音箱耳机低音小音量增强实现方法
  • DAC输出功率调试
  • DAC性能测试指南
  • 针对各类底噪、电流声分析流程
  • 录音相关应用
  • OPUS编解码相关
  • RTC相关应用
  • 升级相关
  • UI相关应用
  • 通话调试流程指南
  • 通话相关应用
  • 省电容mic使用手册
  • 如何测试验证手表通话系统的语音失真 V1.0
  • AC695X_AC696X_AD697X 常见通话问题处理参考资料
  • 通话调试问题确定步骤
  • 内置触摸调试指南
  • 低功耗内置触摸介绍V2.2
  • 触摸相关文档
  • AC697X、AC698X内置触摸调试及整改方法V1.0
  • 产测相关应用
  • AC63X BLE DUT测试介绍
  • 兆华序列使用简易说明
  • JL_1T2蓝牙测试盒音频文件更换说明
  • ENC相关应用入口汇总
  • ANC相关应用入口汇总
  • JL DMS通话调试手册-V3.9.4
  • ANC-ENC结构设计要点-20240407
  • 半入耳式ANC耳机器件选型与结构设计指南V1.0
  • JL 耳道自适应调试指南
  • ANC相关问题处理
  • ANC调试文档
  • 评估蓝牙耳机通话上行降噪性能的方法 V1.0 (2)
  • FCC 或者 BQB 认证相关应用
  • BQB profile 测试中常遇到的问题点汇总
  • 蓝牙参数整理20210811
  • 杰理科技认证问题参考
  • 无线音频产品开发指南
  • 无线麦系列从入门到进阶开发指导
  • 量产烧录相关说明
  • 一拖八烧录器远程过程调用说明
  • 量产相关建议
  • EffectTool(eq)调试工具说明文档
  • AC897AD697系列的EQ调试方法-V3
  • 杰理调音指南-20220622
  • 音效模块总结
  • 简要调音步骤指引(可视化)
  • 耳机充电与通信调试指南
  • 充电仓硬件调试指南
  • 充电仓软件问题整理
  • AC951常用说明
  • AC951_AC961_开发板使用说明V1.0
  • 彩屏仓AC982 入门指导及FAQ
  • 蓝牙音频APP相关应用
  • 手机APP的简介和开发流程
  • 蓝牙音频系列-硬件设计指南
  • 静电测试及整改方法-20220706
  • TWS耳机底噪整改指南V1.2
  • 杰理蓝牙距离调试文档
  • 蓝牙RF硬件设计与调试V1.1-20250219
  • AC695N_AC696N FM天线ESD静电防护措施说明V2.0_20241228
  • 音效调试指南
  • 无线话筒K歌音箱标准开发流程
  • 杰理科技 700N TWS耳机产品标准-202303
  • 杰理科技 701N 广播产品标准-202303
  • JL-HAT ANC高效产测自适应
  • 无线话筒测试板使用介绍
  • 一拖八频偏校准使用说明
  • 领夹麦产测工具使用介绍
  • Dongle量产测试说明
  • Dongle+Tws或头戴式 SDK通过工具绑定配对功能说明文档
  • 双麦ENC产测宏配置验证方法 V1.0
  • JL耳机方案麦克风声学测试指令_V1.0
  • JL耳机方案麦克风声学测试指令_V2.0
  • JL_ENC自动测试命令_V0.0.1
  • JL蓝牙测试盒用例说明
  • LDAC自测环境搭建_ubuntu
  • 延迟小板使用手册
  • 杰理库文件的制作及添加实现过程
  • 关于 AC635N&AC636N系列免晶振兼容性补丁 说明
  • 关于 AC63系列VM兼容性修复补丁_20250224 说明
  • 关于 AC632N &AE632N_ 蓝牙& 低功耗兼容性修复补丁 说明
  • AD698N和AC638N电压优化补丁V3说明
  • 关于 AC635N&AC636N漏电和E&G版兼容联合补丁 说明
  • AD698N和AC638N电压优化补丁V2说明
  • 702相关应用
  • 2024-4-30 发布歌词显示SDK开发注意事项
  • BQB RF & FCC 认证测试固件问题汇总及源码
  • BQB profile 测试中常遇到的问题点汇总
  • 进dut测试模式方法及固件
  • 704-频偏修改bin文件合集
  • 701手表BQB PROFILE认证注意事项
  • 认证的干扰规避整改
  • 海外CRA认证报告生成说明
  • JL700N可视化工具问题处理文档
  • JL701X可视化工具问题处理文档
  • JL701N_earphone_release_v1.6.0_ANC 低功耗问题补丁
  • JL708X可视化工具问题处理文档
  • JL709N可视化工具问题处理文档
  • JLstudio可视化工具使用说明
  • 一拖二-串口_蓝牙_app在线EQ、通话参数及调试方式和内置触摸调试
  • 可视化JL701M_DONGLE_SDK添加MIC为发射源
  • 可视化JL701M_DONGLE_SDK添加按键切换usb audio与MIC发射源
  • JL701M_DONGLE_SDK_1.0.0_dongle输入linein输出dac
  • 701可视化_a2dp_to_le_demo说明
  • 耳机系列demo汇总
  • JL7018F&JL7006F_7003F AUX IIS
  • 一键连接应用
  • 普通SDK动态开关一拖二功能
  • 蓝牙分析仪(EllisysBluetoothAnalyzer)抓包例程
  • TWS配对常见应用
  • APP自定义按键的demo
  • AC700N 播歌双EQ DEMO示例及说明
  • AC698V164 MIC与蓝牙音乐共同输出DAC demo
  • 添加第三方算法以及多算法授权流程
  • 空间音频配置方法
  • 普通高低电平TWS耳机控制通讯
  • 入耳检测状态更新demo解析
  • 资源优化(非可视化的SDK)
  • 资源优化(可视化SDK)
  • 翻译耳机、语音识别应用demo
  • 耳机抗干扰问题排查和优化
  • AC698D2 抗干扰优化
  • AC696X软件问题整理
  • AC695X软件问题整理
  • AC695X软件问题整理_1722249702
  • AC608X软件问题整理
  • JL701N_2T1_DUPLEX 应用软件问题汇总
  • le_audio_1.0.0_patch05 以及之前的版本IRkey 功能异常修改
  • AC706N-le_audio-200SDK有线_无线麦录音demo
  • jl701n_le_audio_v200patch02 IO串口升级修改串口单次发送字节长度的修改办法
  • 703创建IIS 输入dac输出音频流demo
  • 703将媒体流音频同时上传PC_mic录音demo实现
  • 703四路IIS输入输出demo
  • 底噪调试
  • AW328A烧录说明
  • 文档合集
  • AC706N_wireless_mic_release_PATCH_20240712 补丁 说明
  • AC706N_wireless_mic_release_PATCH_20240726 补丁 说明
  • AC706N_wireless_mic_release_V1.0.0、1.0.1、1.0.2 补丁 说明
  • AC706N_wireless_mic_release_V1.1.2 中的2T1应用 RX端不绑定配对,TX端实现绑定配对的修改方法
  • 各系列省晶振实现方法
  • iis tx rx说明文档
  • spdif信号
  • 蓝牙电话本
  • 安卓手机同步时间补丁
  • CDC配置
  • PC模式下增加Teams唤起功能
  • 杰理HDMIARC开发实现过程
  • AC701N patch06之前的版本用第三方算法节点实现新版本的pcm delay节点功能
  • (K歌音箱)各SDK音效配置相关说明
  • 长文件录音
  • 点阵屏歌词字库相关(蓝牙歌词,普通歌词)
  • 字模提取工具说明
  • 音箱可视化彩屏-入门到进阶开发指导
  • 彩屏LVGL UI设计及工具使用
  • 使用内部UI框架进行UI调试的系列步骤
  • AD101C使用强制升级工具spi 烧录不了问题处理(测试版本)
  • AD161扩展灯板说明文档
  • 歌词显示器开发注意项
  • 使用硬件数字增益控制通话下行音量(可视化)
  • 杰理小牛产测资料
  • ENC配置说明
  • 通话调试流程指引
  • ANC相关功能demo
  • 无线麦硬件资料汇总
  • 无线麦相关应用
  • 无线麦复杂功能补丁包汇总
  • 无线话筒形态SDK程序&开发经验&问题点分享
  • 双模式结合应用问题汇总
  • 无线麦距离优化案例
  • 无线麦系列中的双工形态(duplex)演变开发对讲机方案开发资料
  • 音箱入门到进阶指导文档(编写中)
  • 蓝牙耳机品控和生产技巧
  • 982过_欠压标志获取异常
  • 如何获取最新涂鸦SDK及库文件
  • 无线话筒K歌音响-调音标准流程
  • 无线话筒产测流程

AUDIO相关应用

📎 原始文档:https://www.kdocs.cn/l/cnOtPP7mbZrW AUDIO相关应用

一、通用函数

  1. 正弦波生成函数 a.固定数据
const s16 tsin_48k[48] = {
    0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
    14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
    14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
    0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
    -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
    -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
};

int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
{
    while (points--) {
        if (*s_cnt >= 48) {
            *s_cnt = 0;
        }
        *data++ = tsin_48k[*s_cnt];
        if (ch == 2) {
            *data++ = tsin_48k[*s_cnt];
        }
        (*s_cnt)++;
    }
    return 0;
}
/* test */
static u16 user_cnt;
get_sine_data(&user_cnt,数据buff,长度,多少通道);
  1. 代码生成一个周期的频点数据
    1. 初始化接口:

      1. 如果只是一个正弦波数据使用generate_sine_wave
      2. 如果需要生成多个正弦波数据使用generate_sine_wave_ret接口并保存返回结构体
    2. 获取数据接口:

      1. 如果只是一个正弦波数据使用sine_data_get
      2. 如果需要获取多个正弦波数据使用generate_sine_wave_ret接口并保存返回结构体
#include <stdio.h>
#include <math.h>

typedef struct _SINE_WAVE_DATE_ {
    s16 *data;//数据地址
    int len;//数据长度
    int offset;//取数的偏移量
}sine;

static sine wave={.data=NULL,.len=0,.offset=0};

/*
 * 获取已知正弦波数据
 返回:获取到的数据,每调用一次偏移地址加一
*/
s16 sine_data_addr_get(sine *addr){
    if(!addr||!addr->data||addr->len<=0){
        return 0;
    }
    addr->offset=(addr->offset+1)%addr->len;
    return addr->data[addr->offset];
}


/*
 * 生成正弦波数据
*/
sine generate_sine_wave_ret(double sample_rate/* 采样率 */, double frequency/* 正弦波频率 */) {
    sine data={.data=NULL,.len=0,.offset=0};

    // 时间轴增量
    double t_increment = 1.0 / sample_rate;
    // 每个周期的样本数
    int num_samples=sample_rate/frequency;

    data.data=zalloc(sizeof(s16)*num_samples);
    if(!data.data)return data;
    data.len = num_samples;

    // 生成正弦波数据
    for (int i = 0; i < num_samples; i++) {
        double t = i * t_increment;
        data.data[i] = (s16)(32767 *sin(2 * M_PI * frequency * t));
    }

    // 打印样本点作为验证
    printf("样本点:\n");
    for (int i = 0;i < num_samples; i++) {
        // printf("sample %d: %f\n", i, data[i]);
        printf("[i=%d %d]\r\n",i, data.data[i]);
    }
    return data;
}

void generate_sine_free_addr(sine *addr){
    if(!addr||!addr->data){
        return ;
    }
    addr->len=0;
    free(addr->data);
    addr->data=NULL;
    return;
}
/*
 * 获取已知正弦波数据
 返回:获取到的数据,每调用一次偏移地址加一
*/
s16 sine_data_get(void){
    return sine_data_addr_get(&wave);
}
/*
 * 生成正弦波数据
 */
void generate_sine_wave(double sample_rate/* 采样率 */, double frequency/* 正弦波频率 */){
    if(wave.data)return;
    wave = generate_sine_wave_ret(sample_rate,frequency);
}

void generate_sine_free(void){
    generate_sine_free_addr(&wave);
}
  1. 立体声的左右声道对调
void pcm_lr_exchange(void *data, u32 len)
{
    s32 valuetemp;
    s16 *buf;
    buf = data;
    len >>= 1; //byte to point

    for (u32 i = 0; i < len; i += 2) {
        valuetemp = buf[i];
                buf[i] = buf[i+1];
                buf[i+1] = valuetemp;
      
    }
}
  1. 立体声的反相处理
void pcm_phase(void *data, u32 len)
{
    s32 valuetemp;
    s16 *buf;
    buf = data;
    len >>= 1; //byte to point

    for (u32 i = 0; i < len; i += 2) {
        buf[i] = (buf[i] == -32768) ? 32767 : -dat[i];        // 左声道
        buf[i+1] = (buf[i+1] == -32768) ? 32767 : -data[i+1]; // 右声道     
    }
}
  1. 立体声的数字音量处理

16bit数据数字音量处理

//单/双声道数字音量处理。用于TWS时l_vol、r_vol设置一样即可
// vol:0~16384(大于16384会把数据放大,有可能出现失真)
int audio_digital_vol_run(void *data, u32 len, u32 l_vol,u32 r_vol)
{
    s32 valuetemp;
    s16 *buf;

    buf = data;
    len >>= 1; //byte to point

    for (u32 i = 0; i < len; i += 2) {
        ///left channel
        valuetemp = buf[i];
        if (valuetemp < 0) {
            valuetemp = -valuetemp; 
            valuetemp = (valuetemp * l_vol) >> 14 ;
            valuetemp = -valuetemp;
        } else {
            valuetemp = (valuetemp * l_vol) >> 14 ;
        }
        if (valuetemp < -32768) {
            valuetemp = -32768;
        } else if (valuetemp > 32767) {
            valuetemp = 32767;
        }
        buf[i] = (s16)valuetemp;
        ///right channel
        valuetemp = buf[i + 1];
        if (valuetemp < 0) {
            valuetemp = -valuetemp;
            valuetemp = (valuetemp * r_vol) >> 14 ;
            valuetemp = -valuetemp;
        } else {
            valuetemp = (valuetemp * r_vol) >> 14 ;
        }
        if (valuetemp < -32768) {
            valuetemp = -32768;
        } else if (valuetemp > 32767) {
            valuetemp = 32767;
        }
        buf[i + 1] = (s16)valuetemp;
    }
    return 0;
}

24bit数据数字音量处理

//单/双声道数字音量处理
// vol:0~16384(大于16384会把数据放大,有可能出现失真)
int audio_digital_vol_run32(void *data, u32 len, u32 l_vol,u32 r_vol)
{
    s64 valuetemp;
    s32 *buf;

    buf = data;
    len >>= 2; //byte to point

    for (u32 i = 0; i < len; i += 2) {
        ///left channel
        valuetemp = buf[i];
        if (valuetemp < 0) {
            valuetemp = -valuetemp; 
            valuetemp = (valuetemp * l_vol) >> 14 ;
            valuetemp = -valuetemp;
        } else {
            valuetemp = (valuetemp * l_vol) >> 14 ;
        }
        if (valuetemp < -8388608) {
            valuetemp = -8388608;
        } else if (valuetemp > 8388607) {
            valuetemp = 8388607;
        }
        buf[i] = (s32)valuetemp;
        ///right channel
        valuetemp = buf[i + 1];
        if (valuetemp < 0) {
            valuetemp = -valuetemp;
            valuetemp = (valuetemp * r_vol) >> 14 ;
            valuetemp = -valuetemp;
        } else {
            valuetemp = (valuetemp * r_vol) >> 14 ;
        }
        if (valuetemp < -8388608) {
            valuetemp = -8388608;
        } else if (valuetemp > 8388607) {
            valuetemp = 8388607;
        }
        buf[i + 1] = (s32)valuetemp;
    }
    return 0;
}
  1. 通用能量值计算(取平均值)

#define ABS(x)                      (x > 0 ? x : (-x))
int audio_output_data_db_calc_simple(short *data, unsigned short len,unsigned char channels)
{
    //长度转换,如果长度是u8 需要/2
    unsigned short points = len / 2;
        unsigned short user_sample_rate = 16000;
    signed int  calc_point = user_sample_rate/50;
    static signed int  data_cnt = 0;
    static signed int  sum[4] = {0,0,0,0};
    static int average_value;

    int index = 0;

    for(index = 0; index < points; index+=channels) {
        //计算数值总和
        switch (channels) {
        case 4:
            sum[3] +=  ABS(data[index+3]);
        case 3:
            sum[2] +=  ABS(data[index+2]);
        case 2:
            sum[1] +=  ABS(data[index+1]);
        case 1:
            sum[0] +=  ABS(data[index]);
            break;
        default:
            sum[0] +=  ABS(data[index]);
            break;
        }
        data_cnt++;
        if(data_cnt>=calc_point) {
            //计算各通道取平均
            average_value= (sum[0]+sum[1]+sum[2]+sum[3])/(channels*calc_point);
            //printf("average_value:%d\n",average_value);
            sum[0] = 0;
            sum[1] = 0;
            sum[2] = 0;
            sum[3] = 0;
            data_cnt = 0;
        }
    }
    return average_value;
}
  1. 通用能量值计算(取最大最小值)
//目前只实现计算单通道
int audio_data_automute(s16 *data, u16 len, u8 channels)
{
    //参数定义
    #define CALC_DATA_SUM 16000   //多长时间更新一次数据
    
    u16 points = len / 2;
    u16 index;
    static s32 min = 0xfffff;
    static s32 max = -100000;
    static s32 cnt_sum = 0;
    s32 db = 0;

    for (index = 0; index < points; index += channels) {
        db = data[index];
        cnt_sum++;
        if (cnt_sum > CALC_DATA_SUM) {
            printf("update : %d\t%d\n",max,min);
            cnt_sum = 0;
            min = 0xfffff;
            max = -100000;
        }
        if (min > db)
            min = db;
        if (max < db)
            max = db;
    }
    return max;
}
  1. 立体声(双声道)音频混合
u32 pcm_mix(void *data, u32 len)
{
    s32 valuetemp;
    s16 *buf;
    buf = data;
    len >>= 2; //byte to point

    for (u32 i = 0; i < len; i++) {
        valuetemp = (buf[2*i] + buf[2*i+1])/2;
        buf[i] = valuetemp;
    }

    return len*2;
}

二、频响(频谱)接口函数

频响:当前声音下每个频点的声音大小

  1. 开启板级配置文件的功能 image
  2. 频响配置后,开机就会打开,位置: image
  3. 参数设置 image
  4. 数据打印处: 单位数字 db,最大值不到 90
    image 注意点:以上获取频响都是获取DAC的数据去做的,在linein走模拟信号输入等情况时,会因为拿不到数据等情况,获取不了频响。
  5. 不同采样率对应第n个数据对应的频率 比如:48K采样率下第0个数据为123.686951hz的声音大小
    【金山文档】 频谱显示中心频率点
    频谱显示中心频率点.xlsx
    image
  6. 用户自定义数据流的频响获取可参考下文此处 【金山文档】 AUDIO相关应用
    AUDIO相关应用.otl
    image

三、音量控制

音量控制的核心原理

音量的本质是音频信号的幅度(电压 / 采样值)大小—— 信号幅度越大,音量越大。

  • 一般我们音频信号流程:数字音频文件(MP3/蓝牙等) → 解码器解码 → 数字信号处理(音量控制、EQ、DRC等音效处理) → 硬件数字音量控制 → DAC数模转换 → 硬件模拟音量控制 → 功率放大器 → 喇叭 一般SDK 提供的两种音量类型(硬件 / 软件),对应不同的信号处理阶段和实现方式。

1. 硬件方式:硬件模拟音量(TYPE_DAC_AGAIN)

原理:模拟信号放大 / 衰减
核心实现:通过硬件内部的模拟运算放大器(运放) 调节增益。比如增益值 0 ~30,对应运放的放大倍数梯度。

2. 硬件方式:硬件数字音量(TYPE_DAC_DGAIN)

原理:数字信号幅度缩放(硬件模拟之前)

  • 核心实现:通过硬件的数字信号处理器(DSP) 对解码后的数字采样值进行乘法运算。比如 14 位精度(0~16384),本质是 “采样值 × 缩放系数”(例:采样值 = 2048,缩放系数 = 0.5 → 输出 1024,音量减半)。

3. 软件方式:软件数字音量

原理:软件音量控制是解码后、硬件数字音量处理前的数字信号缩放运算,通过 CPU/DSP 的软件算法,直接修改音频 PCM 采样值的幅度,从而改变用户感知的音量大小。
核心实现方式:音频信号解码后输出PCM 采样值(如 16 位精度,范围 - 32768~32767),软件音量的核心是对该采样值做 “乘法运算”:
如前面的数字音量处理:

处理后采样值 = 原始采样值 × 软件音量缩放系数
  • 缩放系数:映射用户感知的 “0~100% 音量”,例如:
    • 音量 100% → 系数 = 1.0(采样值不变);
    • 音量 50% → 系数 = 0.5(采样值减半,音量降低);
    • 音量 0%(静音) → 系数 = 0.0(采样值置 0)。

软件数字音量与硬件数字音量的核心差异

对比维度软件音量控制硬件数字音量
实现载体CPU/DSP 软件算法(纯软件)硬件 DSP 模块(专用硬件)
调节精度理论无上限(支持浮点运算)硬件限制(如 14 位 = 16384 级)
灵活度极高(支持复杂算法、自定义逻辑)有限(仅支持基础缩放)
资源占用占用 CPU/DSP 算力无额外算力消耗
延迟轻微(软件运算耗时)无延迟(硬件并行处理)
核心作用用户交互适配、复杂逻辑实现底层精准执行、独立通道硬件加速

1、音量调节接口

  • 音箱SDK
    • 硬件音量控制(硬件数字,硬件模拟)

// type: TYPE_DAC_AGAIN->模拟音量  TYPE_DAC_DGAIN->硬件数字音量
// ch  : BIT(0):FL     BIT(1):FR     BIT(2):RL     BIT(3):RR 
// gain: 模拟音量:一般(0~30)  数字音量(0~16384)
int audio_dac_vol_set(u8 type, u32 ch, u16 gain, u8 fade_en);    

//设置左声道 模拟音量
audio_dac_vol_set(TYPE_DAC_AGAIN, BIT(0), gain_l, fade);
//设置右声道 模拟音量
audio_dac_vol_set(TYPE_DAC_AGAIN, BIT(1), gain_r, fade);
//设置左声道 数字音量
audio_dac_vol_set(TYPE_DAC_DGAIN, BIT(0), gain_l ? DEFAULT_DIGTAL_VOLUME : 0, fade);
//设置右声道 数字音量
audio_dac_vol_set(TYPE_DAC_DGAIN, BIT(1), gain_r ? DEFAULT_DIGTAL_VOLUME : 0, fade);
- 软件数字音量控制(独立通道音量调节实现)

每个解码通道独立音量

//每个解码通道都开启数字音量管理,音量类型为VOL_TYPE_DIGGROUP时要使能
#define SYS_DIGVOL_GROUP_EN     1//DISABLE

#define SYS_VOL_TYPE            VOL_TYPE_DIGGROUP
  • 实际上使能了独立通道音量调节:会在开机的时候固定设置模拟音量跟数字音量

jl701n
image

音乐音量 观察每个通道的音量可以打开以下打印
image - 实际应用

  1. 实现任意音量等级调节—— LZK 步骤1:board文件选择,独立通道数字音量。
    image 步骤2:生成一个数字音量表替换默认的音量表
    (生成音量表方法可以参考:“数字音量表生成方法” )
    image
  2. 四声道音量独立调节 image 示范代码如下:
//变量
#ifdef USER_FOUR_DAC_VOL_CTL_EN
void *four_dac_digvol_last = NULL;
void *four_dac_digvol_last_entry = NULL;
#endif


//添加的节点
#ifdef USER_FOUR_DAC_VOL_CTL_EN
    audio_dig_vol_param four_digvol_last_param = {
        .vol_start = app_var.music_volume,
        .vol_max = SYS_MAX_VOL,
        .ch_total = ch_num,
        .fade_en = 1,
        .fade_points_step = 5,
        .fade_gain_step = 10,
        .vol_list = NULL,
    };
    four_dac_digvol_last = audio_dig_vol_open(&four_digvol_last_param);
    four_dac_digvol_last_entry = audio_dig_vol_entry_get(four_dac_digvol_last);
    entries[entry_cnt++] = four_dac_digvol_last_entry;
#endif


//测试代码
#ifdef USER_FOUR_DAC_VOL_CTL_EN
    case KEY_VOL_RR_VOL_TEST:
        {
            static u8 vol = 0;
            vol++;
            if(vol>30)vol = 0;
            printf("RR VOL %d\n",vol);
            extern void *four_dac_digvol_last;
            audio_dig_vol_set(four_dac_digvol_last,     AUDIO_DIG_VOL_CH(3),vol);
            // audio_dig_vol_set(audio_dig_vol_group_hdl_get(sys_digvol_group, "music_file"),     AUDIO_DIG_VOL_CH(3), vol);
        }
        break;
    case KEY_VOL_RL_VOL_TEST:
        {
            static u8 vol = 0;
            vol++;
            if(vol>30)vol = 0;
            printf("RL VOL %d\n",vol);
            extern void *four_dac_digvol_last;
            audio_dig_vol_set(four_dac_digvol_last,     AUDIO_DIG_VOL_CH(2),vol);
            // audio_dig_vol_set(audio_dig_vol_group_hdl_get(sys_digvol_group, "music_file"),     AUDIO_DIG_VOL_CH(2), vol);
        }
        break;
    case KEY_VOL_FR_VOL_TEST:
        {
            static u8 vol = 0;
            vol++;
            if(vol>30)vol = 0;
            printf("FR VOL %d\n",vol);
            extern void *four_dac_digvol_last;
            audio_dig_vol_set(four_dac_digvol_last,     AUDIO_DIG_VOL_CH(1),vol);
            // audio_dig_vol_set(audio_dig_vol_group_hdl_get(sys_digvol_group, "music_file"),     AUDIO_DIG_VOL_CH(1), vol);
        }
        break;
    case KEY_VOL_FL_VOL_TEST:
        {
            static u8 vol = 0;
            vol++;
            if(vol>30)vol = 0;
            printf("FL VOL %d\n",vol);
            extern void *four_dac_digvol_last;
            audio_dig_vol_set(four_dac_digvol_last,     AUDIO_DIG_VOL_CH(0),vol);
            // audio_dig_vol_set(audio_dig_vol_group_hdl_get(sys_digvol_group, "music_file"),     AUDIO_DIG_VOL_CH(0), vol);
        }
        break;
#endif

2、音量级db值修改 --WTS

如果使用硬件模拟音量调节,音量级对应DB值达不到需求。可以选择使用数字音量或联合音量调节,然后到配置工具中设置每个
音量等级的db值,生产的音量表替换程序中的表:

image

(操作可以看以下第三点:“数字音量表生成方法”参考)
image

替换到程序中数字音量表:
image

替换到程序中的联合音量表:

image

3、数字音量表生成方法

数字音量表生成操作.zip

4、进FM模式不改变当前系统音量等级的情况下降低整体音量

此方法适用的前提条件:
1. 使用的是模拟音量 2. FM模式下没有eq 原理:通过降低数字音量实现整体音量的降低
demo:http://192.168.1.245/soundbox/ac695n-soundbox-sdk/-/tree/FM_DOW_VOL

四、IIS音频接口

IIS音频接口应用.otl

五、HDMI ARC

杰理HDMIARC开发实现过程.otl

六、光纤同轴 S/PDIF

测试设备:
笔记本电脑台式机外置USB声卡转数字同轴光纤5.1输出DTS杜比AC3 黑色【图片 价格 品牌 报价】-京东 (jd.com)

七、DAC

  1. DAC 参数配置
struct dac_platform_data {
    u32 output : 4;             //DAC输出模式
    u32 ldo_volt : 4;           //DACVDD_LDO电压档选择
    u32 ldo_isel : 4;           //LDO偏置电流选择档位, 0:5u, 1:10u, 2:15u, 3:20u, 4:25u, 5:30u, 6:35u, 7:40u
    u32 lpf_isel : 4;           //LPF bias电流选择, 0:无, 1:0.3125u, 2:0.625u, 3:0.9375, 4:1.25u, 5:1.5625, 6:1.875u, 7:2.1875u, 8:2.5u, 9:2.8125u, 10:3.125u, 11:3.4375u, 12:3.75u, 13:4.0625u, 14:4.375u, 15:4.6875u
    u32 ldo_fb_isel : 2;        //LDO负载电流选择, 0:15u, 1:48u, 2:81u, 3:114u
    u32 vcmo_en : 1;            //VCMO直推使能
    u32 keep_vcmo : 1;
    u32 dsm_clk : 1;
    u32 vcm_risetime : 1;       //VCM上电快慢选择
    u32 zero_cross_detect : 1;  //模拟增益过零检测配置
    u32 vdd_setting_enable : 1; //通过接口设置DACVDD电压的使能
};

//****************
//SDK参数  参考配置
//****************
struct dac_platform_data dac_data = {
    .ldo_volt       = TCFG_AUDIO_DAC_LDO_VOLT,                   //DACVDD等级.需要根据具体硬件来设置(高低压)可选:1.2V/1.3V/2.35V/2.5V/2.65V/2.8V/2.95V/3.1V
#if ((TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) || (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_DUAL_LR_DIFF))
    .vcmo_en        = 0,                                         //四声道与双声道差分关闭VCOMO
#else
    .vcmo_en        = 1,                                         //是否打开VCOMO
#endif
    .output         = TCFG_AUDIO_DAC_CONNECT_MODE,               //DAC输出配置,和具体硬件连接有关,需根据硬件来设置
    .ldo_isel       = 3,
    .ldo_fb_isel    = 2,
    .lpf_isel       = 0x8,
};

当需要修改DAC的驱动电流时,建议是修改lpf_isel 这个参数

  • output:DAC输出模式
#define DAC_OUTPUT_MONO_L                  0    //左声道
#define DAC_OUTPUT_MONO_R                  1    //右声道
#define DAC_OUTPUT_LR                      2    //立体声
#define DAC_OUTPUT_MONO_LR_DIFF            3    //单声道差分输出

#define DAC_OUTPUT_DUAL_LR_DIFF            6    //双声道差分
#define DAC_OUTPUT_FRONT_LR_REAR_LR        9    //四声道单端输出(不可设置vcmo公共端)
- 差分输出:有两个输出端,输出的信号是两输出端之间的电压差;
- 单端输出:只有一个输出端,输出的信号是输出端对地的电压。
  1. DAC 当IO使用 AC696:DAC输出高低电平_ac696n_soundbox_sdk_v1.2.2
    AC695: DAC输出高低电平_AC695N_soundbox_sdk_release_3.1.0
  2. 拦截DAC数据做运算
  • AC696 耳机SDK(0.3.1SDK)
void dac_data_write_handler(u8 channel, void *buf, int len)
{
    //DAC 的数据接口
}
  • AC695 /AC696 音箱SDK 具体可以参考本文档的 《九 音频流 —— 2 左右声道数据互换》 这一节
    image
  1. AC695 数据直接推到DAC
  • AC695N_HCI_SDK_release_v0.0.5 添加 DAC直接推数据的函数
    cbp_out\apps\dongle\audio_dev.c

#include "media/includes.h"
s16 dac_io_data[400];
void audio_dac_mute_ch(u8 ch, u8 mute)
{
    if (mute) {
        JL_ANA->DAA_CON1 &= ~((ch & 0xF) << 20);
        JL_ANA->DAA_CON1 &= ~((ch & 0xF) << 24);
    } else {
        JL_ANA->DAA_CON1 |= ((ch & 0xF) << 20);
        JL_ANA->DAA_CON1 |= ((ch & 0xF) << 24);
    }
}

const s16 tsin_48k[48] = {
    0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
    14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
    14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
    0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
    -14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
    -14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
};

int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
{
    while (points--) {
        if (*s_cnt >= 48) {
            *s_cnt = 0;
        }
        *data++ = tsin_48k[*s_cnt];
        if (ch == 2) {
            *data++ = tsin_48k[*s_cnt];提个
        }
        (*s_cnt)++;
    }
    return 0;
}
#define     USER_IO_DEBUG_0(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT &= ~BIT(x);}
#define     USER_IO_DEBUG_1(i,x)       {JL_PORT##i->DIR &= ~BIT(x), JL_PORT##i->OUT |= BIT(x);}
u16 delay_test_cnt = 0;
u16 sin_cnt = 0;
s16 dual_ch_test_buf[1024 * 2];
void dac_io_test(void *priv)
{
    u16 s_cnt = 0;
    u16 len = 640;
    delay_test_cnt++;
    if(delay_test_cnt<200){
        USER_IO_DEBUG_0(A,6);
        return;
    }else
    {
        USER_IO_DEBUG_1(A,6);
        if(delay_test_cnt>400)delay_test_cnt = 0;
    }
    get_sine_data(&sin_cnt,dual_ch_test_buf,len/2/2,2);
    //ch 0:FL 1:FR 2:RL 3:RR   value (-32768) ~ (32767)
    int wlen = audio_dac_write(&dac_hdl, dual_ch_test_buf, len);

    if (wlen != len) {
        /*dac buf写满了*/
        printf("dac full,wlen:%d-%d", wlen, len);
    }
    putchar('#');
}

void dac_output_test(void *priv)
{
    int i;
    audio_dac_set_delay_time(&dac_hdl, 1, 50);
    audio_output_start(8000, 1);
    audio_dac_start(&dac_hdl);
    s16 dac_data[128];
    for (i=0; i<128; i++) {
        dac_data[i] = 32767;    // 开机默认 低
        //dac_data[i] = -32768;    // 开机默认 高
    }
    audio_dac_mute_ch(0xf, 1);
    audio_dac_write(&dac_hdl, dac_data, 256);
    os_time_dly(50);
    audio_dac_set_L_digital_vol(&dac_hdl, 16384);
    audio_dac_set_R_digital_vol(&dac_hdl, 16384);
    audio_dac_set_RL_digital_vol(&dac_hdl, 16384);
    audio_dac_set_RR_digital_vol(&dac_hdl, 16384);

#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR)
    int err = audio_dac_set_analog_vol_support4way(&dac_hdl, 31, 31, 31, 31);
#else
    int err = audio_dac_set_analog_vol(&dac_hdl, 31);
#endif

    JL_AUDIO->DAC_CON &= ~(0xF << 12);
    audio_dac_mute_ch(0xf, 0);
    sys_timer_add(NULL, dac_io_test, 1);
}

image 5. DAC极性修改

  • 数字反相器,用来矫正DAC的输出相位 新的SDK已经有实现该功能,以前的SDK要实现可以参考自行添加,宏定义如下:
#define TCFG_DIG_PHASE_INVERTER_EN    1  //数字反相器,用来矫正DAC的输出相位

实现代码:


#if TCFG_DIG_PHASE_INVERTER_EN
    audio_phase_inver_hdl.entry.data_process_len = audio_phase_inver_output_data_process_len;
    audio_phase_inver_hdl.entry.data_handler = audio_phase_inver_data_handler;
    entries[entry_cnt++] = &(audio_phase_inver_hdl.entry);
#endif/*TCFG_DIG_PHASE_INVERTER_EN*/
  • AC698X DAC极性修改 image
  • AC697X DAC极性修改 先检查代码里面有没有TCFG_DIG_PHASE_INVERTER_EN这个宏,以及下面的代码
    imageimage 有的话直接代码改TCFG_DIG_PHASE_INVERTER_EN宏的值,1是反的话就改成0,0是反的话就改成1 。
    没有TCFG_DIG_PHASE_INVERTER_EN宏就按照上面698的添加既可。
  • 可视化SDK极性修改 需要加个节点,在节点处理中添加上面698的代码
    imageimage
  1. DAC高阻态
  2. AC695 系列设置 DAC 管脚高阻态 注意:下面的接口需要DAVDD电压(2.8V)打开后,才能够实际配置成为高阻态。可以在app_main()调用以下代码段。

    extern struct audio_dac_hdl dac_hdl;
    audio_dac_vdd_power_on(&dac_hdl);
    delay(1000);
    JL_ANA->DAA_CON3 |= BIT(16);
    delay(1000);
    JL_ANA->DAA_CON0 |= BIT(23);
    delay(100);
    JL_ANA->DAA_CON0 |= BIT(0);
    delay(100);
    JL_ANA->DAA_CON0 |= BIT(1);
    delay(100);
    audio_dac_mute_ch(BIT(0)|BIT(1),1);
    os_time_dly(1);

/*
ch: FL:BIT(0) FR:BIT(1) RL:BIT(2) RR:BIT(3)
例如:BIT(0)是 FL 左声道, BIT(1)是 FR 右声道, FLR BIT(0)|bit(1)是立体声
MUTE:1  MUTE    0UNMUTE
*/
void audio_dac_mute_ch(u8 ch, u8 mute)
{
    if (mute) { 
        JL_ANA->DAA_CON1 &= ~((ch & 0xf) << 20);
        JL_ANA->DAA_CON1 &= ~((ch & 0xf) << 24);
    } else {
        JL_ANA->DAA_CON1 |= ((ch & 0xf) << 20);
        JL_ANA->DAA_CON1 |= ((ch & 0xf) << 24);
    }
} 
  1. AC696N 系列设置 DAC 管脚高阻态
/*
ch: FL:BIT(0) FR:BIT(1) RL:BIT(2) RR:BIT(3)
例如:BIT(0)是 FL 左声道, BIT(1)是 FR 右声道, FLR BIT(0)|bit(1)是立体声
MUTE:1:MUTE 0:UNMUTE
*/
void audio_dac_mute_ch(u8 ch, u8 mute)
{
    if (mute) { 
        JL_ANA->DAA_CON1 &= ~((ch & 0x3) << 10);
        JL_ANA->DAA_CON1 &= ~((ch & 0x3) << 13);
    } else {
        JL_ANA->DAA_CON1 |= ((ch & 0x3) << 10);
        JL_ANA->DAA_CON1 |= ((ch & 0x3) << 13);
    }
} 
  1. 706N 系列设置 DAC 管脚高阻态 AC706N音箱问题整理.otl
    //DAC高阻态
    SFR(JL_ADDA->DAA_CON2,    23,  1,   1);            //SDDAC_PA_TRIM_EN_11v
  1. DAC tirm值

  2. AC697X_AC698X_AC700X DAC左右声道trim 值获取

备注:DAC左右声道trim值相差在正负150左右正常。如果相差很大,在播放提示音或蓝牙音乐前会听到一个啵声。这个是由第一次上电时DAC trim时,供电不稳引起。需要确保供电稳定,可以用强升工具重新下载程序,擦掉所有VM数据,然后再重新上电测试。
image

  1. AC695X /AC696X DAC trim值获取

image

image

  1. 697N音量可调参数
/*
 *系统音量类型选择
 *软件数字音量是指纯软件对声音进行运算后得到的
 *硬件数字音量是指dac内部数字模块对声音进行运算后输出
 */
#define VOL_TYPE_DIGITAL        0    //软件数字音量
#define VOL_TYPE_ANALOG            1    //硬件模拟音量
#define VOL_TYPE_AD                2    //联合音量(模拟数字混合调节)
#define VOL_TYPE_DIGITAL_HW        3      //硬件数字音量
#define SYS_VOL_TYPE            VOL_TYPE_AD

#define MAX_ANA_VOL             (10)    //系统最大模拟音量0~15
  1. 使用软件数字音量时,音量表在apps\common\audio\audio_digital_vol.c中的const u16 dig_vol_table[DIGITAL_VOL_MAX + 1]。
  2. 不建议使用硬件模拟音量
  3. 使用联合音量(模拟数字混合调节)时:
    1. 如果使能USE_CONFIG_COMBINE_VOL_SETTING,从配置工具中修改音量
    2. 否则修改combined_vol_list和call_combined_vol_list
  4. 使用硬件数字音量时,可在audio_fade_in_fade_out函数中修改或添加自定义数字音量表,如下图位置: image
  5. 其他影响音量的功能模块:EQ、DRC、ANC,测试时,要关掉EQ、DRC、ANC测试,或者EQ的曲线拉平和总增益置0,ANC的dac增益配置配成15,如图: image
  6. 700N音量可调参数

普通SDK:

#define TCFG_AUDIO_DAC_LDO_VOLT                DACVDD_LDO_1_80V //普通模式 DACVDD有1.8V到2.5V可选,最大音量空载1K 0DB峰峰值1.3V~1.8V,需要更大时TCFG_AUDIO_DAC_LDO_VOLT 可以定义为28,但是VDDIO要提高到3.2V
/*
 *系统音量类型选择
 *软件数字音量是指纯软件对声音进行运算后得到的
 *硬件数字音量是指dac内部数字模块对声音进行运算后输出
 */
#define VOL_TYPE_DIGITAL        0    //软件数字音量(调节解码输出数据的音量)
#define VOL_TYPE_ANALOG            1    //(暂未支持)硬件模拟音量
#define VOL_TYPE_AD                2    //(暂未支持)联合音量(模拟数字混合调节)
#define VOL_TYPE_DIGITAL_HW        3      //硬件数字音量(调节DAC模块的硬件音量)
#define SYS_VOL_TYPE            VOL_TYPE_DIGITAL_HW

#define MAX_ANA_VOL             (15)    // 系统最大模拟音量,范围: 0 ~ 15
#define DEFAULT_DIGITAL_VOLUME   16384  // 硬件数字音量0~16384
  1. 700N仅支持硬件数字音量和软件数字音量
  2. 硬件数字音量表hw_dig_vol_table,软件数字音量表是dig_vol_table,可以通过配置工具-->数字音量配置功能得到想要DB值的音量表,然后替换到hw_dig_vol_table或者dig_vol_table。 imageimage
  3. 其他影响音量的功能模块:EQ、DRC、ANC 测试最大音量时,要关掉EQ、DRC、ANC测试,或者EQ的曲线拉平和总增益置0,ANC的dac增益配置配成15,如图:
    image

可视化SDK:

imageimageimageimage 自定义数字音量的方法
imageimage

按照普通sdk的方式修改下面的表
image

  1. 701N音量可调参数

普通SDK:

硬件上支持多种DAC电压配置,有HPVDD邦出来的,可外接电压最大3V,没有HPVDD这个IO口的,内部默认接VDDIO。

/*
         DAC模式选择
#define DAC_MODE_L_DIFF          (0)  // 低压差分模式   , 适用于低功率差分耳机  , 输出幅度 0~2Vpp
#define DAC_MODE_L_SINGLE        (1)  // 低压单端模式   , 主要用于左右差分模式, 差分输出幅度 0~2Vpp
#define DAC_MODE_H1_DIFF         (2)  // 高压1档差分模式, 适用于高功率差分耳机  , 输出幅度 0~3Vpp  , VDDIO >= 3.0V
#define DAC_MODE_H1_SINGLE       (3)  // 高压1档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~1.5Vpp, VDDIO >= 3.0V
#define DAC_MODE_H2_DIFF         (4)  // 高压2档差分模式, 适用于高功率差分PA音箱, 输出幅度 0~5Vpp  , VDDIO >= 3.3V   
#define DAC_MODE_H2_SINGLE       (5)  // 高压2档单端模式, 适用于高功率单端PA音箱, 输出幅度 0~2.5Vpp, VDDIO >= 3.3V
*/
#define TCFG_AUDIO_DAC_MODE         DAC_MODE_L_DIFF    // DAC_MODE_L_DIFF 低压, DAC_MODE_H1_DIFF 高压
//HPVDD 1.85V,选择DAC_MODE_H1_DIFF,关掉EQ、DRC、ANC测试,空载1K峰峰值2.7V左右
/*
 *系统音量类型选择
 *软件数字音量是指纯软件对声音进行运算后得到的
 *硬件数字音量是指dac内部数字模块对声音进行运算后输出
 *选择软件数字音量或者硬件数字音量会固定模拟音量,
 *固定的模拟音量值由 MAX_ANA_VOL 决定
 */
#define VOL_TYPE_DIGITAL        0    //软件数字音量
#define VOL_TYPE_AD                2    //联合音量(模拟数字混合调节)
#define VOL_TYPE_DIGITAL_HW        3      //硬件数字音量
/*注意:ANC使能情况下使用软件数字音量*/
#if (TCFG_AUDIO_ANC_ENABLE || TCFG_AD2DA_LOW_LATENCY_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
#define SYS_VOL_TYPE            VOL_TYPE_DIGITAL
#else
#define SYS_VOL_TYPE            VOL_TYPE_DIGITAL_HW
#endif/*TCFG_AUDIO_ANC_ENABLE*/

#define MAX_ANA_VOL             (3)    //系统最大模拟音量 (0-3)

#if TCFG_AUDIO_HEARING_AID_ENABLE
#define DIG_VOL_MAX_VALUE       (0.0f)  // 数字音量最大值(单位:dB),最大0
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_L_DIFF)
#define DIG_VOL_MAX_VALUE       (-5.0f)  // 数字音量最大值(单位:dB),最大0
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF)
#define DIG_VOL_MAX_VALUE       (-8.0f)  // 数字音量最大值(单位:dB),最大0
#else
#define DIG_VOL_MAX_VALUE       (0.0f)  // 数字音量最大值(单位:dB),最大0
#endif

#if (TCFG_AUDIO_ANC_ENABLE)
#define  ANC_MODE_DIG_VOL_LIMIT   (-6.0f) // 限制数字音量,最大0
#endif/*TCFG_AUDIO_ANC_ENABLE*/

/*数字音量最大值定义 最大16384*/
#define DEFAULT_DIGITAL_VOLUME   16384
  1. 使用软件数字音量时:
    1. SW_DIG_VOL_TAB_USER_DEFINED打开时,由SDK流程生成数字音量表,大小受上面的DIG_VOL_MAX_VALUE参数限制,每个等级差异由DIG_VOL_STEP决定。
    2. SW_DIG_VOL_TAB_USER_DEFINED关闭时,数字音量表使用default_dig_vol_table。
  2. 使用硬件数字音量时:
    1. 默认由SDK流程生成数字音量表,大小受上面的DIG_VOL_MAX_VALUE参数限制,每个等级差异由BT_MUSIC_VOL_STEP(音乐)或者BT_CALL_VOL_STEP(通话)决定。
    2. 可通过修改下图改为使用数字音量表,数字音量表使用hw_dig_vol_table。 image
  3. 其他影响音量的功能模块:EQ、DRC、ANC 测试最大音量时,要关掉EQ、DRC、ANC测试,或者EQ的曲线拉平和总增益置0,ANC的dac增益配置配成15,如图:
    image 开了ANC后输出不够时,可以加大ANC_MODE_DIG_VOL_LIMIT,最大为0。
    公版SDK使用如下配置,最大音量空载1K 0DB输出峰峰值2.7V左右:
    1. HPVDD接1.85V;
    2. TCFG_AUDIO_DAC_MODE选择DAC_MODE_H1_DIFF;
    3. DIG_VOL_MAX_VALUE配置为(0.0f);
    4. 关掉EQ、DRC、ANC。

可视化SDK:

imageimageimageimage自定义数字音量的方法

11. 打印所有adc,dac的增益

AC696n

void audio_adda_gain_dump(void)//打印所有adc,dac的增益
{
    u8 dac_again_fl = JL_ANA->DAA_CON1 & 0x1F;
    u8 dac_again_fr = (JL_ANA->DAA_CON1 >> 5) & 0x1F;

    u32 dac_dgain_fl = JL_AUDIO->DAC_VL0 & 0xFFFF;
    u32 dac_dgain_fr = (JL_AUDIO->DAC_VL0 >> 16) & 0xFFFF;

    u8 mic0_gain = (JL_ANA->ADA_CON1) & 0x1F;
    u8 mic0_db = (JL_ANA->ADA_CON1 >> 16) & 0x1; //0db还是6db

    u8 linein_l_gain = (JL_ANA->ADA_CON1 >> 5) & 0xF;
    printf("MIC_G:%d,MIC_0_6:%d, linein_gain:%d,DAC_AG:%d,%d,DAC_DG:%d,%d\n", mic0_gain, mic0_db, linein_l_gain, dac_again_fl, dac_again_fr, dac_dgain_fl, dac_dgain_fr);

}

ac695 n

void audio_adda_gain_dump(void)//打印所有adc,dac的增益
{
    u8 dac_again_fl = JL_ANA->DAA_CON1 & 0x1F;
    u8 dac_again_fr = (JL_ANA->DAA_CON1 >> 5) & 0x1F;
    u8 dac_again_rl = (JL_ANA->DAA_CON1 >> 10) & 0x1F;
    u8 dac_again_rr = (JL_ANA->DAA_CON1 >> 15) & 0x1F;


    u32 dac_dgain_fl = JL_AUDIO->DAC_VL0 & 0xFFFF;
    u32 dac_dgain_fr = (JL_AUDIO->DAC_VL0 >> 16) & 0xFFFF;
    u32 dac_dgain_rl = JL_AUDIO->DAC_VL1 & 0xFFFF;
    u32 dac_dgain_rr = (JL_AUDIO->DAC_VL1 >> 16) & 0xFFFF;


    u8 mic0_gain = (JL_ANA->ADA_CON0 >> 8) & 0x1F;
    u8 mic0_db = (JL_ANA->ADA_CON4 >> 29) & 0x1; //0db还是6db

    u8 linein_r_gain = (JL_ANA->ADA_CON0 >> 4) & 0xF;
    u8 linein_l_gain = JL_ANA->ADA_CON0 & 0xF;
    printf("MIC_G:%d,MIC_0_6:%d, linein_gain:%d,%d,DAC_AG:%d,%d,%d,%d,DAC_DG:%d,%d,%d,%d\n", mic0_gain, mic0_db, linein_l_gain, linein_r_gain, dac_again_fl, dac_again_fr, dac_again_rl, dac_again_rr, dac_dgain_fl, dac_dgain_fr, dac_dgain_rl, dac_dgain_rr);

}

八、MIC

  1. 打开MIC数据采样 示范程序
    AC696N_soundbox_sdk_release_1.5.0
struct adc_mic_ch user_mic;
struct audio_adc_output_hdl user_mic_output;
/*----------------------------------------------------------------------------*/
/**@brief  MIC数据的回调
   @param
   @return
   @note : 默认统计最大/最小值/最大最小的差
*/
/*----------------------------------------------------------------------------*/
static void my_adc_output_to_enc(void *priv, s16 *data, int len)
{
    //参数定义
    #define CALC_DATA_SUM 16000   //多长时间更新一次数据 
    
    u16 points = len / 2;
    u16 index;
    static s32 min = 0xfffff;
    static s32 max = -100000;
    static s32 cnt_sum = 0;
    s32 db = 0;

    for (index = 0; index < points; index ++) {
        db = data[index];
        cnt_sum++;
        if (cnt_sum > CALC_DATA_SUM) {
            printf("MAX : %d\tMIN : %d  \t: %d\n",max,min,max-min);
            cnt_sum = 0;
            min = 0xfffff;
            max = -100000;
        }
        if (min > db)
            min = db;
        if (max < db)
            max = db;
    }
}

/*----------------------------------------------------------------------------*/
/**@brief  打开MIC
   @param
   @return
   @note : audio_mic_open 另外两个传参为 采样率 和 MIC增益
*/
/*----------------------------------------------------------------------------*/
void user_mic_open(void)
{
    user_mic_output.handler = my_adc_output_to_enc;
    user_mic_output.priv    = NULL;
    if (audio_mic_open(&user_mic, 16000,0) == 0) {
        audio_mic_add_output(&user_mic_output);
        audio_mic_start(&user_mic);
    }
}

/*----------------------------------------------------------------------------*/
/**@brief  关闭MIC
   @param
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void user_mic_close(void)
{
    audio_mic_close(&user_mic, &user_mic_output);
}

  1. 打开mic,获取mic数据,分析mic频谱
//使用头文件
#include "spectrum/Spectrum_fft.h"
//数据定义
#define mic_spectrum_fft        1
int get_spectrum;
spectrum_fft_hdl *fft_hdl = NULL;


//开mic,获取mic数据:
extern void mic_spectrum_get_demo(void *p);
int audio_adc_mic_open_demo(u16 sr)                           
{    printf("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKL\n");
    u8 ladc_mic_gain = 5;
    ASSERT(ladc_mic == NULL);
    ladc_mic = zalloc(sizeof(struct ladc_mic_demo));
    if (ladc_mic) {
        audio_adc_mic_open(&ladc_mic->mic_ch, AUDIO_ADC_MIC_CH, &adc_hdl);
        audio_adc_mic_set_sample_rate(&ladc_mic->mic_ch, sr);
        audio_adc_mic_set_gain(&ladc_mic->mic_ch, ladc_mic_gain);
        audio_adc_mic_set_buffs(&ladc_mic->mic_ch, ladc_mic->adc_buf, LADC_MIC_IRQ_POINTS * 2, LADC_MIC_BUF_NUM);
        audio_adc_mic_start(&ladc_mic->mic_ch);
        ladc_mic->adc_output.handler = adc_mic_open_demo_output;    //回调函数
        ladc_mic->adc_output.priv = &adc_hdl;
        audio_adc_add_output_handler(&adc_hdl, &ladc_mic->adc_output);
 #if mic_spectrum_fft                                              //频谱部分
        spectrum_fft_open_parm parm = {0};
        parm.sr = sr;
        parm.channel = 1;
        parm.attackFactor = 0.9;
        parm.releaseFactor = 0.9;
        parm.mode = 2;
        fft_hdl = audio_spectrum_fft_open(&parm);
        get_spectrum = sys_timer_add(fft_hdl, mic_spectrum_get_demo, 500);//频谱值获取测试 */
        printf("spectrum_open_demo\n");
        clock_add(SPECTRUM_CLK);
#endif
        return 0;
    } else {
        return -1;
    }
}
////MIC回调函数:
extern int audio_spectrum_fft_run(spectrum_fft_hdl *hdl, s16 *data, int len);
static void adc_mic_open_demo_output(void *priv, s16 *data, int len)
{
    struct audio_adc_hdl *hdl = priv;
    //putchar('o');
    if (ladc_mic == NULL) {
        return;
    }
#if mic_spectrum_fft                                  //频谱部分
    audio_spectrum_fft_run(fft_hdl,data,len);
#endif
   // printf("ppppp:%d,%d\n",data[2],len);                //可在此处拿到MIC采集的数据,对所有数据做绝对值累加则可以作为声音能量参考依据
}
///关MIC函数
void audio_adc_mic_close_demo(void)
{
    if (ladc_mic){
#if mic_spectrum_fft                                   //频谱部分
        audio_spectrum_fft_close(fft_hdl);
        clock_remove(SPECTRUM_CLK);
        sys_timer_del(get_spectrum);
#endif
        audio_adc_mic_close(&ladc_mic->mic_ch);
        audio_adc_del_output_handler(&adc_hdl, &ladc_mic->adc_output);
        free(ladc_mic);
        ladc_mic = NULL;
    }
}
//频谱数据处理函数涉及的头文件及参数:
#include "spectrum/spectrum_fft.h"
#include "audio_splicing.h"
#define spectrum_fft_points_per_ch  (512)
//频谱部分:
//上文获取频谱输出函数:
void mic_spectrum_get_demo(void *p)
{
    spectrum_fft_hdl *hdl = p;
    printf("spectrum_open_demo : %d\n",hdl);
    if (hdl) {
        u8 db_num = audio_spectrum_fft_get_num(hdl);//获取频谱个数
        short *db_data = audio_spectrum_fft_get_val(hdl);//获取存储频谱值得地址
        if (!db_data) {
            return;
        }
        for (int i = 0; i < db_num; i++) {
            //输出db_num个 db值
            printf("db_data db[%d] %d\n", i, db_data[i]);
        }
    }
}
//频谱数据处理函数:
/*----------------------------------------------------------------------------*/
/**@brief    audio_spectrum_fft_run 同步处理,每次run都会把输入buf消耗完,才会往下走
   @param    _hdl:句柄
   @param    data:输入数据
   @param    len:输入数据长度
   @return  len
   @note    频谱计算处理,只获取输入的数据,不改变输入的数据
*/
/*----------------------------------------------------------------------------*/
int audio_spectrum_fft_run(spectrum_fft_hdl *hdl, s16 *data, int len)
{
    if (!hdl) {
        return len;
    }
    if (!len) {
        return len;
    }

    if (!hdl->run_en) {
        hdl->offset = 0;
        return len;
    }

    u8 channel = (hdl->parm.channel & 0x3);
    s16 *indata_tmp = data;
    u32 in_remain = len;
    u32 tlen;
__here:
    indata_tmp = (s16 *)((int)data + (len - in_remain));
    if (hdl->offset < hdl->out_buf_size) {
        tlen = hdl->out_buf_size - hdl->offset;
        if (channel == 2 && (hdl->parm.channel & BIT(4))) {
            if (tlen > in_remain / 2) {
                tlen = in_remain / 2;
            }
            pcm_qual_to_dual((void *)((int)hdl->out_buf + hdl->offset), indata_tmp, tlen * 2);
            hdl->offset += tlen;
            in_remain -= tlen * 2;
        } else {
            if (tlen > in_remain) {
                tlen = in_remain;
            }
            memcpy((void *)((int)hdl->out_buf + hdl->offset), indata_tmp, tlen);
            hdl->offset += tlen;
            in_remain -= tlen;
        }
        if (in_remain && (hdl->offset != hdl->out_buf_size)) {
            goto __here;
        }
    }
    if (hdl->offset == hdl->out_buf_size) {
        hdl->offset = 0;
        SpectrumShowRun(hdl->work_buf, hdl->out_buf, spectrum_fft_points_per_ch);
        if (in_remain) {
            goto __here;
        }
    }
    return len;
}

参考按键使用例程:
extern int audio_adc_mic_open_demo(u16 sr);
extern void audio_adc_mic_close_demo(void);
case KEY_OPEN_ADC:
static int i = 0;
if(i == 0){
    printf("audio_adc_open_demo");
    audio_adc_mic_open_demo(44100);
    i = 1;
}
else{
    printf("audio_adc_close_demo");
    audio_adc_mic_close_demo();
    i = 0;
}
break;  

上文主要实现功能:当audio_adc_mic_open_demo函数执行后,将开启MIC,并采集MIC数据在adc_mic_open_demo_output回调函数处可以对收集到的数据做处理。同时如果将mic_spectrum_fft宏定义为1时,可以同时得到频谱的输出。
频谱数据解答:
此图是在上述程序执行后,mic输入2984hz的音频后,频谱输出结果:
image 2984hz对应采样率为44100的频谱显示中心频率点第16点,此时在频谱输出图中对应的db[16]为最大值。简单来说:就是输入频率的声音越大,频谱对应的数据就越大。
备注:频率中心附近几个频点的数据也比较大,属于正常现象。
完整采样率对应频谱显示中心频率点如下图:
【金山文档】 频谱显示中心频率点
频谱显示中心频率点.xlsx
image

695_3.0.1_sdk_add_mic_spectrum_demo

链接:https://pan.baidu.com/s/13tHCwnd055UTSQn2a1ZFWg
提取码:8888

  1. ac696n_earphone_v0.3.0获取mic采样数据 (696其他耳机SDK可尝试共用)
    1. 只需要获取mic的采样数据 添加如下代码,调用audio_adc_demo()启动采样,调用audio_adc_demo_stop()结束采样
struct adc_stream_ops {
    void (*buf_reset)(void *priv);
    void *(*alloc_space)(void *priv, u32 *len);
    void (*output)(void *priv, void *buf, u32 len);
};
struct audio_adc_attr {
    u8 gain;
    u16 sample_rate;
    u16 irq_time;
    u16 irq_points;
};

int audio_adc_sample_start(void *adc);
int audio_adc_sample_stop(void *adc);
int audio_adc_get_attr(void *adc, struct audio_adc_attr *attr);
int audio_adc_set_attr(void *adc, struct audio_adc_attr *attr);
int audio_adc_close(void *adc);

void audio_adc_set_irq_handler(void *adc, void *priv, void (*handler)(void *, void *, u32));
void audio_adc_set_buf_ops(void *adc, void *priv, struct adc_stream_ops *ops);

int audio_adc_set_buffer(void *adc, void *buf, int len);
int audio_adc_set_sample_rate(void *adc, u32 sample_rate);
void audio_adc_set_mic_gain(void *adc, u8 gain);
static void *adc_buf;
static int adc_bufsize = 2048;
static void *adc;
#define DEFAULT_REC_POINTS   64
#define ADC_SR    16000
extern struct adc_platform_data adc_data;

static void *test_adc_stream_alloc(void *priv, u32 * len) {
    *len = DEFAULT_REC_POINTS;
    return (void *)adc_buf;
}

//mic数据输出
static void test_adc_stream_finish(void *priv, void *data, u32 len) {

    put_buf((u8*)data,8);
}

const struct adc_stream_ops output_ops = {
    .alloc_space = test_adc_stream_alloc,
    .output      = test_adc_stream_finish,
};
void audio_adc_demo()
{
    if(adc){
        return;
    }
    adc_buf = zalloc(adc_bufsize);
    adc = audio_adc_open(&adc_data, "mic");

    audio_adc_set_buf_ops(adc, adc, &output_ops);
    audio_adc_set_buffer(adc, adc_buf, adc_bufsize);
    struct audio_adc_attr adc_attr;
    audio_adc_get_attr(adc, &adc_attr);
    adc_attr.gain = 14;
    adc_attr.sample_rate = ADC_SR;
    adc_attr.irq_points = DEFAULT_REC_POINTS;
    audio_adc_set_attr(adc, &adc_attr);

    audio_adc_sample_start(adc);

    //audio_adc_sample_stop(adc_mc);
    //audio_adc_close(adc_mc);
}

void audio_adc_demo_stop()
{
    if(adc){
        audio_adc_sample_stop(adc);
        audio_adc_close(adc);
        free(adc_buf);
        adc_buf = NULL;
        adc = NULL;
    }
}
2. mic输出到dac功能

定义宏AUDIO_MIC_TEST
#define AUDIO_MIC_TEST
调用mic_rec_play_start()启动,启动后不要再播提示音和蓝牙音乐。
调用mic_rec_play_stop()停止。
同时修改如下截图内容,也可以在截图位置获取mic的采样数据
image

  1. USB通话、智能语音使用数字MIC
    1. usb通话 USB通话修改audio_usb_mic.c文件
      添加库和宏
      image
#include "pdm_link.h"
static audio_plnk_t *audio_plnk_mic = NULL;
#define ESCO_PLNK_SCLK   2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
#define ESCO_PLNK_CH_NUM          1  /*支持的最大通道(max = 2)*/
#define ESCO_PLNK_IRQ_POINTS    256 /*采样中断点数*/

添加输出函数
image

void plink_data_to_usb(s16 *data, int len)
{
    adc_output_to_cbuf(NULL, data, len << 1);
}

添加数字mic流程
image

#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
    printf("pink_2_adc open\n");
    audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
    //audio_mic_pwr_ctl(MIC_PWR_ON);
    if (audio_plnk_mic) {
        audio_plnk_mic->ch_num = ESCO_PLNK_CH_NUM;//PLNK_MIC_CH;
        /*SCLK:1M-4M,SCLK/SR需为整数且在1-4096范围*/
        audio_plnk_mic->sr = sample_rate;
        audio_plnk_mic->sclk_fre = ESCO_PLNK_SCLK;
        if (audio_plnk_mic->sclk_fre % audio_plnk_mic->sr) {
            r_printf("[warn]SCLK/SR需为整数且在1-4096范围\n");
        }
#if (PLNK_CH_EN == PLNK_CH0_EN)
        audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
#elif (PLNK_CH_EN == PLNK_CH1_EN)
        audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
        audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#else
        audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
        audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#endif
        audio_plnk_mic->output = plink_data_to_usb;//*adc_output_to_cbuf;
        audio_plnk_mic->buf_len = ESCO_PLNK_IRQ_POINTS;
       audio_plnk_mic->buf=zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
        ASSERT(audio_plnk_mic->buf);
        audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
        audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
        audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
        audio_plnk_open(audio_plnk_mic);
        audio_plnk_start(audio_plnk_mic);
    }
#else

注意补全#endif
image 添加关MIC流程
image

#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
            printf("pink_2_adc close\n");

            audio_plnk_close();
            audio_mic_pwr_ctl(MIC_PWR_OFF);
            if (audio_plnk_mic->buf) {
                free(audio_plnk_mic->buf);
            }
            if (audio_plnk_mic) {
                free(audio_plnk_mic);
                audio_plnk_mic = NULL;
            }
#else
2. 智能语音

智能语音修改voice_mic_data.c文件
添加相应库和宏
image

#include "pdm_link.h"
static audio_plnk_t *audio_plnk_mic = NULL;
#define ESCO_PLNK_SCLK   2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
#define ESCO_PLNK_CH_NUM          1  /*支持的最大通道(max = 2)*/
#define ESCO_PLNK_IRQ_POINTS    256 /*采样中断点数*/

添加输出函数
image

void plink_data_to_kws(s16 *data, int len)
{
    audio_main_adc_dma_data_handler(NULL, data, len << 1);
}

添加数字mic流程
image

#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
    if (1) {
        audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
        audio_mic_pwr_ctl(MIC_PWR_ON);
        if (audio_plnk_mic) {
            audio_plnk_mic->ch_num = ESCO_PLNK_CH_NUM;//PLNK_MIC_CH;
            /*SCLK:1M-4M,SCLK/SR需为整数且在1-4096范围*/
            audio_plnk_mic->sr = 16000;//*sample_rate;
            audio_plnk_mic->sclk_fre = ESCO_PLNK_SCLK;
            if (audio_plnk_mic->sclk_fre % audio_plnk_mic->sr) {
            r_printf("[warn]SCLK/SR需为整数且在1-4096范围\n");
            }
#if (PLNK_CH_EN == PLNK_CH0_EN)
            audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
            audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
#elif (PLNK_CH_EN == PLNK_CH1_EN)
            audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
            audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#else
            audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
            audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#endif
            audio_plnk_mic->output = plink_data_to_kws;
            audio_plnk_mic->buf_len = ESCO_PLNK_IRQ_POINTS;
       audio_plnk_mic->buf = zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
            ASSERT(audio_plnk_mic->buf);
            audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
            audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
            audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
            audio_plnk_open(audio_plnk_mic);
            audio_plnk_start(audio_plnk_mic);
        }
}
#else

添加关MIC流程
image

#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
        audio_plnk_close();
        audio_mic_pwr_ctl(MIC_PWR_OFF);
        if (audio_plnk_mic->buf) {
            free(audio_plnk_mic->buf);
        }
        if (audio_plnk_mic) {
            free(audio_plnk_mic);
            audio_plnk_mic = NULL;
        }

#else
3. 701N数字MIC使用补充

701系列使用数字MIC时需要做如下添加

SFR(JL_ASS->CLK_CON, 0, 2, 3);

image 4. 使用数字mic做USB mic声音不够大 可以使用aec模块做AGC放大,或者自行处理采样数据放大
image 5. 打开MIC偏置接口 AC695N
audio_adc.h

int audio_adc_mic_open(struct adc_mic_ch *mic, int ch, struct audio_adc_hdl *adc);
  1. AD698蓝牙音乐和mic同时输出 【金山文档】 AC698V164 MIC与蓝牙音乐共同输出DAC demo
    AC698V164 MIC与蓝牙音乐共同输出DAC demo.otl
  2. 其他与MIC相关的demo 翻译耳机、语音识别
  3. 700N/701N话务耳机单mic和双mic互相切换的接口 ENC相关应用入口汇总.otl

九、音频流

  1. 人声消除
  • 目前有以下情况目前不支持人声消除(可能会出现无声的情况):
  1. 左右声道数据基本一致的音频文件。
  • 程序宏定义开关
//*********************************************************************************//
//                                人声消除使能
//*********************************************************************************//
#define AUDIO_VOCAL_REMOVE_EN       0

//*********************************************************************************//
//                                相关函数
//*********************************************************************************//
/*----------------------------------------------------------------------------*/
/**@brief    audio_vocal_remove_sw 运行过程开关处理
   @param    _hdl:句柄
   @param    dis: 0:人声消除有效  1:人声消除无效
   @return  0:成功  -1:失败
   @note
*/
/*----------------------------------------------------------------------------*/
int audio_vocal_remove_sw(vocal_remove_hdl *_hdl, u32 dis);
  1. 人声消除额外保留部分频率声音办法(695_3.1.0_sdk) 公版对比此压缩包内文件将修改点到修改到程序上
    【金山文档】 AC695X 人声消除增加了低音保留处理方法
    https://kdocs.cn/l/cu2XQVI8FRnS
    AC696N_SOUNDBOX_SDK_1.7.0 人声消除补丁.zip

原理:
将原始声音分为两份,一份走原先的人声消除,另一份走EQ调节
最后输出声音 = 原先人声消除效果(左-右)+ EQ调节后声音
EQ调节处:
image

  1. 左右声道数据互换

2.1 695sdk参考

  • AC695N_soundbox_sdk_release_3.0.4 添加以下节点及函数

image 2.

#include "stream_entry.h"


u8 pcm_lr_exchange_flag = 1;
int pcm_lr_exchange_sw(u8 sw)
{
    pcm_lr_exchange_flag = sw;
}

int pcm_lr_exchange_deal(void *priv, struct audio_data_frame *in)
{
    s16 *f_lr=in->data;
    s16 tmp_l,tmp_r;
    u16 rlen;
    if(pcm_lr_exchange_flag == 0)
        return in->data_len;

    rlen = in->data_len>>2; ////u8*4
    //printf("%d\n",in->offset);

    if(in->channel == 2){
        if(in->offset==0){
            for(u16 i=0; i<rlen; i++) ///lrlrlr......
            {
                tmp_l = f_lr[i*2];
                tmp_r = f_lr[i*2+1];
                f_lr[i*2] = tmp_r;
                f_lr[i*2+1] = tmp_l;
            } 
        }
    }
    return in->data_len;
}


2.2 608 sdk参考

  • ac608n_soundbox_sdk_v1.2.2 添加以下节点及函数
  1. 在audio_dec.c中的audio_dec_init();函数中如下位置增加左右声道转换节点 image
struct __audio_test_hdl audio_test_hdl;
memset(&audio_test_hdl, 0x00, sizeof(struct __audio_test_hdl));
audio_test_hdl.entry.data_process_len = audio_test_output_data_process_len;
audio_test_hdl.entry.data_handler = audio_test_data_handler;
// 加入数据流
entries[entry_cnt++] = &(audio_test_hdl.entry);

其中用到的相关接口如下:
image

extern struct audio_dac_hdl dac_hdl;

struct __audio_test_hdl {
    struct audio_stream_entry entry;    // 音频流入口
}audio_test_hdl; 

// 处理函数

int audio_test_run(void *hdl, s16 *data, u32 len)
{
    // 在这里可以处理数据,或者拿走数据
    s16 *ddata = data;
    u32 points = len/2;
    for(int i = 0; i < points; i+=2){
        s16 tmp = ddata[i];
        ddata[i] = ddata[i+1];
        ddata[i+1] = tmp;
    }

    return 0;
}

static void audio_test_output_data_process_len(struct audio_stream_entry *entry,  int len)
{
    // 不需要做处理,空着就行
}

static int audio_test_data_handler(struct audio_stream_entry *entry,
                                      struct audio_data_frame *in,
                                      struct audio_data_frame *out)
{
    struct __audio_test_hdl *hdl = container_of(entry, struct __audio_test_hdl, entry);

    out->data = in->data;
    out->data_len = in->data_len;

    if (in->data_len - in->offset > 0) {
        audio_test_run(hdl, in->data + in->offset / 2, in->data_len - in->offset);
    }
    return in->data_len;
}
  1. 数字反相器,用来矫正DAC的输出相位 新的SDK已经有实现该功能,以前的SDK要实现可以参考自行添加,宏定义如下:
#define TCFG_DIG_PHASE_INVERTER_EN    1  //数字反相器,用来矫正DAC的输出相位

实现代码:


#if TCFG_DIG_PHASE_INVERTER_EN
    audio_phase_inver_hdl.entry.data_process_len = audio_phase_inver_output_data_process_len;
    audio_phase_inver_hdl.entry.data_handler = audio_phase_inver_data_handler;
    entries[entry_cnt++] = &(audio_phase_inver_hdl.entry);
#endif/*TCFG_DIG_PHASE_INVERTER_EN*/
  1. DAC能量值计算
  • AC696 耳机SDK(0.3.1SDK) 参考上面 拦截DAC数据做运行及通用能量值计算 去实现该功能。

  • AC696 音箱SDK 2M包应用 蓝牙模式下(参考例子)
    拿到蓝牙解码数据后,对数据进行累加取平均值计算。得出能量值。(修改如下图)
    image int audio_output_data_db_calc_simple(short *data, unsigned short len,unsigned char channels) 函数看 第一点 的第 4 小点 :通用能量值计算(取平均值)

  • AC696 非2M包应用 开 AUDIO_OUTPUT_AUTOMUTE 调用 audio_dac_energy_get()函数;

  1. 自定义音频流(适用于音箱SDK添加第三方算法/数据处理) 下面以AC695N_soundbox_sdk_release_3.0.1 数据除以2作为例子
    主要修改 SDK\cpu\br23\audio_dec\audio_dec.c 文件
  2. 添加数据节点 int audio_dec_init()函数 image 截图中的代码
#if AUDIO_VOCAL_REMOVE_EN
    struct __stream_entry *l_r_entry = NULL;
    l_r_entry = stream_entry_open(&mixer,pcm_lr_exchange_deal,0);
    entries[entry_cnt++] = &(l_r_entry->entry);
    if (mix_vocal_remove_hdl) {
        entries[entry_cnt++] = &mix_vocal_remove_hdl->entry;
    }
    if (vocal_remove_mix_ch_switch) {
        entries[entry_cnt++] = &vocal_remove_mix_ch_switch->entry;
    }
#endif
  1. 数据处理 image 截图中的代码

#include "stream_entry.h"


u8 pcm_lr_exchange_flag = 1;
int pcm_lr_exchange_sw(u8 sw)
{
    pcm_lr_exchange_flag = sw;
}
//任意长度
int pcm_lr_exchange_deal(void *priv, struct audio_data_frame *in)
{
    s16 *f_lr=in->data;
    s16 tmp_l,tmp_r;
    u16 rlen;
    if(pcm_lr_exchange_flag == 0)
        return in->data_len;

    rlen = in->data_len>>2; ////u8*4
    //printf("%d\n",in->offset);

    if(in->channel == 2){
        if(in->offset==0){
            for(u16 i=0; i<rlen; i++) ///lrlrlr......
            {
                // tmp_l = f_lr[i*2];
                // tmp_r = f_lr[i*2+1];
                f_lr[i*2] = f_lr[i*2]/2;
                f_lr[i*2+1] = f_lr[i*2+1]/2;
            } 
        }
    }
    return in->data_len;
}
  • 如果客户数据处理需要定长,可参考以下做法添加以下流程处理 flowchart
    • 初始化CBUFF:用于数据缓存
#define USER_DATA_LEN 128
static cbuffer_t user_dac_cbuf_in;
static cbuffer_t user_dac_cbuf_out;
static u8 user_dac_buffer_in[1024];
static u8 user_dac_buffer_out[1024];

cbuf_init(&user_dac_cbuf_in,user_dac_buffer_in, sizeof(user_dac_buffer_in));
cbuf_init(&user_dac_cbuf_out,user_dac_buffer_out, sizeof(user_dac_buffer_out));
- 音频数据添加缓存处理(数据处理在:数据处理部分定长为:USER_DATA_LEN)
int pcm_lr_exchange_deal(void *priv, struct audio_data_frame *in)
{
    u8 user_buffer[USER_DATA_LEN*2];
    u16 rlen;

    if(pcm_lr_exchange_flag == 0)
        return in->data_len;
 
    if(in->offset==0){
        //写入读缓存
        cbuf_write(&user_dac_cbuf_in,in->data,in->data_len);
        
        //处理缓存数据
        while (cbuf_get_data_size(&user_dac_cbuf_in) >= USER_DATA_LEN) {
            cbuf_read(&user_dac_cbuf_in,user_buffer,USER_DATA_LEN);

            s16 *f_lr=user_buffer;
            rlen = USER_DATA_LEN>>2; 

            //数据处理部分
            for(u16 i=0; i<rlen; i++) ///lrlrlr......
            {
                // tmp_l = f_lr[i*2];
                // tmp_r = f_lr[i*2+1];
                f_lr[i*2] = f_lr[i*2]/2;
                f_lr[i*2+1] = f_lr[i*2+1]/2;
            }

            cbuf_write(&user_dac_cbuf_out,user_buffer,USER_DATA_LEN);

        }
        //printf("len %d - %d - %d\n",in->data_len,cbuf_get_data_size(&user_dac_cbuf_in),cbuf_get_data_size(&user_dac_cbuf_out));
        
        if(cbuf_get_data_size(&user_dac_cbuf_out)>=in->data_len){
            // putchar('*');
            cbuf_read(&user_dac_cbuf_out,in->data,in->data_len);
        }else{
            memset(in->data,0,in->data_len);
        }
    }

    return in->data_len;
}

每次音频解码开始清楚之前的buff
image

参考应用:清零数据流方式(音乐模式,其他模式参照修改)

imageimageimageimage

int zero_entry_handle(void *priv, struct audio_data_frame *in)
{
    memset(in->data,0x00,in->data_len);
    return in->data_len;
}
struct __stream_entry *zero_entry = NULL;
/****************************************************/

    zero_entry = stream_entry_open(&mixer,zero_entry_handle,0);
    entries[entry_cnt++] = &(zero_entry->entry);
/****************************************************/
    if(zero_entry){
        stream_entry_close(&zero_entry);
        zero_entry = NULL;
    }

淡出淡入方式:

//淡入:
dvol_handle fade_in_dvol = {
    .toggle = 1,
    .fade = 1,
    .vol = 0,
    .vol_max = 16384,
    .vol_fade = 0,
    .fade_step = 5,
    .vol_target = 16384,
};
//数据流加入此数据处理后,声音会从0淡入到16384(0db增益)结束
//一般是16bit数据流处理,位宽注意对齐
audio_digital_vol_run(&fade_in_dvol,in->data,in->data_len);
fade_in_dvol.vol_fade = 0; //淡入前设置,当这个值是16384的时候淡入结束

//淡出
dvol_handle fade_out_dvol = {
    .toggle = 1,
    .fade = 1,
    .vol = 16384,
    .vol_max = 16384,
    .vol_fade = 16384,
    .fade_step = 6,
    .vol_target = 0,
};
//数据流加入此数据处理后,声音会从16384(0db)淡入到0(静音)结束
//一般是16bit数据流处理,位宽注意对齐
audio_digital_vol_run(&fade_out_dvol,in->data,in->data_len);
fade_in_dvol.vol_fade = 16384; //淡出前设置,当这个值是0的时候淡入结束
//淡出需要特别注最后的音量是0,如果下次数据流开启时还继续执行的话,就会没有声音!!!!!!

  1. 700NSDK\697NSDK添加A2DP第三方音频算法 700N\697N耳机的SDK需要放在a2dp_dec_output_handler内的remain部分进行缓存,如图:
    image 注意:我们自带的EQ和DRC等音效算法要关闭,若遇到打印'F'等字眼,很可能是跑不过来。此时需要屏蔽掉第三方算法,先验证不跑第三方需要多大时钟,再将时钟提高到128M验证能否跑得过来。如果提高到128M还跑不动算法,则该算法需要的算力为:128M-无算法的时钟大小。可以处理算法前后拉IO口抓波形看一次处理需要多长时间,若要求算力太高,则优先优化算法运行速度。
  2. AC695X 多路WAV叠加播放 【金山文档】 AC695X多路wav叠加参考资料
    AC695X多路wav叠加参考资料.zip
  3. 可视化耳机SDK,音频数据淡入淡出 音频PCM数据淡入淡出(可视化).otl

十、混响

1、在线调试方法

【金山文档】 新Tools的使用

2、混响高低音调节

对应修改修改方法:【金山文档】 混响高低音接口_AC695N_soundbox_sdk_release_3.1.0 ->仓库链接

3、相关补丁

  • AC695N_soundbox_sdk_release_3.1.0 混响接口 mic_effect_set_echo_delay等用不了 解决方法:对比替换下面的文件
    【金山文档】 AC695N_soundbox_sdk_release_3.1.0(修复混响接口用不了问题)

3、混响数据流叠加linein解码

AC695N_soundbox_sdk_release_3.1.0_混响叠加linein通道.zip

十一、EQ

  1. 在线调试方法 串口:【金山文档】 新Tools的使用
    蓝牙:
    701N 普通SDK:
    imageimageimage 可视化SDK:
    image

  2. 离线调试方法 与在线调试方法不一样的地方是,需要注意SDK的EQ版本,工具上要对应选择。
    imageimage

  3. 实现等响功能 原理:在每一路解码通道添加一个EQ处理的节点去实现等响音量调节功能
    实现:
    具体添加可以参考DEMO里面宏定义实现内容

///*********************************************************************************//
//          等响功能
//1. 通过EQ去实现该功能
//*********************************************************************************//
#define AUDIO_EQUAL_LOUDNESS_EQ_EN

AC695N_soundbox_sdk_release_3.1.0

【金山文档】 EQ_等响度_AC695N_soundbox_sdk_release_3.1.0

AC700N_earphone_release_V1.3.5

AC700N_earphone_release_V1.3.5_bt_多带wdrc
demo实现的曲线类似这种,音源音量变化较大的情况下,低频增益变化不大(实际曲线和效果取决于参数、喇叭、结构)
image demo代码默认开启了此功能,默认使能了EQ在线调试,可以借用辅听EQ来调试
image 在线调试时使用辅听EQ调试,没有辅听功能时,调试好可以直接使用辅听EQ的DRC参数,只需要将READ_HEARING_AID_PARAM置1,不用修改其他代码。
image 如果有辅听功能,用辅听EQ调完参数后要把参数填到mix_out_wdrc_get_filter_info函数中,并将READ_HEARING_AID_PARAM置0。
其中mix_out_wdrc_p._p.wdrc[x].threshold_num取决于下图位置,有4个就是4,参数填到mix_out_wdrc_p._p.wdrc[x].threshold[x]中
image

int mix_out_wdrc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
    //多带
    mix_out_wdrc_p.nband = 2; //max<=3,1:全带 2:两段 3:三段
    //WDRC
    mix_out_wdrc_p.type = 3;  //0:没有使能限幅和压缩器,1:限幅器   2:压缩器  3:wdrc(wdrc不支持3带)
    mix_out_wdrc_p.low_freq = 200; //中低频分频点
    mix_out_wdrc_p.order = 2; //分频器阶数, 2或者4

    //低频参数
    mix_out_wdrc_p._p.wdrc[0].attacktime = 100;
    mix_out_wdrc_p._p.wdrc[0].releasetime = 200;
    mix_out_wdrc_p._p.wdrc[0].inputgain = 0;
    mix_out_wdrc_p._p.wdrc[0].outputgain = 0;
    mix_out_wdrc_p._p.wdrc[0].threshold_num = 4; //点数,也就是限幅器、压缩器的总数
    mix_out_wdrc_p._p.wdrc[0].rms_time = 25; //RMS时间
    mix_out_wdrc_p._p.wdrc[0].algorithm = 0; //detect mode
    mix_out_wdrc_p._p.wdrc[0].mode = 0;

    //第1个点[0, 0]
    mix_out_wdrc_p._p.wdrc[0].threshold[0].in_threshold = 0;
    mix_out_wdrc_p._p.wdrc[0].threshold[0].out_threshold = 0;
    //第2个点[40, 50]
    mix_out_wdrc_p._p.wdrc[0].threshold[1].in_threshold = 40;
    mix_out_wdrc_p._p.wdrc[0].threshold[1].out_threshold = 40 + 10;
    //第3个点[65, 85]
    mix_out_wdrc_p._p.wdrc[0].threshold[2].in_threshold = 65;
    mix_out_wdrc_p._p.wdrc[0].threshold[2].out_threshold = 65 + 20;
    //第4个点[90, 90]
    mix_out_wdrc_p._p.wdrc[0].threshold[3].in_threshold = 90;
    mix_out_wdrc_p._p.wdrc[0].threshold[3].out_threshold = 90 + 0;

    //高频参数
    mix_out_wdrc_p._p.wdrc[1].attacktime = 100;
    mix_out_wdrc_p._p.wdrc[1].releasetime = 200;
    mix_out_wdrc_p._p.wdrc[1].inputgain = 0;
    mix_out_wdrc_p._p.wdrc[1].outputgain = 0;
    mix_out_wdrc_p._p.wdrc[1].threshold_num = 2;
    mix_out_wdrc_p._p.wdrc[1].rms_time = 25;
    mix_out_wdrc_p._p.wdrc[1].algorithm = 0;
    mix_out_wdrc_p._p.wdrc[1].mode = 0;

    //第1个点[0, 0]
    mix_out_wdrc_p._p.wdrc[1].threshold[0].in_threshold = 0;
    mix_out_wdrc_p._p.wdrc[1].threshold[0].out_threshold = 0;
    //第2个点[90, 90]
    mix_out_wdrc_p._p.wdrc[1].threshold[1].in_threshold = 90;
    mix_out_wdrc_p._p.wdrc[1].threshold[1].out_threshold = 90;

    info->R_pch = info->pch = &mix_out_wdrc_p;
    return 0;
}
  1. EQ切换

AC695X&AC701N

AC701N:

测试代码
#define your_EQ_FILE_NAME           SDFILE_RES_ROOT_PATH"eq_cfg_h2.bin"
#define your_EQ_FILE_NAME1          SDFILE_RES_ROOT_PATH"eq_cfg_h1.bin"
void user_eq_change(void)
{
    s32 ret = 0;
    static u8 flag = 0;
    if(flag){
        flag = 0;
        eff_file_switch(your_EQ_FILE_NAME);
    }
    else{
        flag = 1;
        eff_file_switch(your_EQ_FILE_NAME1);
    }
}

701音箱SDK需要注意音效文件命名长度要一致,或者自行修改此处逻辑:
image

3.1.0_SDK_EQ文件切换

effect_adj.c文件改动
//更改
//#define EFF_CFG_FILE_NAME             SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
u8 EFF_CFG_FILE_NAME[48] =    SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin";

//添加
/*
 *设置eq更新标志,eq运行时会重新调用系数回调,获取系数
 * */
static void cur_eq_update(u32 eq_name)
{
    struct audio_eq *eq = get_cur_eq_hdl_by_name(eq_name);
    local_irq_disable();
    if (eq) {
        eq->mask[0] = (u32)-1;
        eq->mask[1] = (u32)-1;
        eq->updata = 1;
    }
    local_irq_enable();
}
/*
 *设置drc更新标志,drc运行时会重新调用系数回调,获取系数
 * */
static void cur_drc_update(u32 drc_name)
{
    struct audio_drc *drc = get_cur_drc_hdl_by_name(drc_name);
    local_irq_disable();
    if (drc) {
        drc->updata = 1;
    }
    local_irq_enable();

}
/*
 *效果文件切换
 *path:效果文件路径
 * */
void eff_file_switch(u8 *path)
{
    //更新效果文件路径
    memcpy(EFF_CFG_FILE_NAME, path, strlen(path));
    //重新解析效果文件
    phone_eff_analyze_data();
    music_eff_analyze_data();
#if (TCFG_EQ_ENABLE != 0)
    cp_eq_file_seg_to_custom_tab();
#endif
#if defined(LINEIN_MODE_SOLE_EQ_EN) && LINEIN_MODE_SOLE_EQ_EN
    linein_eff_analyze_data();
#endif

#if defined(TCFG_MIC_EFFECT_ENABLE) && TCFG_MIC_EFFECT_ENABLE
    for (int i = 0 ; i < EFFECT_REVERB_PARM_MAX; i++) {
        mic_eff_analyze_data(i);
    }
#endif

    //设置需要更新的模块
    audio_vbass_update_demo(AEID_MUSIC_VBASS, &vbass_parm.parm, vbass_parm.is_bypass);
    int i = 0;
    for(i=0;i<4;i++){
        cur_drc_set_update(AEID_MUSIC_DRC, i, &music_mode.drc_parm.wdrc_parm[i]);
        cur_drc_set_bypass(AEID_MUSIC_DRC, i,&music_mode.drc_parm.wdrc_parm[i].is_bypass);
    }
    eq_mode_set(EQ_MODE_CUSTOM);
    mic_effect_change_mode(0);//这里的0是使用0号的话筒音效,默认还有1、2、3、4号
}

eq_config.c文件改动
//更改
#define EQ_FILE_CP_TO_CUSTOM  1

void cp_eq_file_seg_to_custom_tab()
{
    printf("[%s]------------Row[%d]",__FUNCTION__,__LINE__);
#if EQ_FILE_CP_TO_CUSTOM
    u8 nsection = music_mode.eq_parm.seg_num;
    struct eq_seg_info *seg = eq_tab_custom;
    if (nsection > ARRAY_SIZE(eq_tab_custom)) {
        log_e("music nsection:%d > custom nsection:%d\n", nsection, ARRAY_SIZE(eq_tab_custom));
        return ;
    }
    printf("music_mode.eq_parm.global_gain == %d\n",(int)((int)(music_mode.eq_parm.global_gain*100)/100));
    globa_gain_tab[EQ_MODE_CUSTOM] = music_mode.eq_parm.global_gain;
    memcpy(seg, music_mode.eq_parm.seg, sizeof(struct eq_seg_info)*nsection);
    eq_mode=EQ_MODE_CUSTOM;
#endif
}

测试代码
#define your_EQ_FILE_NAME           SDFILE_RES_ROOT_PATH"eq_cfg_h2.bin"
#define your_EQ_FILE_NAME1          SDFILE_RES_ROOT_PATH"eq_cfg_h1.bin"
void user_eq_change(void)
{
    s32 ret = 0;
    static u8 flag = 0;
    if(flag){
        flag = 0;
        eff_file_switch(your_EQ_FILE_NAME);
    }
    else{
        flag = 1;
        eff_file_switch(your_EQ_FILE_NAME1);
    }
}
注意点

1、必须必须必须使用新版EQ工具生成的EQ文件
2、文件放在SDK\cpu\br23\tools\download\standard
3、在SDK\cpu\br23\tools\download\standard\download.bat文件此处后面添加文件,比如:-res tone.cfg eq_cfg_h1.bin eq_cfg_h2.bin

demo程序下载:

696N_170
695_3.1.0_change_eq_demo
链接:https://pan.baidu.com/s/1REnAwIE8yVIqB_U0uA0rQg
提取码:8888

V3.0.6及以下旧版本&以及696 V160SDK版本 多外部EQ文件切换修改方法

#define TCFG_USE_EQ_FILE                    1    //离线eq使用配置文件还是默认系数表 1:使用文件  0 使用默认系数表

注意:过老的版本可以无法使用该方法。

cpu\br25\audio_effect\eq_config.c 修改:
EQ_CFG *user_eq_cfg;
/////////////////////////////////////////////
extern s32 eq_file_get_cfg(EQ_CFG * eq_cfg,u8 * path);
#define EQ_FILE_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
#define EQ_FILE1_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin"

#define EQ_FILE2_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwja.bin"
#define EQ_FILE3_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwco.bin"
#define EQ_FILE4_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwcl.bin"
#define EQ_FILE5_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwpo.bin"
#define EQ_FILE6_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwro.bin"
#define EQ_FILE7_NAME  SDFILE_RES_ROOT_PATH"eq_cfg_hwno.bin"



void set_user_eq_change(u8 flag)
{
    s32 ret =0;
    
    if(user_eq_cfg){
        if(flag==0){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE_NAME);
        }
        else if(flag==1){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE1_NAME);
        }
        else if(flag==2){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE2_NAME);
        }
        else if(flag==3){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE3_NAME);
        }
        else if(flag==4){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE4_NAME);
        }
        else if(flag==5){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE5_NAME);
        }
        else if(flag==6){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE6_NAME);
        }
        else if(flag==7){
            ret = eq_file_get_cfg(user_eq_cfg,EQ_FILE7_NAME);
        }
    }
}
//////////////////////////////////////////////
int eq_init(void)
{
    audio_eq_init();
    eq_adjust_parm parm = {0};
#if TCFG_EQ_ONLINE_ENABLE
    parm.online_en = 1;
#endif
    if (config_filter_coeff_fade_en) {
        parm.fade_en = 1;
    }

#if TCFG_USE_EQ_FILE
    parm.file_en = 1;
#endif

#if EQ_FILE_CP_TO_CUSTOM
    parm.file_en = 1;
    parm.type_gain_tab = type_gain_tab;
#endif

#if TCFG_DRC_ENABLE
    parm.drc = 1;
#endif

#if TCFG_USER_TWS_ENABLE
    parm.tws = 1;
#endif

#if APP_ONLINE_DEBUG
    parm.app = 1;
#endif

#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
    parm.limit_zero = 1;
#endif

#if TCFG_EQ_DIVIDE_ENABLE
    parm.stero = 1;
    parm.mode_num = 8;
#endif

    if (!parm.stero) {
        parm.mode_num = 5;// 一共有多少个模式
        /* #ifdef DAC_OUTPUT_FRONT_LR_REAR_LR */
        /* #if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) */
        /* parm.mode_num = 6; */
        /* #endif */
        /* #endif */
    }

#if !TCFG_USE_EQ_FILE
#if TCFG_PHONE_EQ_ENABLE
    parm.phone_eq_tab = (void *)phone_eq_tab_normal;
    parm.phone_eq_tab_size = ARRAY_SIZE(phone_eq_tab_normal);
#endif
    parm.ul_eq_tab = (void *)ul_eq_tab_normal;
    parm.ul_eq_tab_size = ARRAY_SIZE(ul_eq_tab_normal);
#endif

    parm.eq_tool_tab = eq_tool_tab;
    parm.eq_mode_use_idx = (u8 *)eq_mode_use_idx;

    parm.eq_type_tab = (void *)get_eq_mode_tab();
#if TCFG_USER_EQ_MODE_NUM
    parm.type_num = TCFG_USER_EQ_MODE_NUM;//EQ_MODE_MAX;
#endif

    parm.section_max = EQ_SECTION_MAX;

    EQ_CFG *eq_cfg = eq_cfg_open(&parm);
    user_eq_cfg = eq_cfg;

    if (eq_cfg) {
        eq_cfg->priv = eq_cfg;
        eq_cfg->send_cmd = ci_send_cmd;
#if APP_ONLINE_DEBUG
        if (eq_cfg->app) {
            app_online_db_register_handle(DB_PKT_TYPE_EQ, eq_app_online_parse);
        }
#endif

#if EQ_FILE_CP_TO_CUSTOM
        eq_file_cp_to_custon_mode_fun(eq_cfg);
#else
        for (int i = 0; i < eq_cfg->mode_num; i++) {
            if (eq_cfg->eq_type == EQ_TYPE_MODE_TAB) {
                set_global_gain(eq_cfg, i, 0);
                drc_default_init(eq_cfg, i);
            }
        }
#endif
    }
    return 0;
}
__initcall(eq_init);
download.bat中添加外部EQ bin文件

image

最后在需要的地方切换EQ使用函数:
void set_user_eq_change(u8 flag);

注意:如果程序还打开 “#define TCFG_AUDIO_OUT_EQ_ENABLE 1 //mix_out后高低音EQ”还需要做以下修改:
image

AC697X

文件eq效果当成自定义模式参与效果切换

原理:把外部EQ读取到系数表,参与到效果切换
实现:具体可参考demo
应用:当存在外部EQ文件需要使用到,同时程序需要切换EQ模式时
【金山文档】 AC697X_eq效果文件参与效果切换使用说明 (1)
https://kdocs.cn/l/cb9fqYSBFRTj

697N_V2.3.x版本SDK多个EQ文件切换

添加如下代码到eq_config.c文件中,download.bat中请自行添加eq bin文件

void eq_cfg_open(void);
#define EQ_FILE_0   SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
#define EQ_FILE_1   SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin"
#define EQ_FILE_2   SDFILE_RES_ROOT_PATH"eq_cfg_hw2.bin"
const u8 *eq_file_list[] = { //需要更多EQ文件,将路径填到这个数组中
    EQ_FILE_0,
    EQ_FILE_1,
    EQ_FILE_2,
};
static u8 file_index = 0; //当前eq文件的序号
/**
 * @brief 切换EQ文件
 * 
 * @param file 0xff:按照eq_file_list的顺序循环切换,n(0~(ARRAY_SIZE(eq_file_list)-1)):切换到eq_file_list中的第n个文件
 */
void eq_file_switch(u8 file)
{
    if(file == 0xff){
        file_index++;
    }
    else{
        file_index = file;
    }
    if(file_index >= ARRAY_SIZE(eq_file_list)){
        file_index = 0;
    }
 
    eq_cfg_open();
    if(p_eq_cfg){
        p_eq_cfg->mode_updata = 1;
    }
}

修改void eq_cfg_open(void)函数

if (eq_file_get_cfg(p_eq_cfg, eq_file_list[file_index]))

image 调用方法:

        void eq_file_switch(u8 file);
        eq_file_switch(0xff);//循环切换数组中的文件
        // eq_file_switch(0);//切换到数组中的第1个文件

image

AC698X

多EQ文件切换

#define EQ_FILE_0   SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin"
#define EQ_FILE_1   SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin"
#define EQ_FILE_2   SDFILE_RES_ROOT_PATH"eq_cfg_hw2.bin"
const u8 *eq_file_list[] = { //需要更多EQ文件,将路径填到这个数组中
    EQ_FILE_0,
    EQ_FILE_1,
    EQ_FILE_2,
};
static u8 file_index = 0; //当前eq文件的序号
/**
 * @brief 切换EQ文件
 * 
 * @param file 0xff:按照eq_file_list的顺序循环切换,n(0~(ARRAY_SIZE(eq_file_list)-1)):切换到eq_file_list中的第n个文件
 */
void eq_file_switch(u8 file)
{
    if(file == 0xff){
        file_index++;
    }
    else{
        file_index = file;
    }
    if(file_index >= ARRAY_SIZE(eq_file_list)){
        file_index = 0;
    }

    EQ_CFG *eq_cfg = get_eq_cfg_hdl();
    eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
    eq_cfg_default_init(get_eq_cfg_hdl());
    drc_default_init(get_eq_cfg_hdl(), song_eq_mode);
    if (!eq_file_get_cfg(get_eq_cfg_hdl(), eq_file_list[file_index])) {
        eq_cfg->eq_type = EQ_TYPE_FILE;
        eq_cfg->mode_updata = 1;
    }
}

698在EQ初始化重设EQ
eq_file_switch(file_index);
image 调用方法:

        void eq_file_switch(u8 file);
        eq_file_switch(0xff);//循环切换数组中的文件
        // eq_file_switch(0);//切换到数组中的第1个文件

image

2M包开SPP在线调试EQ和TWS在线EQ调试同步

2M包btstack.a没有开启SPP协议不能在线调EQ,需要按照698问题处理文档说明修改btstack.a改为4M库。
如果空间不足,V125版本也可以修改下面的库:
【金山文档】 btstack_2M_flash
TWS在线调试EQ2M包未同步参数到从机:默认未开启主从传参数同步,需按照下图修改。
image

AC692X

两个外部EQ文件切换demo:
链接:https://pan.baidu.com/s/1yKRqpBB124b7ugiLM8AF7w
提取码:8888

AC700N/JL701N

u8 curr_eq_index = 0;
const u8 *eq_file_list[] = {
    (u8 *)SDFILE_RES_ROOT_PATH"norm.bin",
    (u8 *)SDFILE_RES_ROOT_PATH"norm_p.bin",
    (u8 *)SDFILE_RES_ROOT_PATH"bass.bin",
    (u8 *)SDFILE_RES_ROOT_PATH"bass_p.bin",
    (u8 *)SDFILE_RES_ROOT_PATH"light.bin",
    (u8 *)SDFILE_RES_ROOT_PATH"light_p.bin",
};

/**
 * @brief 切换EQ效果文件的接口
 * 
 * @param index 对应eq_file_list效果,0xff:循环切换
 */
void eq_effect_switch(u8 index)
{
    if(index == 0xff){
        curr_eq_index++;
        if(curr_eq_index >= ARRAY_SIZE(eq_file_list)){
            curr_eq_index = 0;
        }
    }
    else{
        if(index >= ARRAY_SIZE(eq_file_list)){
            return;
        }
        curr_eq_index = index;
    }

#if (!TCFG_EQ_ONLINE_ENABLE)
    EQ_CFG *eq_cfg = get_eq_cfg_hdl();
    if(!eq_cfg){
        return;
    }
    eq_cfg->eq_type = EQ_TYPE_FILE;
    int ret = eq_file_get_cfg(eq_cfg, eq_file_list[curr_eq_index]);
    printf("eq_effect_switch %d ret %d\n", curr_eq_index, ret);
#endif
}

image

可视化工具AC700+1T2

u8 curr_eq_index = 0;
const u8 *eq_file_list[] = {
    (u8 *)FLASH_RES_PATH "eq_cfg_hw.bin",
    (u8 *)FLASH_RES_PATH "eq_cfg_hw1.bin",
    (u8 *)FLASH_RES_PATH "eq_cfg_hw2.bin",
};

/**
 * @brief 切换EQ效果文件的接口
 * 
 * @param index 对应eq_file_list效果,0xff:循环切换
 */
void eq_effect_switch(u8 index)
{
    if(index == 0xff){
        curr_eq_index++;
        if(curr_eq_index >= ARRAY_SIZE(eq_file_list)){
            curr_eq_index = 0;
        }
    }
    else{
        if(index >= ARRAY_SIZE(eq_file_list)){
            return;
        }
        curr_eq_index = index;
    }

#if (!TCFG_EQ_ONLINE_ENABLE)
    EQ_CFG *eq_cfg = get_eq_cfg_hdl();
    if(!eq_cfg){
        return;
    }
    eq_cfg->eq_type = EQ_TYPE_FILE;
    int ret = eq_file_get_cfg(eq_cfg, eq_file_list[curr_eq_index]);
    y_printf("eq_effect_switch %d ret %d\n", curr_eq_index, ret);
    // syscfg_write(CFG_USER_DEFINE_EQ_INDEX, &curr_eq_index, sizeof(curr_eq_index));
#endif
}

①找个地方放上面代码
image ②这里打开
image ③注意EQ版本和工具生产的EQ文件版本要对应
imageimage ⑤在下载目录的download.bat文件里加入要添加的.bin文件
image ⑥测试用例,音乐播放暂时键触发

    case API_MUSIC_PP:
        y_printf("API_MUSIC_PP");
        eq_effect_switch(0xFF);
        // if (state != BT_CALL_HANGUP) {
        //     break;
        // }
        // user_send_cmd_prepare_for_addr(bt_addr, USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
        break;

image ⑦如果需要关机保存切换的效果,存一下VM(注意不要在中断里读写VM,VM的ID不要与其他的冲突)

#define     CFG_USER_DEFINE_EQ_INDEX    10

//************************************************//

syscfg_write(CFG_USER_DEFINE_EQ_INDEX, &curr_eq_index, sizeof(curr_eq_index));

//************************************************//

#if (!TCFG_EQ_ONLINE_ENABLE)
    u8 user_eq_index = 0;
    int ret = syscfg_read(CFG_USER_DEFINE_EQ_INDEX, &user_eq_index, sizeof(user_eq_index));
    y_printf("ret = %d, user_eq_index = %d", ret, user_eq_index);
    if ((ret>0) && (user_eq_index >= 0 && user_eq_index <= ARRAY_SIZE(eq_file_list))) {
        eq_effect_switch(user_eq_index);
    }
#endif

imageimageimage

最新可视化工具切换EQ文件方法

先添加EQ效果
imageimageimage 使用如下接口切换添加好的多个EQ

#define CFG_FILE_MAX_EQ_NUM  3//有多少个EQ效果这里就填多少
static u8 curr_eq_index = 0;
void eq_effect_switch(u8 index)
{
    if(index == 0xff){
        curr_eq_index++;
    }
    else{
        curr_eq_index = index;
    }
    if(curr_eq_index >= CFG_FILE_MAX_EQ_NUM){
        curr_eq_index = 0;
    }

    eq_file_cfg_switch("MusicEqBt", curr_eq_index);
}
  1. 自定义系数表动态更新
//系数切换
void eq_sw_demo()
{
    eq_mode_sw();//7种默认系数切换
}

//获取当前eq系数表类型
void eq_mode_get_demo()
{
    u8 mode ;
    mode = eq_mode_get_cur();
}
//宏TCFG_USE_EQ_FILE配0
//自定义系数表动态更新
//本demo 示意更新中心截止频率,增益,总增益,如需设置更多参数,请查看eq_config.h头文件的demo
void eq_update_demo()
{
    eq_mode_set_custom_info(0, 200, 2);//第0段,200Hz中心截止频率,2db
    eq_mode_set_custom_info(5, 2000, 2);//第5段,2000Hz中心截止频率,2db

    set_global_gain(get_eq_cfg_hdl(), song_eq_mode, -2);//设置普通音乐eq 总增益 -2db(可避免最大增益大于0db,导致失真)

    eq_mode_set(EQ_MODE_CUSTOM);//设置系数、总增益更新
}
  1. 697N加载了eq_cfg_hw.bin后切换EQ无效果---调通话EQ必须加载EQ文件
int eq_mode_set(u8 mode)
{
#if !TCFG_USE_EQ_FILE
    if (mode >= get_eq_mode_max()) {
        mode = 0;
    }
    eq_mode = mode;
    if (p_eq_cfg && ((p_eq_cfg->eq_type == EQ_TYPE_MODE_TAB) || (p_eq_cfg->eq_type == EQ_TYPE_FILE))) {
        p_eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
        p_eq_cfg->mode_updata = 1;
    }
#endif
    return 0;
}
  1. SDK-eq内部系数表切换修改为淡入淡出配置

AC695X

  1. AC695N_soundbox_sdk_release_3.1.0 310SDK底层已添加了eq系数表切换淡入淡出处理 695n310sdk在eq节点open处添加如下修改:
    image
  2. AC695N_soundbox_其他系列sdk 可以参考以下的修改demo,demo程序在695n200sdk上修改 (客户自行获取AC695N_soundbox_sdk_release_2.0.0公版程序与demo程序进行对比)
    AC695N_soundbox_sdk_release_2.0.0_eq系数表切换添加淡入淡出demo
    链接:https://pan.baidu.com/s/1cnc8Ib3SnJS_Z-dE0sIoKQ
    提取码:8888

AD697X

AC897N_AD697N_earphone_release_V2.4.0_EQ_fade
AC897N_AD697N_earphone_release_V2.4.0_EQ_fade.zip
支持EQ默认系数和EQ文件淡入淡出
可调参数
image

AC700N

br36_V138_eq_xfade.zip -- 适用于AC700N_earphone_release_V1.3.8
8. 可视化高低音使用方法 添加高低音节点
image 要更改节点名称为下图
image 修改编译问题
imageimageimage

__attribute__((weak))
u8 get_mic_current_scene()
{
    return 0;
}

使用demo
image

十二、虚拟低音

image

700N参数调节

image

701N参数调节

image

十三、按键提示音

1、AC697X 按键音添加demo程序

demo提取:
链接:https://pan.baidu.com/s/1yvFNLORiDYy5s4a5Vi3Xew
提取码:8888
跟以下宏KEY_TONE_EN 看:
image

2、AC698X 按键音添加demo程序

demo提取:
链接:https://pan.baidu.com/s/19NqqYFUsyFX2TYsKDFsmpg
提取码:8888
跟以下宏KEY_TONE_EN 看:

image

十四、MP3文件无缝播放

  1. AD697x提示音无缝播放 【金山文档】 AD697_MP3文件无缝播放demo_20221213
    https://kdocs.cn/l/cdcw4JGspyfQ
    主要修改了audio_dec_file.h和audio_dec_file.c
    要使用该功能确保以下宏有打开
#define FILE_DEC_REPEAT_EN            1//0 // 无缝循环播放

#define TCFG_DEC_MP3_ENABLE                       1//0

需要保证播放时不能进入低功耗,最好取消进入低功耗的配置宏和蓝牙没有连接自动关机的宏(当然也可以自行根据需求去控制)

#define TCFG_LOWPOWER_LOWPOWER_SEL            0//1   //芯片是否进入powerdown

#define TCFG_AUTO_SHUT_DOWN_TIME                  0//180   //没有蓝牙连接自动关机时间

在函数 gapless_playback_open 中,将对应的路径换成自己mp3文件的路径,或者将提示音0的文件替换为对应的mp3文件

/**************************************************************
*
*             mp3文件循环播放demo
*            调用该demo需要保证不会进入低功耗功能, 也需关闭蓝牙超时关机
*
*************************************************************/
void gapless_playback_open(void)
{
    printf("--- tone gapless playback ---\n");
    if (!close_gapless_playback_timer_id) {
        u32 time_sec = 120;        //120s
        printf("\n>>> time : %d sec\n\n", time_sec);
        close_gapless_playback_timer_id = sys_timer_add(NULL, gapless_playback_close, 120 * 1000);
    }
    if (!file_sound) {
        file_sound = fopen("mnt/sdfile/res/tone/noise.*", "r");        //mp3文件路径
        if (!file_sound) {
            printf("file_sound open failed!!\n");
        }

    }
    /* 打开循环播放, 需要关闭蓝牙超时关机的功能。也需要避免进入低功耗 */
    file_dec_gapless_playback_open(file_sound);
}

time_sec是定时时间,根据需求修改

十五、简易数据音频解码实现

1. 该工程在原来的基础上实现 PCM数据解码及文件数据解码。
2. 使用注意点如下
    a. user_decoder.c 主要添加的文件
    b. void user_dec_test(void) 函数为提供的测试函数
    c. 用户主要自行修改文件接口如下(读数据接口):
        PCM 解码接口 :user_dec_read
         FILE 解码接口:file_input
    d. FILE 解码 提供一个 测试示范:USER_DEC_TEST //使用默认SD0 里面的 文件名进行测试
        PCM 解码 : 默认播放正弦波

主要文件:user_decoder.c https://kdocs.cn/l/crIImErNZ6DU

/*----------------------------------------------------------------------------*/
/**@brief    测试自定义解码函数
   @param    
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void user_dec_test(void)
{
    static u8 flag = 0;
    // //* FILE
    if(flag){
        user_file_dec_open(USER_DEC_TEST__FILE,AUDIO_CODING_M4A);
    }else{
        //user_file_dec_open(USER_DEC_TEST2__FILE,AUDIO_CODING_MP3);
        audio_dec_file_app_close(user_file_dec);
    }

    flag = !flag;
}

SDK版本_AC695N_soundbox_sdk_release_3.1.0 :https://kdocs.cn/l/ccmSKEeSCXY2
6082_1.2.2_sdk接收SPI数据解码demo
链接:https://pan.baidu.com/s/16My0ixCQPIEgTVxFXbQKjQ
提取码:8888

JL701N 参考接口:

image

十六、辅听耳机

  1. JL701N立体声耳机使用两个mic分别输出到左右声道 【金山文档】 ac701n_earphone_release_v1.6.0_立体声双mic辅听,gitlab链接
    ac701n_earphone_release_v1.6.0_立体声双mic辅听.zip
    V140旧版本:ac701n_earphone_release_v1.4.0_立体声双mic辅听.zip
    以上demo实现立体声耳机的mic0输出到左声道,mic1输出到右声道
    可修改mic的通道
    image 如果左右mic反了,在下面这个位置对调左右声道的数据,点击查看对调方法
    image
  2. JL700V1.3.8版本移植--why 20260729 AC700N_earphone_release_V1.3.8_立体声双mic辅听.zip

十七、第三方算法添加

  1. 第三方算法添加参考文档 第三方音效算法接入介绍_20230712.01.pdf

2. PCM DELAY用第三方算法实现demo

AC701N patch06之前的版本用第三方算法节点实现新版本的pcm delay节点功能.otl

十八、变速变调

宏定义:

//696/695/701
#define TCFG_SPEED_PITCH_ENABLE             DISABLE//
b

image

变速有具体的换算方法

static int get_speedV(float speed)
{
    int speedV;
    if (speed >= 1) {
        //变快
        speedV = (256 - 256 / speed) * 80 / 140 + 80;
    } else {
        //变慢
        speedV = 80 - (256 / speed) * 80 / 450;
    }
    return speedV;
}

FAQ

1、AC696N_soundbox_sdk_release_1.6.0

【音箱SDK1.6.0】修复开混响EQ和蓝牙EQ同时开导致蓝牙播歌卡顿

替换一个media_app.a文件
media_app(SDK1.6.0_修复开混响EQ和蓝牙EQ同时开导致蓝牙播歌卡顿)

2、AC700X 双声道差分和单声道差分动态切换例子

1、程序默认设置为双声道差分输出 DAC_OUTPUT_LR

image

  1. 当要动态切换到单声道差分输出时,直接拿左右声道数据相加除2处理,以达到单声道差分输出效果(左右声道耦合输出): image
s16 *buff = data;
u16  temp_len = len/2;
u16 i = 0;
if(typeC_insert == 0)  //切换条件,自己根据应用定义使用
{
    while(i<temp_len)
    {
        s16 temp = (buff[i]+buff[i+1])/2; //左右声道相加除以2
        buff[i] = temp;  //把叠加后的数据分别赋予左右声道
        buff[i+1] = temp; //把叠加后的数据分别赋予左右声道
        i+=2;
    }
}
  1. 二代音效算法音效文件汇总

20段EQ

image 【金山文档】 music_base20
https://kdocs.cn/l/ceJB5IRSuM7k

虚拟低音

【金山文档】 music_base_vbass
https://kdocs.cn/l/cooqAsLBgN2r

DRC

1、增加2带drc和3带drc的音效文件到effects_file目录(music_base_mdrc.bin、music_base_mdrc_3b.bin)
2、使能宏#define TCFG_AUDIO_MDRC_ENABLE 1
3、在download.c内添加copy .\effect_file\music_base_mdrc.bin eq_cfg_hw.bin
例如:
image

2段DRC

【金山文档】 music_base_mdrc
https://kdocs.cn/l/cdoeLsUYdEXS

3段DRC

【金山文档】 music_base_mdrc_3b
https://kdocs.cn/l/ctTaycra29eT

3段DRC+虚拟低音

【金山文档】 music_base_mdrc_3b_vbass
https://kdocs.cn/l/cqd9Zv5omOQa
image

3段DRC+虚拟低音+后级EQ

image

【金山文档】 music_base_mdrc_3b_vbass_eq2
https://kdocs.cn/l/cnLgQTJVotLC

3段DRC+全带DRC

image 【金山文档】 music_base_mdrc_3b_and_wholedrc
https://kdocs.cn/l/cpQ13exjIwzV

带混响的音效

【金山文档】 mic_effect_echo_mdrc_3b
https://kdocs.cn/l/ca3bMNuo3UXW
imageimage

JL701N 带混响的音效文件

imageimage

【金山文档】 JL701N_mic_effect_2023年7月6日
https://kdocs.cn/l/caM5PivD6hVg

如果在使用695N音效文件中话筒的EQ段从5段改为10段,替换以下文件和修改以下代码
1、代码修改
image 2、替换音效文件
【金山文档】 mic_effect_full
https://kdocs.cn/l/csXacB9BZcg1

本文档包含以下子页面

  • 杰理HDMIARC开发实现过程
  • 音频PCM数据淡入淡出(可视化)
  • 第三方音效算法接入介绍_20230712.01
  • AC701N patch06之前的版本用第三方算法节点实现新版本的pcm delay节点功能
Prev
ADC模块
Next
新Tools的音效调试使用