dugujiujian 2020-05-29
当音频的声道数多于一个时,音频数据的存放有两种格式,即交织的(interleave)和非交织的(non-interleave)。以最常见的双声道为例,交织和非交织的音频数据存放如下图:
上图中L表示左声道数据,R表示右声道数据,整数1、2等表示第几个采样点,这样L1就表示左声道的第一个采样点数据。从上图看出,所谓交织的是指一个采样点的两个声道的数据依次放在一起,非交织的是指先放左声道的所有采样点的数据,再放右声道的所有采样点的数据。
在音频处理时,有时需要交织的数据,而有时又需要非交织的数据,这样就存在两种数据格式之间的转换。本文就讲讲这两种数据格式转换的两种方法,第一种是常规的简单的方法,第二种是巧妙的省memory的方法。
1, 常规方法
1.1 interleave 转 non-interleave
先动态申请一块memory(大小等于采样点数),把右声道的数据放在这块动态申请的memory上,同时把左声道的数据放在原buffer的前一半。然后再把动态memory上的右声道的数据放到原buffer的后一半,这样就完成了interleave到non-interleave的转换。C语言的实现代码如下:
int interleave2noninterleave(short *buf, int count) { int i; short *temp; if(buf == NULL) { printf("input point buf is NULL \n"); return -1; } temp = (short *)malloc(sizeof(short) * count); if(temp == NULL) { printf("memory alloc failed \n"); return -1; } for(i = 0; i < count; i++) { temp[i] = buf[2 * i + 1]; buf[i] = buf[2 * i]; } for(i = 0; i < count; i++) { buf[count + i] = temp[i]; } if(temp != NULL) { free(temp); temp = NULL; } return 0; }
1.2 non-interleave 转interleave
同样先动态申请一块memory(大小等于采样点数),把原buffer前一半的(即左声道的)数据放在这块动态申请的memory上。然后再把动态memory上的左声道的数据放到原buffer的奇数位置上,把原buffer后一半的(即右声道的)数据放到原buffer的偶数位置上,这样就完成了non-interleave到interleave的转换。C语言的实现代码如下:
int noninterleave2interleave(short *buf, int count) { int i; short *temp; if(buf == NULL) { printf("input point buf is NULL \n"); return -1; } temp = (short *)malloc(sizeof(short) * count); if(temp == NULL) { printf("memory alloc failed \n"); return -1; } for(i = 0; i < count; i++) { temp[i] = buf[i]; } for(i = 0; i < count; i++) { buf[2 * i] = temp[i]; buf[2 * i + 1] = buf[count + i]; } if(temp != NULL) { free(temp); temp = NULL; } return 0; }
由于常规方法比较简单,这里就不详述了。
2, 省memory的巧妙方法
2.1 interleave 转 non-interleave
这里为了讲清楚,左右声道各有四个采样点,更多点也是一样处理。处理过程如下图:
第一步,将L2放在临时变量里,R1向后移一位置,再将临时变量的值(即L2)放在原buffer第二位置上;第二步,将L3放在临时变量里,R1和R2向后移一位置,再将临时变量的值(即L3)放在原buffer第三位置上;将L4放在临时变量里,R1、R2和R3向后移一位置,再将临时变量的值(即L4)放在原buffer第四位置上。这样就完成了interleave到non-interleave的转换。C语言的实现代码如下:
int interleave2noninterleave(short *buf, int count) { int i,j; short temp; if(buf == NULL) { printf("input point buf is NULL \n"); return -1; } for(i = 1; i < count; i++) { temp = buf[2*i]; for(j = 0; j < i; j++) buf[2*i - j] = buf[2*i - j -1]; buf[i] = temp; } return 0; }
2.2 non-interleave 转interleave
这里为了讲清楚,同样左右声道各有四个采样点,更多点也是一样处理。处理过程如下图:
第一步,将R1放在临时变量里,L2、L3和L4向后移一位置,再将临时变量的值(即R1)放在原buffer第二位置上;第二步,将R2放在临时变量里,L3和L4向后移一位置,再将临时变量的值(即R2)放在原buffer第四位置上;第三步,将R3放在临时变量里,L4向后移一位置,再将临时变量的值(即R3)放在原buffer第六位置上。这样就完成了non-interleave到interleave的转换。C语言的实现代码如下:
int noninterleave2interleave(short *buf, int count) { int i,j; short temp; if(buf == NULL) { printf("input point buf is NULL \n"); return -1; } for(i = 0; i < count; i++) { temp = buf[count + i]; for(j = 0; j < count - 1 - i; j++) buf[count + i - j] = buf[count + i - j -1]; buf[2 * i + 1] = temp; } return 0; }
第二种方法相对第一种少用了一块memory,更简洁,尤其适用于memory资源紧张的硬件环境里,比如DSP上,但是不如第一种通俗易懂。到底用哪一种,就取决于硬件资源了。