现有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]);
}
}
以上,作为记录和技术储备。