音频处理中交织与非交织数据转换的几种方法

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上,但是不如第一种通俗易懂。到底用哪一种,就取决于硬件资源了。

相关推荐