音頻處理中交織與非交織數據轉換的幾種方法


當音頻的聲道數多於一個時,音頻數據的存放有兩種格式,即交織的(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上,但是不如第一種通俗易懂。到底用哪一種,就取決於硬件資源了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM