语音压缩存储与回放实验报告__王颖__王燕

语音的压缩、存储与回放

一、 设计要求与目标

(1)使用DSP实现语音压缩和解压缩的基本算法,算法类型自定,例如可以采用G.711、G.729等语音压缩算法。

(2)采用A/D转换器从MIC输入口实时采集语音信号,进行压缩后存储到DSP的片内和片外RAM存储器中,存储时间不小于10秒。

(3)存储器存满之后,使用DSP进行实时解压缩,并从SPEAKER输出口进行回放输出。

(4)使用指示灯对语音存储和回放过程进行指示。

发挥部分:

使用多种算法进行语音的压缩、存储和解压缩,比较它们之间的优缺点。

二、 实验目的

1、通过本实验掌握5402DSP片上外设多通道缓冲串行口mcbsp。

2、学习掌握tlc320ad50CODEC编译码器的内部结构、工作原理。

3、学习A律语音压缩以及C语言下的编程方法。

三、实验原理

1.语音采集与输出模块

语音采集与输出模块采用的是TI公司推出的一款高性能的立体声音频Codec芯片TLC320AD50C,内置耳机输出放大器,支持MIC和LINE IN两种输入方式(二选一),且对输入和输出都具有可编程增益调节。AD50的模数转换(ADCs)和数模转换(DACs)部件高度集成在芯片内部,采用了先进的Sigma-delta过采样技术,可以在8K到96K的频率范围内提供16bit、20bit、24bit和32bit的采样,ADC和DAC的输出信噪比分别可以达到90dB和100dB。与此同时,AD50还具有很低的能耗,回放模式下功率仅为23mW,省电模式下更是小于15uW。由于具有上述优点,使得AD50是一款非常理想的音频模拟I/O器件,可以很好的应用在随声听(如CD,MP3??)、录音机等数字音频领域[2]。由TLC320AD50C组成的语音输入与输出模块不仅采样率高最高可达96K,且外围电路简单,性价比高。

2.语音编码

(1) 概念:

语音编码一般分为两类:一类是波形编码,一类是被称为“声码器技术”的编码。 PCM编码即脉冲编码调制。

波形编码的最简单形式就是脉冲编码调制(Pulse code modulation),这种方式将语音变换成与其幅度成正比的二进制序列,而二进制数值往往采用脉冲表示,并用脉冲对采样幅 度进行编码,所以叫做脉冲编码调制。

脉冲编码调制没有考虑语音的性质,所以信号没有得到压缩。

(2)量化:

脉冲编码调制用同等的量化级数进行量化,即采用均匀量化,而均匀量化是基本的量化方 式。但是均匀量化有缺点,在信号动态范围较大而方差较小的时候,其信噪比会下降 。 国际上有两种非均匀量化的方法:A律和u律,u律是最常用的一种。在美国,7位u律是长途电话质量的标准。 而我国采用的是A律压缩,而且有标准的A律PCM编码芯片。

(3)DPCM&ADPCM:

降低传输比特率的方法之一是减少编码的信息量,这要消除语音信号中的冗余度。相邻的语音样本之间存在明显的相关性,因此对相邻样本间的差信号进行编码,便可使信息量得

到压缩。因为差分信号比原语音信号的动态范围和平均能量都小。这种编码叫Differential PCM,简称DPCM,即差分脉冲编码调制。

ADPCM即自适应差分脉冲编码调制,是包括短时预测的编码系统。CCITT(国际电报电话咨询委员会)在19xx年提出的32 kbit/s的编码器建议就是采用ADPCM作为长途传输中的国际通用语音编码方案。这种ADPCM编码方案达到64 kbit/s PCM的语音传输质量,并具有很好的抗误码性能。

(4)a律压缩

a律压缩示意图

语音压缩存储与回放实验报告王颖王燕

A律压缩编码表

语音压缩存储与回放实验报告王颖王燕

采用DSP可以直接对PCM编码后的语音信号进行μ律和A律压缩。图1是DSP硬件实现数据压缩解压的简单流程,DSP将传输来的压缩后的数据进行解压成16位或者32位,然后对解压后的数据进行分析、处理,最后将处理后的数据按照要求压缩成8位的数据格式输出到相应设备,供其他设备读取。 2

图1 数据压缩解压流程

图2是DSP将数据解压的值,DSP将压缩的8位数据解压成16位的DSP通用数据格式,其中高13位为解压后的数据,低3位补0。这是因为6.711的A律压缩只能对13位数据操作。DSP将解压后的数据放在缓冲串口的发送寄存器中,只要运行发送指令,缓冲串口就会将数据发送出去。缓冲串口对接收数据的解压过程和压缩过程完全相反。图3是μ律数据解压的示意图。

语音压缩存储与回放实验报告王颖王燕

图2 A律数据解压

语音压缩存储与回放实验报告王颖王燕

图3 μ律数据解压

DSP内部的缓冲串口(McBSPs)带有硬件实现的μ律/A律压缩解压,用户只需要在相应寄存器中进行设置就可以了。

在进行A律压缩时,采样后的12位数据,默认其最高位为符号位,压缩时要保持最高位即符号位不变,原数据的后11位要压缩成7位。这7位码由3位段落码和4位段内码组成。具体的压缩变换后的数据根据后11位数据大小决定。

表2 A律数据压缩表

语音压缩存储与回放实验报告王颖王燕

3

除对串行口数据实现压扩处理外,这套硬件在McBSP不使用时还可以当作一个特殊的处理单元对内部数据实现压扩处理,他有两种实现方法。

法一:当串行口的发送和接受部分都处于复位状态时,DRR1和DXR1内部通过压扩逻辑连接在一起,数据从DXR1写入并根据XCOMPAND处理,然后根据RCOMPAND再处理,在4个CPU时钟后从DRR1中读出数据。该处理比软件实现快,不利之处在于处理完后没有同步信息通知CPU和DMA。

法二:在数据环回模式下,McBSP也实现了一种内连。数据处理与第一种方法相同,但它可以提供中断信号(或同步事件)给CPU(或DMA)。这里数据处理的时间是根据串行口的比特律确定的。

另外,在通常情况下McBSP先传输信号的高位后传输低位,但是在字长为8比特的数据传输时,McBSP提供了比特倒序的功能,即可以先传输低位后传输高位。

在本实验中,我们通过软件编程来完成线性码转换成A律。

语音信号通常是小信号概率大,大信号出现的概率小,为提高小信号时的量化信躁比,压缩比特速率,可为非线性量化。语音压缩是把16位的数据比特转化为8位数据比特,从而到达语音压缩的目的。

在主程序中通过A/D抽样量化,可以得到16位的线性编码,再由编码表通过软件计算得到8位A律编码,其中最高位为符号位,第6位到第4位为段落码,低4位为段内码。将8位的压缩结果存储到系统RAM中进行缓存,根据抽样率、语音存储时间以及系统RAM的容量设置语音存储缓冲区的大小,待缓冲区存满后,将缓冲区内的数据进行解压缩,然后输出到SPEAKER接口输出端。

若使用A/D转换器,必须首先对A/D转换器进行初始化设置,即设置A/D转换器的工作模式、输入增益以及抽样频率等。

3.程序设计

(1)、程序流程

语音压缩存储与回放实验报告王颖王燕

4

语音压缩存储与回放实验报告王颖王燕

存储器的分配(5402.cmd)

MEMORY {

PAGE 0: VECS: origin = 0080h, length = 0080h /* Internal Program RAM */ PRAM: origin = 7600h, length = 8000h /* Internal Program RAM */

PAGE 1: SCRATCH: origin = 0060h, length = 0020h /* Scratch Pad Data RAM */ DMARAM: origin = 0C00h, length = 0300h /* DMA buffer */

DATA: origin = 1100h, length = 0080h /* Internal Data RAM */ STACK: origin = 1180h, length = 0560h /* Stack Memory Space */ INRAM: origin = 1900h, length = 0100h /* Internal Data RAM */ HPRAM0: origin = 1A00h, length = 0002h /* HPI memory accessible by Host and DSP */

HPRAM1: origin = 1A02h, length = 0280h /* HPI memory accessible by Host and DSP */

HPRAM2: origin = 1C82h, length = 0280h /* HPI memory accessible by Host and DSP */

EXRAM: origin = 1F10h, length = 9000h /* External Data RAM */

5

}

SECTIONS

{

.cinit > PRAM PAGE 0

.text > PRAM PAGE 0

.vectors > VECS PAGE 0

init_var > PRAM PAGE 0

detect > PRAM PAGE 0

vrcprg

matprg

.stack > STACK PAGE 1

.trap > SCRATCH PAGE 1

.const > EXRAM PAGE 1

.data > EXRAM PAGE 1

.bss > EXRAM PAGE 1

.cio > EXRAM PAGE 1

.switch > EXRAM PAGE 1

tables > EXRAM PAGE 1

var > EXRAM PAGE 1

svctab > EXRAM PAGE 1 /* SS_V LSP table */

vctab > EXRAM PAGE 1 /* V LSP table */

uvctab > EXRAM PAGE 1 /* UV LSP table */

cuvtab > EXRAM PAGE 1 /* Stochastic codebook */

cdbktab > EXRAM PAGE 1 /* various codebook tables*/

logtab > EXRAM PAGE 1 /* table for log2 */

powtab > EXRAM PAGE 1 /* table for pow2 */

hamtab > EXRAM PAGE 1 /* table for hamming */

lgwtab > EXRAM PAGE 1 /* table for lag window */

acostab > EXRAM PAGE 1 /* table for arccos */

sqrtab > EXRAM PAGE 1 /* table for square root */

acbtab > EXRAM PAGE 1 /* table for thresholds in acb */ pm03tab > EXRAM PAGE 1 /* table for x^(-0.3) computation */ costab > EXRAM PAGE 1 /* table for cosine */

V23 > INRAM PAGE 1

FSK > INRAM PAGE 1

6 > PRAM PAGE 0 > PRAM PAGE 0

hpibuff0 > HPRAM0 PAGE 1

hpibuff1 > HPRAM1 PAGE 1

hpibuff2 > HPRAM2 PAGE 1

dma_buff > DMARAM PAGE 1

}

/*主程序设计*/

/*语音采集及回放程序*/

/*用A律进行压缩及解压*/

/*采用AD50进行A/D,D/A转换 */ /*灯循环闪烁程序开始*/

/*L0:录音*/

/*L1:放音*/

#include <type.h> /* 头文件*/

#include <board.h>

#include <codec.h>

#include <mcbsp54.h>

/* 宏定义 */

#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ #define QUANT_MASK (0xf) /* Quantization field mask. */ #define NSEGS (8) /* Number of A-law segments. */

#define SEG_SHIFT (4) /* Left shift for segment number. */ #define SEG_MASK (0x70) /* Segment field mask. */

/* 函数声明 */

void delay(s16 period);

void led(s16 cnt);

void initcodec(void);

void flashenable(void);

unsigned char data2alaw(s16 pcm_val);

int alaw2data(unsigned char a_val);

static int search(int val,short *table,int size);

/* 全局变量 */

HANDLE hHandset;

s16 data;

s16 data1;

u16 i=0;

7

u16 temp1;

u16 j=0;

u16 k,l=0;

u8 temp2;

u16 buffer[20000];

static short seg_end[8]={0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF};

/* 主函数 */

void main()

{

if (brd_init(100))

return;

led(2); //闪灯两次

initcodec(); //初始化codec

flashenable(); //选择片外FLASH为片外存储器

/*

delay(100);

brd_led_toggle(BRD_LED0);

for(i=0x9000;i<0xefff;i++)

{

REG_WRITE(i,*(volatile u16*)DRR1_ADDR(HANDSET_CODEC));

delay(20);

}

brd_led_toggle(BRD_LED1);

delay(200);

for(i=0x9000;i<0xefff;i++)

{

*(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=REG_READ(i);

delay(20);

}

brd_led_toggle(BRD_LED2);

*/

while (1)

{

while (!MCBSP_RRDY(HANDSET_CODEC)) {}; //等待接收handset处的采样

brd_led_toggle(BRD_LED0);

data = *(volatile u16*)DRR1_ADDR(HANDSET_CODEC); //从handset处读取采样

temp1=data2alaw(data); //对采样进行a律压缩

8

/* 把低地址数据放在高八位 高地址数据放在低八位 */

i=i+1;

if(i%2==1)

{

buffer[j]=(temp1<<=8);

/*奇数数据左移8位 temp1=abcdefgh00000000

buffer[j]=temp1*/

}

else

{

buffer[j]=(buffer[j]|temp1);

/*偶数数据与temp1取或 组成新的数据

buffer[j]=abcdefghiabcdefghi*/

j++; //j加1

}

if(i>=40000)

{

i=0;

}

if(j>=20000)

{

j=0;

brd_led_disable(BRD_LED0);

brd_led_toggle(BRD_LED1);

//点亮二极管1 表示放音开始

/* 放音部分 */

for(k=0;k<40000;k++)

{

if(k%2==0)

{

temp2=(buffer[l]>>8)&0x0ff;

}

else

{

temp2=buffer[l]&0x0ff;

l++;

}

if(l>=20000)

9

l=0;

data1=alaw2data(temp2); // a律解压 while (!MCBSP_XRDY(HANDSET_CODEC)) {}; *(volatile u16*)DXR1_ADDR(HANDSET_CODEC) = data1; //将数据写入

D/A转换器

}

/* 放音结束 */

brd_led_toggle(BRD_LED0);

brd_led_toggle(BRD_LED1);

}

}

} //主程序结束

/* 子函数 */

/*******延时******/

void delay(s16 period)

{

int i, j;

for(i=0; i<period; i++)

{

for(j=0; j<period>>1; j++);

}

}

/*******闪灯******/

void led(s16 cnt)

{

while ( cnt-- )

{

brd_led_toggle(BRD_LED0); //切换LED指示灯0的显示状态

delay(1000);

10

}

} brd_led_toggle(BRD_LED1); delay(1000); brd_led_toggle(BRD_LED2); delay(1000);

/*****初始化codec**/

void initcodec(void)

{

/* Open Handset Codec 获取设置codec的句柄*/

hHandset = codec_open(HANDSET_CODEC); / Acquire handle to codec /* Set codec parameters */

codec_dac_mode(hHandset, CODEC_DAC_15BIT); // DAC in 15-bit mode codec_adc_mode(hHandset, CODEC_ADC_15BIT); // ADC in 15-bit mode

codec_ain_gain(hHandset, CODEC_AIN_6dB); // 6dB gain on analog input to ADC codec_aout_gain(hHandset, CODEC_AOUT_MINUS_6dB);

// -6dB gain on analog output from DAC codec_sample_rate(hHandset,SR_8000); // 8KHz sampling rate }

/*****设置flash****/

void flashenable(void)

{

CPLD_CTRL2_REG|=0x0010;

CPLD_DMCTRL_REG|=0x0040;

}

/*****a律压缩******/

unsigned char data2alaw(s16 pcm_val)

{

int mask; aval; int seg; unsigned char if (pcm_val >= 0) { mask = 0xD5; } else { } mask = 0x55; // 标记 bit = 0 pcm_val = -pcm_val; // 标记 (7th) bit = 1

11

// Convert the scaled magnitude to segment number.

seg = search(pcm_val, seg_end, 8);

// Combine the sign, segment, and quantization bits.

if (seg >= 8) // out of range, 返回最大数. return (0x7F ^ mask);

else

{

aval = seg << SEG_SHIFT;

if (seg < 2)

aval |= (pcm_val >> 1) & QUANT_MASK;

else

aval |= (pcm_val >>seg) & QUANT_MASK;

return (aval ^ mask);

}

}

/****alaw的子程序**/

static int search(int val,short *table,int size)

{

int i;

for (i = 0; i < size; i++)

{

if (val <= *table++)

return (i);

}

return (size);

}

/*****a律解压******/

int alaw2data(unsigned char a_val)

{

int t;

int seg;

a_val ^= 0x55;

t = (a_val & QUANT_MASK) << 4;

seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;

if(seg==0)

{

t += 8;

t=(t>>3);

12

} if((seg<4)&&(seg>0)) { t +=0x108; t=(t>>(4-seg)); } if(seg>3) { } t+=0x108; t=(t<<=(seg-4));

return ((a_val & SIGN_BIT) ? t : -t);

}

/* 结束 */

四.操作过程

1.将工程文件夹放入C盘要求目录下。

2. 打开CCS,Project → open,打开工程文件。

3.进行编译,连接。

4.根据错误提示,对build option进行正确的设置,修改头文件路径。

5.再编译,连接,显示没有错误。

6.load program---run,此时三盏灯循环亮,之后程序开始,第一盏灯亮开始录音,一段时间后第二盏灯亮开始放音,然后又开始录音。依次循环。

五.调试过程与运行结果

1.观察数据结果

View——watch window

我们输入buffer,显示此数组的值,如图D所示。

2.观察数据图形

View——Graph——Time Frequency

可以加入断点,然后按Animate 动态显示。

分别观察语音输入(存放在变量data中)波形,压缩后波形(temp1),解压后输出波形(data1),图形分别为A,B,C。

3.观察存储器中数据

View——Memory

经过多次调试,使录音时间在保持音质的前提下达到5-6秒。

13

A.输入波形

语音压缩存储与回放实验报告王颖王燕

(data)

B.压缩后波形

语音压缩存储与回放实验报告王颖王燕

(temp1)

C.解压缩后输出波形(data1)

14

D.watch window中的值

语音压缩存储与回放实验报告王颖王燕

语音压缩存储与回放实验报告王颖王燕

五.实验总结

经历了这次实验,我想我们充分认识到了压力带给人的巨大动力。确定做语音压缩,存

语音压缩存储与回放实验报告王颖王燕

15

储与回放实验后,查了大量A律,u律压缩方法的资料,并学习了CCS环境下的操作、调试与运行。由于之前对DSP很不了解,这方面学习我们去实验室操作了不少时间,终于熟悉了它的操作步骤与简单调试方法。

然后具体针对语音压缩回放实验,我们经历了比较大的挫折。首先借了板子后怎么都不能和计算机连接,换了好几台电脑都不行,换了板子后终于可以了,但问题是语音不能录入,很疑惑,编译下载都没问题,最后发现是耳机的问题。终于能录入后,我们很激动,接下来就是观察波形与数据了。分别看了输入与经压缩后波形,发现没什么区别,而且有连续整段波形全在横轴上方或下方,经分析后我们修改了显示点数,将256改为128,则波形变疏,同时也能看出压缩后的变化,只是不太明显,说明A律压缩不会有很大失真,效果较好。对比输入输出波形,发现很相近,达到了实验要求。至于为何有连续整段波形全在横轴上方或下方,我想是因为没有信号输入导致,但具体还有待自己去查找资料。

在调试过程中我们还学习了断点的设置与利用,还有在watch window 中对输入变量data 设置不同的值可分析波形的变化情况,同时还可查看buffer 中存储内容。

我们自己试验的扩展部分是将录音与放音时间调长,经改大buffer容量,并相应加大i, j 的循环次数则可。

由于时间比较紧,我们只是查了u律压缩的实现方法,没有将其与A律压缩做具体比较,觉得比较遗憾。我觉得这是挺有意思的实验,让我自己去摸索验证理论性的东西。

王颖 通信0607 06282022

通过这次的DSP实验,让我充分认识到了我的不足。我虽然学习过C语言的编程,但一旦将它应用到实际的比较专业的问题上,我所学的知识就变得完全不够用了,为了这次实验我和我的搭档查询了大量的资料,无论是C语言方面的还是压缩算法方面的都让我们花费了很多时间,查询到了需要的资料我们又对它们进行了整理,提取出我们需要的a律压缩和μ律压缩的算法和原理,并且努力去理解其中的知识,使其能为我们所用,尽管如此我们仍然没能成功的编出属于我们自己的程序,因此我们找到了一份编好的程序,用我们已经理解的知识去分析它,理解这份程序的原理,并根据我们的实际对它进行一些修改,从而我们才得出我们现在的程序。虽然程序编写成功了但我们在调试上又遇到了很多的问题,比如在CCS环境下我们要如何观察波形,波形有代表什么等等,为此我们又不断的翻阅课件和资料,才最终解决了所有的问题,我们的实验才算基本完成了。

整个实验过程中,我在不断的查阅资料和开动脑筋过程中,锻炼了我的资料采集能力,也锻炼了我的分析整理能力,为以后作毕业设计打下了基础;同样在实验过程中我遇到很多困难,而这些困难则锻炼了我的耐心和分析解决问题的能力;通过编程锻炼了我的编程能力,使我对C语言,汇编语言和MATLAB语言更加熟悉,让我能更好的运用它们;而且两人一组的实验,也锻炼了我们的团结协作能力,为将来走入社会能更好的工作打下了基础。

总之通过这次的实验,让我认识到了自己的不足,同时又通过这次的实验让我们学到了让我们受用一生的知识。

王燕 自动化0601 06212016

六.参考资料:[1] 高海林 钱满义 DSP技术及其应用 自编讲义,2005

[2] 谭浩强 C程序设计(第二版)清华大学出版社,2003

[3]李颖 李文海 现代通信技术 人民邮电出版社 2002.3

[4]赵勇、甘泉 DSP应用系统设计 电子工业出版社 2002.10

16

相关推荐