Android手机上Audio DSP频率低 memory小的应对措施

我在前面的文章(Android智能手机上的音频浅析)中说过Android手机上有一块专门用于音频处理的DSP,它的特色是频率低(通常几百MHZ)、内部memory小(一般不超过100k word)。要想让Audio DSP上放下更多的内容以及能流畅的运行,要有一些应对措施。今天就聊聊这些措施。html

 

1,频率低的应对措施算法

因为DSP的频率低,要想软件能流畅的运行,就得把运行时的load降下来。主要的措施有两种,定点化和load优化。先看定点化。编程

 

DSP有定点DSP和浮点DSP之分。通常来讲,定点DSP具备速度快,功耗低,价格便宜的特色;而浮点DSP则计算精确,动态范围大,速度快,易于编程,功耗大,价格高。音频处理用的DSP一般都是定点DSP。定点DSP,处理定点数据会至关快,可是处理浮点数据就会很是慢。那在定点DSP上涉及到浮点运算怎么办呢?解决方法是浮点运算定点化来节约处理时间,即用定点数表示浮点数。定点数中最高位表示符号位,符号位右边n位表示整数,剩下的表示小数。这种表示方法叫Q格式。数组

 

Q格式表示为:Qm.n,表示数据用m比特表示整数部分,n比特表示小数部分,共须要m+n+1位来表示这个数据,多余的一位用做符合位(不表示出来)。例如Q15表示小数部分有15位,一个short型数据,占2个字节,最高位是符号位,后面15位是小数位,表示的范围是:-1<X<0.9999695 。浮点数据转化为Q15,将数据乘以2^15;Q15数据转化为浮点数据,将数据除以2^15。例如假设数据存储空间为2个字节,0.333×2^15=10911=0x2A9F,0.333的全部运算就能够用0x2A9F表示,同理10911×2^(-15)=0.332977294921875,能够看出浮点数据经过Q格式转化后是有偏差的。函数

再看看Q格式的加减乘除基本运算。加减法时须转换成相同的Q格式才能加减。不一样Q格式的数据相乘,至关于Q值相加,要右移n位获得正确的值。不一样Q格式的数据相除,至关于Q值相减,要左移n位获得正确的值。这里举一个乘的例子:两个小数相乘,0.333*0.414=0.137862优化

0.333*2^15=10911=0x2A9F,0.414*2^15=13565=0x34FDspa

short a = 0x2A9F;code

short b = 0x34FD;htm

short c = a * b >> 15;  // 两个Q15格式的数据相乘后为Q30格式数据,所以为了获得Q15的数据结果须要右移15位blog

这样c的结果是0x11A4=0001000110100100,这个数据一样是Q15格式的,它的小数点假设在第15位左边,即为0.001000110100100=0.1378173828125...和实际结果0.137862差距不大。或者0x11A4 / 2^15 = 0.1378173828125

其余的基本运算就不举例了,网上讲Q格式的有一些文章,感兴趣本身去看。

实际应用中,浮点运算大都时候都是既有整数部分,也有小数部分的。因此要选择一个适当的定标格式才能更好的处理运算。通常用以下两种方法:一是使用适中的定标,既能够表示必定的整数复位也能够表示小数复位,如对于2812的32位系统,使用Q15格式,可表示-65536.0~65535.999969482区间内的数据。二是所有采用小数,这样由于小数之间相乘永远是小数,永远不会溢出。取一个极限最大值(最好使用2的n次幂),转换成x/Max的小数(若是Max是取的2的 n次幂,就可使用移位代替除法)。刚开始用Q格式时会很别扭,不习惯,用多了就慢慢习惯了。

 

为了降load,咱们在软件开发过程当中要作到如下两点:一是选择算法实现时必定要用定点实现。Audio DSP上会运行好多音频处理算法,好比各类codec,这些codec的制定者通常会提供两套reference code,一套定点实现的,一套浮点实现的,咱们在选择时必定要选用定点实现的。对于应用在ARM上的音频处理算法,一样是推荐用定点实现的算法,虽然ARM频率高。在ARM上仍是要优化算法把load降到尽可能低。二是在咱们本身的代码中如遇到要作浮点运算(好比算百分比),要用Q格式定点化去算,而不是直接用浮点数去运算。

 

再来看load优化。我在前面的文章(音频的编解码及其优化方法和经验)中load优化的一些通用方法,在DSP上也适用。不过因为DSP频率低,且DSP上运行的音频处理算法多,有些算法又比较耗load(好比AEC),要想让音频软件流畅的运行,复杂的算法都是要作汇编优化的。作这些不只专业并且耗时,load优化没有最低只有更低。

 

2,memory低的应对措施

DSP的内部memory分两种,DTCM(Data Tightly Coupled Memory, 数据紧密耦合存储器)和PTCM(Program Tightly Coupled Memory, 程序紧密耦合存储器)。DTCM用于存data,PTCM用于存code。同时还有外部memory(DDR),它也可存data和code。data和code尽可能放内部,由于这样速度快效率高,不到万不得已才将它们放在外部memory上。即便放在外部的也是一些低频访问的data和code,如初始化函数等。今天咱们主要讲的是应对DTCM(data memory)小的措施。DTCM主要分如下几个区域:const区、data区、bss区、overlay区。const区顾名思义就是放一些常量的,data区是放已初始化的全局变量和静态变量,bss区是放未初始化的全局变量和静态变量,overlay区主要是根据场景的互斥作一些memory的复用,这是应对memory小的主要措施。咱们先看overlay机制。

 

Overlay机制是指不会同时发生的场景下使用的memory能够复用,在音频上主要有两种状况。一是music使用的memory能够和voice使用的memory复用,由于音乐播放和打电话不可能同时发生。一般是音乐播放时来电话,音乐播放就暂停,把音乐播放的context以及还在buffer中未播放的数据拷贝到外部memory上,把music使用的memory让给voice用。打电话结束后再把放在外部memory上的音乐相关的context以及未播放的数据拷进内部memory原先的位置上,从而继续音乐的播放。二是各类codec使用的memory的复用,由于同时只有一种codec在使用。音乐的decoder有MP三、AAC,播放音乐时只可能有一种decoder在用。Voice的codec有AMR-NB、AMR-WB、EVS,打电话时只可能有一种codec在用。它与第一种的区别是不须要保存上下文。这样能够画出DTCM的分布图,以下图:

 

上图中memory地址是由低向高增加,分别是const区、data区、bss区、overlay区。在overlay区music和voice有相同的起始地址,在music中decoder MP3和AAC又有相同的起始地址,在voice中codec AMR-NB、AMR-WB和EVS又有相同的起始地址。

 

对于PTCM,一样能够用overlay机制。不过除非一些代码重写,通常很难省code size了。 

 

除了overlay机制,其余的就要一点一点的抠来省memory了,主要有如下几点:

1) 定义数据类型时能用short的就不要用int

2)在overlay区域,buffer的大小都是指定的。指定时要正确算出大小值,不要指定大了,指定大了就浪费了。

3)在data区或者bss区的buffer要看是否是分大了,好比有的buffer分三块就够了,也就不必分四块了,分四块一是浪费了buffer,二是有些场景下增长了时延。

4)  DSP上每一个thread/task的栈的大小都是指定的。为了省memory,栈的大小不可能很大,通常不超过1k word。这就要求写代码时不能有大的局部变量数组等,遇到时就要经过一些技巧解决。如一个要把双声道的数据从interleave变成non-interleave的函数,写成了以下实现,避免了大的局部变量数组。一般的作法是用一个大的局部变量数组先存右声道数据,最后再一块儿拷到指定位置上。

void interleave_to_noninterleave(int16_t *buf, int32_t frame_cnt)

{

    int i,j;

    short temp;

    for(i = 1; i < frame_cnt; i++) {

        temp = buf[2*i];

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

            buf[2*i - j] = buf[2*i - j -1];

        buf[i] = temp;

    }

}

5)代码编好后会生成一个各buffer起始地址和大小的文件。关注那些size较大的buffer,分析有没有减少的可能。

 

整体而言,DSP因为频率低和memory小的限制,在上面写代码比在ARM上要求高些,花的时间长些。长时间在ARM上写代码,转到DSP上会有些不习惯,有个适应过程。

相关文章
相关标签/搜索