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]);
    }
}

以上,作为记录和技术储备。

 

你可能感兴趣的:(Audio)