音频编解码、数据流、音效处理

news2024/11/25 22:46:03

音频编解码

音频编码

编码流程

音频编码用于把PCM数据通过一定编码器压缩成对应的数据。

编码架构

音频解码

音频解码 用于把数据通过一定解码器转换成PCM数据。

 解码架构

编解码格式

按压缩程度区分:

不压缩的格式(UnCompressed Audio Format):PCM数据、wav(PCM类型)。
无损压缩格式(Lossless Compressed Audio Format):FLAC、APE、dts、m4a。
有损压缩格式(Lossy Compressed Audio Format):mp3、wma、wav(ADPCM等

按数据来源区分:

流媒体格式(一帧一帧的数据):sbc、msbc、cvsd、aac。
文件格式(音频文件):mp3、wav、wma、flac、ape、m4a、amr、dts、alac。
既可以用于流媒体解码又可以用于文件解码的格式:MSBC

按技术标准区分:

标准格式(国际通用):mp3、wav、wma、flac、ape、m4a、sbc、msbc、cvsd。
自定义格式(仅本司SDK可以使用):G729(wtg)、G726、MTY、wtgv2。

文件名后缀

一般音频格式都有其固定的文件名后缀,如mp3格式:123.mp3
同一文件名后缀,格式可能不同。如wav后缀,可能是adpcm或者dts格式;mp4后缀,可能是m4a或者alac格式。
同一格式,文件名后缀也可能不同。如dts格式,可能是dts或者wav后缀。

格式检查

一般流媒体格式的数据不需要做格式检查,由应用层指定解码格式,如sbc等。
文件解码格式会有格式检查,格式检查正确后才使用对应的解码器解码,如wma等。
mp3的格式检查较弱,如果是其他格式的音频(如wav)使用mp3解码器格式检查,也有可能检查正确,因此,mp3解码器应放在最后检查

空间冲突

代码里面的空间分配在sdk_ld.c中,编译之后的空间占用可以在sdk.map中查看。
overlay里面的空间是共用的,同时只能一个分支。比如正在使用overlay_wma的时候就不能同时使用overlay_mp3,因此假设需要用mp3解码做提示音的时候,就需要把overlay_mp3中的mp3_mem等段定义全部放到非overlay区域中去。

音频数据流

数据流简介

数据流 是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。

示例:

// 数据流节点初始化
audio_decoder_open(&audio_dec.decoder); // 打开解码任务
audio_eq_open(&eq); // 打开eq
audio_dac_new_channel(&dac_hdl, &default_dac); 	// 打开DAC
// 创建数据流
stream = audio_stream_open(&audio_dec.decoder, stream_resume_cb);
// 数据流串联
struct audio_stream_entry *entries[4];
entries[0] = &audio_dec.decoder.entry;
entries[1] = &eq.entry;
entries[2] = &default_dac.entry;
audio_stream_add_list(stream, entries, 3);

音频数据流分流处理

分流 是在原数据流的基础上拷贝一份数据,从这份数据开始重新创建一条新的数据流。

示例:

// 数据流节点初始化
audio_decoder_open(&audio_dec.decoder); // 打开解码任务
audio_eq_open(&eq); // 打开eq
audio_eq_open(&eq1); // 打开eq1
audio_dac_new_channel(&dac_hdl, &default_dac); 	// 打开DAC
audio_iis_open(&iis);                  //  打开IIS
// 创建数据流
stream = audio_stream_open(&audio_dec.decoder, stream_resume_cb);
// 添加解码
audio_stream_add_first(stream, &audio_dec.decoder.entry);
// 添加解码第一路输出流
audio_stream_add_entry(&audio_dec.decoder.entry, &eq.entry);
audio_stream_add_entry(&eq.entry, &default_dac.entry);
// 添加解码第一路输出流
audio_stream_add_entry(&audio_dec.decoder.entry, &eq1.entry);
audio_stream_add_entry(&eq1.entry, &iis.entry);

 音频数据流群组处理

群组 是把多个数据流关联上,当激活尾部的数据流时,能依次激活群组里面的其他数据流。

 示例:

// 创建数据流
stream0 = audio_stream_open(&dec0.decoder, stream0_resume_cb);
stream1 = audio_stream_open(&dec1.decoder, stream1_resume_cb);
stream_n = audio_stream_open(&mixer.decoder, stream_n_resume_cb);
// 数据流0
audio_stream_add_first(stream0, &dec0.decoder.entry);
audio_stream_add_entry(&dec0.decoder.entry, &mix0.entry);
// 数据流1
audio_stream_add_first(stream1, &dec1.decoder.entry);
audio_stream_add_entry(&dec1.decoder.entry, &mix1.entry);
// 数据流n
audio_stream_add_first(stream_n, &mixer.entry);
audio_stream_add_entry(&mixer.entry, &default_dac.entry);
// 关联数据流,把数据流n作为群组的尾部数据流
audio_stream_group_add_entry(&test_group, &mix0.entry);
audio_stream_group_add_entry(&test_group, &mix1.entry);
mixer.entry.group = &test_group;

注意事项

1.自定义数据流节点 - 输入输出buf相同

输入输出buf相同是指数据流节点直接更改 in->data 里面的内容,不使用额外的buf来作为输出,例如数字音量处理。

// 数据处理
static int demo_data_handler(struct audio_stream_entry *entry,
                             struct audio_data_frame *in,
                             struct audio_data_frame *out)
{
    struct demo_hdl *demo = container_of(entry, struct demo_hdl, entry);
    // 设置输出信息,这里输出和输入相同
    out->data = in->data;
    out->data_len = in->data_len;
    if (in->data_len - in->offset > 0) {// 数据处理
        demo_deal(demo, in->data + in->offset / 2, in->data_len - in->offset);
    }
    return in->data_len;
}

2.自定义数据流节点 - 输入输出buf不同

输入输出buf不同是指数据流节点处理后,用额外的buf来保存输出数据,例如变采样处理。

static int demo_data_handler(struct audio_stream_entry *entry,
                             struct audio_data_frame *in,
                             struct audio_data_frame *out)
{
    struct demo_hdl *demo = container_of(entry, struct demo_hdl, entry);
    out->sample_rate = demo->out_sr;// 设置输出信息
    if (demo->remain_len) {// 输出剩余数据
        out->data_len = demo->remain_len;
        out->data = demo->remain_buf;
        return 0;
    }
    int len = demo_deal(demo, in->data, in->data_len);// 数据处理
    out->data_len = demo->remain_len;// 更改信息
    out->data = demo->remain_buf;
    return len;
}

3.添加数据流节点1

以数组方式添加节点,调用audio_stream_add_list()函数添加。该方式可以快速把多个节点链接在一起,方便更改顺序等。

// 数组方式添加节点                                    
struct audio_stream_entry *entries[8] = {NULL};        
u8 entry_cnt = 0;                                      
entries[entry_cnt++] = &dec->decoder.entry;            
entries[entry_cnt++] = &dec->eq_drc->entry;            
entries[entry_cnt++] = &default_dac->entry;            
audio_stream_add_list(dec->stream, entries, entry_cnt);

4.添加数据流节点2

以单个方式依次添加节点,调用audio_stream_add_entry()函数添加。该方式的第一个节点需要用audio_stream_add_first()函数。

// 单个方式依次添加节点
audio_stream_add_first(dec->stream, &dec->decoder.entry);
audio_stream_add_entry(&dec->decoder.entry, 
                       &dec->eq_drc->entry);
audio_stream_add_entry(&dec->eq_drc->entry, 
                       &default_dac->entry);

5.添加数据流节点3

在原数据流中添加节点。调用audio_stream_add_head()/audio_stream_add_tail()函数添加。该方式用于在已经创建好的数据流链表中加入节点,所有方式的添加都是在数据流使用之前处理。

// 在原数据流中添加节点
audio_stream_add_head(dec->stream, &dec->eq_drc1->entry);
audio_stream_add_tail(dec->stream, &dec->dac->entry);

6.参数处理

数据流节点处理函数中,*in参数带有一些音频信息,如:采样率、声道等。当前数据流节点对于信息敏感的,需要处理该参数。例如eq处理。

static int eq_data_handler(struct audio_stream_entry *entry,
                             struct audio_data_frame *in,
                             struct audio_data_frame *out)
{
    struct eq_hdl *eq = container_of(entry, struct eq_hdl, entry);
    if (eq->sr != in->sample_rate) {//参数判断
        eq->sr = in->sample_rate;
        audio_eq_set_samplerate(eq, eq->sr);
    }
    int len = eq_deal(eq, in->data, in->data_len);// 数据处理
    out->data_len = eq->remain_len;// 更改信息
    out->data = eq->remain_buf;
    return len;
}

7.本次没输出完,下次继续输出

数据流节点处理本次没有输出完成的情况下,下次数据流过来应该先输出上一次的剩余数据,全部输出完后才继续处理。

// data_handler函数里的处理
if (demo->remain_len) { // 输出剩余数据
    struct audio_data_frame frame;
    memcpy(&frame, in, sizeof(frame));// 复制原输出信息
    // 更改信息
    frame.sample_rate = demo->out_sr;
    frame.data_len = demo->remain_len;
    frame.data = demo->remain_buf;
    audio_stream_run(entry, &frame);// 数据流输出
    if (demo->remain_len) {// 还没输出完,退出
        return 0;
    }
}
// 数据处理
int len = demo_deal(demo, in->data, in->data_len);

8.激活机制

数据流节点处理处理数据时,如果本次不能处理完全部的 in->data_len数据,那么上层应用应该挂起该数据流。当该节点可以再次处理时激活数据流。如果是后级数据流无法输出,则由后级无法输出的数据流节点激活。

static int demo_data_handler(struct audio_stream_entry *entry,
                             struct audio_data_frame *in,
                             struct audio_data_frame *out)
{
    struct demo_hdl *demo = container_of(entry, struct demo_hdl, entry);
    run_len = in->data_len > 512 ? 512 : in->data_len;
    demo->need_resume = (run_len == in->data_len) ? 0 : 1;
    demo_deal(demo, in->data, run_len);// 处理数据
    out->data_len = run_len;
    out->data = demo->buf;
    return len;
}
// 当可以再次处理的时候再激活
if (demo->need_resume) {
    audio_stream_resume(&demo->entry);
}

音效处理

声音的特性

音调 是指声音的高低,就是我们平时所说的高音,低音。音调由物体振动的频率决定的,频率越高,声音的音调就越高,反正,音调则低。

响度 是指声音的强弱,也就是我们日常生活中常说的声音的大小。声音的响度是由物体振动时的振幅决定的。

音色 是指声音的特色、品质,由声音波形的谐波频谱和包络决定。主要与发声体的材料、结构有关。同样是演奏《梁祝》,我们却能听出二胡演奏和钢琴演奏的不同,因为二者的结构不同,发出声音的音色不同。

 音效处理简介

音效处理就是把一段音频进行二次编辑,达到改变音乐风格等目的。

 更改音调、响度

1.简单的更改声音的音调就可以达到声音变化的效果。比如,把一段48Khz的音频改用8Khz来播放,就可以达到类似树懒(疯狂动物城,闪电)说话的效果。

2.更改声音的响度是改变了声音的大小。一般我们会针对不同的频率来调节响度,比如,把低频的响度增加,就可以达到重低音的效果。

高级处理

一般采用叠加的方式来处理音频。
叠加相对独立的音频,比如KTV里面的麦克风和音乐背景声的叠加。
叠加反向音频,这种情况下音频会被消除,比如接打电话时的降噪功能。
反复叠加某一段音频,这种就是混响(回声)的工作机制。

补充 - 相位

相位 (phase)是对于一个波,特定的时刻在它循环中的位置:一种它是否在波峰、波谷或它们之间的某点的标度。相位发生在周期性的运动之中。相位最直接的理解是角度。这个角度存在于匀速圆周运动之中。实际应用过程中,可能会用到相位处理来辅助其他音效处理。比如做麦克风降噪的时候,就用到反向相位来消除噪声。

音效示例-EQ\DRC

EQ 均衡器(Equalizer),用来调节音频中各种频率的幅度值。比如通过调节eq来得到重低音、流行音等音效。也用于补偿喇叭、麦克风等物理元器件引起的缺陷
DRC Dynamic Range Control动态范围控制提供压缩和放大能力。一般用于eq之后,防止eq调节幅度太大溢出。

音效示例-高低音

高低音 是EQ/DRC的一种简单应用,仅调节音频的高音和低音两个频点(默认125Hz、12000Hz)。

音效示例-混响、回音

混响 reverberation(残响),当一个声音发出后,当它碰到障碍物后会反射,碰到下一个障碍物会再反射,不停反射直至它的能量消失为止。这个持续在空间中反覆反射动作形成的声音集成,就是残响。
回音 echo算是混响的一种,当回声与原始声音直接的间隔较大时,如 >200ms,我们耳朵能分辨出两个声音的就是 Echo

音效示例-噪声抑制

噪声抑制 noisegate,这里是指混响过程中的麦克风声音门限处理。

音效示例-啸叫抑制

啸叫抑制 howling suppression。声源与扩音设备之间因距离过近等问题导致能量发生自激,产生啸叫。啸叫不仅会影响听觉,也会烧坏音响设备。技术上通过移频器(升高或降低输入音频信号的频率,改变频率的输出信号再次进入系统不会和原始信号频率叠加)、陷波器(通过降低啸叫频率点处增益,破坏啸叫产生的增益条件)等方式抑制啸叫。

音效示例-变声

变声 pitch,通过改变声音的频率等达到变速变调的效果,如女声变男声、怪兽音等。

环绕音 surround,是指通过放置音源于不同的位置,通过解码器解码,把声音按照不同时间在不同的音箱里播放出来。环绕声完美地再现声音的层次感,增加了听者对临场感的体验。这里指利用现代电声技术在不改变左右声道扬声器位置的情况下,对左右声道的各频率成分的音量与相位分别进行调节,形成音响的全方位的空间立体感

等响度 equalloudness。声音实际响度和人耳实际感受的响度并不完全呈线性关系,在小音量的时候,人耳对中高频的听觉会有生理性衰减,音量越小,这种衰减越明显。等响度控制其作用是在低音量时提升高频和低频成分的音量,使得低、中、高部分的响度比例保持和在大音量时的响度比例相同

音效示例-人声消除

人声消除 vocal_remove,是一种可以将立体声歌曲的人声消除的技术。人声的声波波形在歌曲的两个声道是相同或者相似的,因此,我们可以简单采取两个声道相减的办法来消除立体声歌曲中的人声。但是,这样做有时会损失歌曲中的低音。因此,常用的人声消除会对低音进行补偿等。

ENC Environmental Noise Cancellation,环境降噪技术,能有效抑制反向环境噪声。我们主要通过agc 数字放大、aec 回声消除、es 回声压制、ans 降噪模块等技术手段实现降噪功能。

ANC Active Noise Control,主动降噪,是麦克风收集外部的环境噪音,通过机器学习等方式,把环境噪声变换为一个反相的声波加到喇叭端,最终人耳听到的声音是:环境噪音+反相的环境噪音,两种噪音叠加从而实现感官上的噪音降低。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1835336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么使用海外仓系统?首次引入海外仓系统必备事项清单

本文将系统分析首次引入海外仓系统时的必备事项,如果您已经在使用类似的系统,可以根据需要跳跃性阅读。 如果现在海外仓还依赖传统的仓储系统、手动流程甚至电子表格来管理海外仓、一件代发业务,那必然会造成出错率高,运营效率低…

RFID期末复习 | 防碰撞算法 | 信源编码 | 差错控制 | 系统调制 | S50卡 | 无源标签 | 工作频率 | 自动识别

防碰撞算法 ALOHA算法 ALOHA算法是一种随机接入方法,其基本思想是采取标签先发言的方式,当标签进入读写器的识别区域内时就自动向读写器发送其自身的ID号,在标签发送数据的过程中,若有其他标签也在发送数据,将会发生…

如何评价2023年亚太杯数学建模竞赛?

APMCM亚太数学建模大赛的含金量在数学建模比赛中虽然不是最高水平,但是也属于比较高的水平了,值得参加试一试。 比如本次C题, 问题一:研究分析影响中国新能源汽车发展的主要因素,建立数学模型,描述这些因…

数据瀑布图升级(自备)

目录 数据整理 初级绘图 升级细节 绘制点图添加曲线和特征筛选-CSDN博客 肿瘤免疫反应瀑布图(源于The Miller Lab)_肿瘤瀑布图-CSDN博客 数据整理 rm(list ls()) library(ggplot2) library(dplyr) library(ggrepel)##防止标签重叠 #模拟数据 dat…

Linux-DNS域名解析服务01

BIND 域名服务基础 1、DNS(Domain Name System)系统的作用及类型 整个 Internet 大家庭中连接了数以亿计的服务器、个人主机,其中大部分的网站、邮件等服务器都使用了域名形式的地址,如 www.google.com、mail.163.com 等。很显然…

Vue02-第一个Vue程序

第一个Vue程序 1、什么是MVVM MVVM(Model-View-ViewModel)是一种软件设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet&#xff0…

Windows 安装 java 环境

搭建java开发环境 java的产品叫JDK(java开发者工具包),必须安装JDK才能使用Java。 一、下载——java下载网址 二、安装 直接全部下一步就行,(安装路径可以更换一下)。 配置JAVA_HOME环境变量, 安装完成后…

css-Echarts图表柱状图,X轴横坐标值显示不完全问题

1.问题 在Echarts图表中当横坐标数值过多,或者数值过长时会导致部分横坐标不显示。数据量少或简单会默认显示完全,当放大时会导致部分横坐标隐藏。 更改第一个Mon字段名 会发现偶数横坐标显示隐藏; 2.解决方法 2.1 在x横坐标中添加interval…

办理无区域名称公司核名流程和条件及时间说明

无行政区划公司是指公司名称中不带有对应的行政区划,经营上不受地方限制。其名称需要通过国家工商总局核名,核名成功后会颁发《名称核准通知书》。之后便可以进行印章制作、银行开户等流程。详情致电咨询我或者来公司面谈。 公司国家局核名的步骤包括&am…

Node.js版本管理工具-NVM

在开发 Node.js 项目时,经常会遇到需要切换不同版本的 Node.js 的情况。为了方便管理和切换各个版本,我们可以使用一些 Node.js 版本管理工具。 Node Version Manager:简称NVM,最流行的 Node.js 版本管理工具之一。它允许我们在同…

AI大模型落地应用场景:LLM训练性能基准测试

随着 ChatGPT 的现象级走红,引领了AI大模型时代的变革,从而导致 AI 算力日益紧缺。与此同时,中美贸易战以及美国对华进行AI芯片相关的制裁导致 AI 算力的国产化适配势在必行。之前也分享过一些国产 AI 芯片、使用国产 AI 框架 Mindformers 基…

工业物联网关为智能制造业提供哪些支撑?天拓四方

随着科技的飞速发展,智能制造业已成为工业领域的转型方向。在这一转变中,工业物联网关发挥着至关重要的作用。作为连接物理世界与数字世界的桥梁,工业物联网关不仅实现了设备与设备、设备与云平台之间的互联互通,更通过实时数据采…

post为什么会发送两次请求详解

文章目录 导文跨域请求的预检复杂请求的定义服务器响应预检请求总结 导文 在Web开发中,开发者可能会遇到POST请求被发送了两次的情况,如下图: 尤其是在处理跨域请求时。这种现象可能让开发者感到困惑,但实际上它是浏览器安全机制…

Linux安装MySQL以及远程连接

1、Linux安装MySQL 1.1、准备解压包 MySQL5.x解压包 提取码:9y7n 1.2、通过rpm脚本安装 切记安装顺序:common --> libs --> client --> server 因为它们之间存在依赖关系,所以务必按照顺序安装 安装前请确保当前目录/文…

金融科技行业的融资趋势、投资者关注及未来预测

一、金融科技行业的融资趋势 金融科技行业的融资趋势近年来展现出强劲的增长势头,具体表现在以下几个方面: 融资规模持续扩大: 根据《全球金融科技投融资趋势报告(2023年上半年)》,2023年上半年全球金融科技行业投融资事件总次数…

防泄密解决方案

防泄密解决方案是一个系统性的策略,旨在保护敏感信息不被非法获取、泄露或滥用。以下是一个结构清晰、分点表示的防泄密解决方案,结合了参考文章中的关键信息和建议: 一、策略制定与政策明确 明确数据分类:将数据分为公开、内部…

【区块链】POS(Proof of Stake)权益证明算法深度解析

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 POS(Proof of Stake)权益证明算法深度解析引言1. POS基本…

【方法】如何隐藏和保护Excel表格中的敏感数据?

在工作中,很多人经常需要处理包含敏感信息的Excel表格。 为了确保这些数据的安全性,我们可以通过隐藏单元格、行和列,以及设置密码保护工作表的方法,来保护数据,下面一起来看看吧! 一、隐藏数据&#xff1…

微信商城源码带分销功能 支持微信小程序+公众号端 含详细图文搭建教程

分享一款微商城源码系统,不仅支持微信公众号端和小程序端二合一管理,带分销机制,集合了市面上电商系统的功能,并增加了多项全新特色功能,如多商户商家入驻、区域代理、收银台、互动直播等,为商家提供了全方…

Go——channel

channel是Go在语言层面提供的协程间的通信方式。通过channel我们可以实现多个协程之间的通信,并对协程进行并发控制。 使用注意: 管道没有缓冲区时,从管道中读取数据会阻塞,直到有协程向管道中写入数据。类似地,向管道…