Codec2语音编码技术小结

Codec2语音编码技术小结

(1)

        作为音频编解码方向的一个分支,低码率语音压缩技术有广泛的应用场景。目前学习一个优秀的语音编码库Codec2(非Android Codec2框架),从demo的接口使用,到库中模块实现,见招拆招,一点点去了解背后实现原理。

首先,先对于音频编解码标准有个大致的介绍:

编码技术

压缩效率

应用场景

MPEG-1 编码-audio layer 1

384kbps(压缩 4 倍)

数字盒式录音磁带

MPEG-1 编码-audio layer 2

256~192kbps(压缩 6~8 倍)

数字音频广播(DAB)和 VCD

MPEG-1 编码-audio layer 3

128~112kbps(压缩 10~12 倍)

MP3 音乐

AAC(Advanced Audio Coding

96-128 kbps

Ipod, 取代mp3格式

Dolby AC-3

64kbps

环绕立体声,数字电视、家庭影院

AMR(Adaptive Multi-Rate)

不同码率适用不同场景(16kbps=电话音质、112kbps=FM 调频立体声广播、192kbps=CD)

移动设备,语音电话

超低码率技术

<=5kbps

对讲技术

        对于多媒体语音,我们熟悉有熟悉的MP3,AAC格式,对于通话voip,使用了AMR格式;而超低码率技术,则主要应用在语音对讲领域。

        语音编解码器通常分为以下三种类型:波形编译码器、音源编译码器、混合编译码器。

其比特率与语音质量关系所示:

        在语音领域中厂家提供语音处理芯片,而Codec2开源项目的出现,绕开了专利限制,提供了一个优秀的语音处理框架。

        例举以下语音处理算法:

1. MELP and MELPe Vocoder (codec):

   支持  2400 bit/s ,1200 bit/s,600 bit/s,300 bit/s,需要向Compandent购买。

2. HVXC@MPEG4 Audio:HVXC(Harmonic Vector Excitation Coding)

   固定比特率有:2kbps和4kbps。可变比特率有:1.2~1.7kbps,需要向MPEG购买。

3.AMBE :

   AMBE-LR: 1.6 - 1.8 kbps,需要向DVSI购买(Digital Voice Systems, Inc.)。

4. Codec 2 

  开源免费 700 bit/s ~ 3200 bit/s。音质介于LPC-10与MELP/AMBE之间。

(2)

       那言语是如何生成的?为什么可以通过数学模型去建模这个过程?再来了解下发声生理原理:

       简单来说言语产生是由三个系统(呼吸系统、发声系统和构音系统)的共同作用实现的。

        贮存在肺、气管与支气管内的气体有规律地随呼气运动排出,形成气流。当气流到达声门处时,被转变成一系列的脉冲信号(声门波)。然后通过声道的共鸣作用,形成具有适当形态的声波,最终由嘴和鼻发出言语信号(声波)。

        定义语音数学模型为:激励-滤波模型

语音信号经过传输,通过播放设备再次形成声波震动,传入人耳。

        语音的编码过程既然是信号处理的过程,涉及信号的时域频域转化,根据傅里叶级数定义,周期函数可以用正弦函数和余弦函数构成的无穷级数来表示。

时频神图展示:

把信号从时域变换到频域,通过频率,幅值,相位的特征进行描述。

        那语音的特征都有哪些?怎么在语音信号的时域和频域中体现呢?

需要了解下先,语音的三要素:音量、音调、音色。

波形的振幅决定了声音的响度大小,基频频率决定了音调,谐波和共振峰决定了音色。

在时域语音:

在频域语音:

在语音编码过程中就是通过算法去提取这些重要特征,用特征集合去还原音频,从而达到极高的压缩效率。

此外,以下几个概念也很重要:

频谱图与语谱图

频谱图就是语音帧的频域变换(FFT):

语谱图是以时间为横坐标,纵坐标装入频谱,通过二维坐标表示出了三维信息。

如图,横坐标是时间,纵坐标是频率,坐标点值为语音数据能量,能量值的大小是通过颜色来表示的,颜色越深表示该点的能量越强。一条条横方向的条纹,称为“声纹”。它因人而异,即不同讲话者语谱图声纹是不同的,因而可以用声纹鉴定不同的讲话人。

语谱图中的花纹有横杠、乱纹和竖直条等,横杠是和时间轴平行的几条深色带纹,它们相应于短时谱中的几个凸出点,即共振峰,有没有横杠出现是判断它是否是浊音的重要标志。

浊音与清音

浊音,当声带处于收紧状态,流经的气流使声带振动,例如一般的母音等。当说话时手按喉咙能感到振动,那就是浊音。

清音,当声带处于放松状态,不伴有声带振动的音,手按喉咙没震动就是清音;

前面提到的激励-滤波模型,可以这样理解:气流与声门,等效为激励源;对应的是激励频率,也就是基音频率F0;声道,等效为滤波器;对应的是谐振频率

       这些语音的基本概念的中英对照如下,看论文对应上,别云里雾里。

音调

Pitch

音色

Timbre

基频

Fundamental

定义音调

谐波

Harmonics

决定音色

共振峰

Formant

频谱

Spectrum

语谱图

Spectrogram

频谱+时间

浊音

Voiced

对于10ms一帧语音,给出清浊判断,其影响激励源生成

清音

Unvoiced

激励源

Excitation

清音激励源白噪声;

浊音激励源根据基频及相位生成;

(3)

        了解了以上的语音基础知识,让我们再学习下Codec2是如何工作的,当然这部分的学习要参照作者David Grant Rowe的博士论文《Techniques for Harmonic Sinusoidal Coding》来看。

        对于具体的算法的理解随缘吧,对于一些重要的概念,找了下相关定义:

线性预测编码(Linear Predictive coding ,LPC),是一种用于语音信号压缩和分析的方法。在LPC模型中,语音信号被看作是由若干个共振峰和各自对应的带通滤波器的输出叠加而成的。LPC算法估计线性滤波器的系数,该滤波器可以近似信号的谱包络,这些系数被称为线性预测系数(Linear Predictive Coefficients,LPCs)。线性预测系数一般用于描述这些带通滤波器的特性,包括各自的带宽、增益和位置等。对声音波形的编码转化为对参数编码,使声音数据量大大减少;解码端通过合成器重构话音,合成器是一个时变线性滤波器,代表了人的话音生成系统模型。

线谱对(Line Spectral Pairs,LSP)是对线性预测系数的直接数学变换,即对线性预测系数进行表征。通过线谱对频率的疏密程度来反应语音信号的谱特点。LSP具有良好的量化特性和高效性的表达性,因此在语音编码中被广泛运用。

量化( Quant ),指将信号的连续取值(或者大量可能的离散取值)近似为有限多个(或较少的)离散值的过程。

多带激励(Multi-Band Excitation,MBE ),把语音频谱划分为多个频带,对每个带进行二元清浊判断,然后对不同的带采用相应的激励信号,最后将各带合成信号叠加,形成全带合成信号,正式由于平铺分带分析合成,故成为多带激励。

对于数字对讲系统架构如下:

在数字对讲开发上,绕过无线电广播,使用TCP/UDP来完成数据转发。

        语音模型是一组正弦函数叠加而成的,其中Wo是基频,{A}为长度L的幅值集合,{Phi}为长度L的相位集合,长度L为谐波个数。

        在编码端完成工作:在时域完成基频估算并进行量化处理,在频域(FFT变换)用多带激励算法完成清浊音判定,在时域完成线性预测编码估算出LPC系数并行性线谱对映射再及进行量化处理,并提取出幅值能量进行量化。

编码函数流程:

计算得到的特征数据结构如下:

2400bps码率下,320Bytes压缩到6Bytes,压缩效率惊人。

        在解码端,将线谱对系数映射为LPC值后作频域变换(FFT),与幅值能量合成,进行震级恢复,经过后滤波,再根据清浊音进行相位合成继而生成激励源,激励源与LPC通道滤波相乘,再作FFT逆变换恢复到时域(时域卷积==频域相乘),进行叠加处理,恢复音频数据。

解码函数流程:

以上具体的函数实现,需要对照论文去学习了,进入了盲区。。。

        在学习Codec2框架时,一定不要忽略octave这个目录,这个是作者设计的软件滤波器,通过它进行调试,我这里也是使用它去了解算法到底作了啥。【Octave是Linux环境下类Matlab工具包】

1)在了解LPC时,调试指令:

./c2sim ../../raw/hts1a.raw --lpc 10 --dump hts1a_lpc10.raw

plamp("../build_linux/src/hts1a_lpc10.raw",30)

上图结果时什么意思呢?

 

上图是时域语音帧(a)经过频域变换得到幅值频谱(b),而我们可以认为语音信号等同于一个激励信号*滤波器, 这个录波器就是用LPC系数来表达,经过LPC模型的幅值频谱特征如上图,其代表了声道滤波器特征。这样先通过决定清浊音来确定激励信号,又通过计算LPC系数,最后卷积重建音频数据,来逼近原始音频数据。

2)在了解相位提取时,

    ./c2sim ../../raw/hts1a.raw hts1a.mdl --phase0 --dump hts1a_phase0.raw

    plphase("../build_linux/src/hts1a_phase0.raw",30)

算法中,对于相位角不作传递,而是通过清浊及基频去作计算。

3)想看下语音切片数据编解码前后的波形对比:

     pl2("../raw/hts1a.raw", "../build_linux/src/hts1a_c2.raw", 80*26, 80*30)

咦?变化挺大?但没关系,一段语音编码下来听起来效果就很好了。

(4)

        最后小结,在使用Codec2库的过程中,工作量在于嵌入式平台移植,好在所有算法与平台无关,去解决编译错误就行了。库的编解码调用非常简单,把PCM采样数据(8Khz)传入即可,编码后的数据可以通过udp发送(效率),接收端按tcp(顺序及包不丢失)处理。

        在调通功能后,我想进一步了解下这个库的原理,因为对音频无基础,就像扯线头一样扯出了很多的概念,然后去查找了解。

        作者的论文很强大,我通读了下,但设计的数学公式还是不理解。感谢作者Rowe!他是在毕业10多年后完成了整个库的实现,这里找到他的照片!无需介绍,最强者发型^-^。

        开源万岁!

最后推荐音频学习连接(台湾清华 张智星老师):http://mirlab.org/jang/books/audiosignalprocessing/

本文中四处搜罗了很多概念及截图,非原创图。

对算法的深入理解,需要对照代码与作者论文学习,你可以的!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STMicroelectronics提供了一个基于STM32的G.722语音编码示例,可以在STM32Cube软件包中找到。 要使用该示例,您需要安装STM32CubeMX和STM32CubeIDE。 在STM32CubeMX中,您需要选择您的STM32微控制器并配置您的工程,包括配置您的时钟、GPIO、ADC和DAC等。 然后,在STM32CubeIDE中,您需要导入您的工程并添加STMicroelectronics提供的G.722语音编码库。您可以在STMicroelectronics的网站上找到该库的下载链接。 在您的代码中,您需要初始化您的ADC和DAC,并且设置您的采样频率和编码器参数。然后,您可以使用编码器将音频数据编码为G.722格式,并使用解码器将G.722数据解码为音频数据。最后,您可以将解码后的数据发送到DAC并播放音频。 以下是一个简单的代码示例,用于初始化编码器和解码器并进行编码和解码: ``` #include "g722codec.h" #include "stm32f4xx_hal.h" #define SAMPLE_FREQ 16000 G722CODEC_HandleTypedef g722EncoderHandle; G722CODEC_HandleTypedef g722DecoderHandle; void initEncoderDecoder(void) { G722CODEC_Init(&g722EncoderHandle, SAMPLE_FREQ, G722CODEC_BITRATE_64K); G722CODEC_Init(&g722DecoderHandle, SAMPLE_FREQ, G722CODEC_BITRATE_64K); } void encodeData(uint16_t *inputBuffer, uint8_t *outputBuffer, uint16_t inputBufferSize) { G722CODEC_Encode(&g722EncoderHandle, inputBuffer, outputBuffer, inputBufferSize); } void decodeData(uint8_t *inputBuffer, uint16_t *outputBuffer, uint16_t inputBufferSize) { G722CODEC_Decode(&g722DecoderHandle, inputBuffer, outputBuffer, inputBufferSize); } int main(void) { initEncoderDecoder(); // Initialize ADC and DAC while (1) { uint16_t sampleBuffer[256]; uint8_t encodedBuffer[256]; uint16_t decodedBuffer[256]; // Read sample data from ADC encodeData(sampleBuffer, encodedBuffer, sizeof(sampleBuffer)); decodeData(encodedBuffer, decodedBuffer, sizeof(encodedBuffer)); // Write decoded data to DAC } } ``` 请注意,这只是一个简单的示例,您需要根据您的具体应用程序进行更多的配置和调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值