大家好,欢迎来到IT知识分享网。
音频编解码
音频编码
编码流程
音频编码用于把PCM数据通过一定编码器压缩成对应的数据。

音频解码
音频解码 用于把数据通过一定解码器转换成PCM数据。
解码架构
编解码格式
按压缩程度区分:
按数据来源区分:
按技术标准区分:
文件名后缀
格式检查
空间冲突
音频数据流
数据流简介
数据流 是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。
示例:
// 数据流节点初始化 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.更改声音的响度是改变了声音的大小。一般我们会针对不同的频率来调节响度,比如,把低频的响度增加,就可以达到重低音的效果。
高级处理
补充 – 相位
相位 (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,主动降噪,是麦克风收集外部的环境噪音,通过机器学习等方式,把环境噪声变换为一个反相的声波加到喇叭端,最终人耳听到的声音是:环境噪音+反相的环境噪音,两种噪音叠加从而实现感官上的噪音降低。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/115236.html













