PCM 單雙聲道轉換

現有PCM數據,要進行如下轉換,

對於16位採樣的PCM來說,

單聲道存儲方式很好理解,一段連續內存,一個個int16_t排排站。以A表示一個int16_t,內存排列如下:

AAAAAAAAAAAAAAA

雙聲道的話,L表示左聲道,R表示右聲道,最常見的形式如下:

LRLRLRLRLRLRLRLR

也有LLLLLLLLRRRRRRRR這種排列的,比較少見,這裏不做分析。

先定義一個宏作爲通用代碼:

#define COMBINE(l,r) (((int32_t)(l) + (r)) >> 1)

注意上述代碼,考慮到兩個int16_t相加容易造成數據溢出,所以先做類型轉換。

1. 假設爲44100Hz,16位採樣,雙聲道;轉換爲44100Hz, 16位採樣,單聲道:

void stereo_2_mono(const int16_t *src_audio,
        int sapmples_per_channel, int16_t *dst_audio) {
    for (int i = 0; i < sapmples_per_channel; i++) {
        dst_audio[i] = COMBINE(src_audio[2*i], src_audio[2*i+1]);
    }
}

2. 假設爲44100Hz,16位採樣,單聲道;轉換爲44100Hz, 16位採樣,雙聲道:

void mono_2_stereo(const int16_t *src_audio,
            int sapmples_per_channel, int16_t *dst_audio) {
    for (int i = 0; i < sapmples_per_channel; i++) {
        dst_audio[2*i] = dst_audio[2*i+1] = src_audio[i]);
    }
}

3. 將兩個單聲道合併位一個雙聲道,均爲44100Hz,16位採樣:

void combine_2_stereo(const int16_t *main_audio,
            const int16_t *extn_audio,
            int sapmples_per_channel, int16_t *dst_audio) {
    for (int i = 0; i < sapmples_per_channel; i++) {
        // left channel
        dst_audio[2*i] = main_audio[i];
        // right channel
        dst_audio[2*i+1] = extn_audio[i];
    }
}

4. 將兩個雙聲道合併位一個雙聲道,單左右聲道分開,即左聲道爲聲音A,右聲道爲聲音B,均爲44100Hz,16位採樣:

合併調用下1和3的兩個函數即可,若不想有過多的內存拷貝,可以合併如下:

void combine_2_stereo2(const int16_t *main_audio,
            const int16_t *extn_audio,
            int sapmples_per_channel, int16_t *dst_audio) {
    for (int i = 0; i < sapmples_per_channel; i++) {
        // left channel
        dst_audio[2*i] = COMBINE(main_audio[2*i], main_audio[2*i+1]);
        // right channel
        dst_audio[2*i+1] = COMBINE(extn_audio[2*i], extn_audio[2*i+1]);
    }
}

以上,作爲記錄和技術儲備。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章