現有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]);
}
}
以上,作爲記錄和技術儲備。