對音頻資料進行處理時經常會對mic陣列的選擇有很多特殊要求,當原始錄取的音頻陣列排布有問題時,會進行一些軟體的處理,使陣列排布達到一定的要求,
1.回聲消除對麥克陣列的特殊要求

2.原始音頻MIC陣列排布處理
對于4ch音頻資料而言,麥克陣列排列要求為mic1、mic2、ref1、ref2,但是通過tinycap采集的原始音頻資料的陣列排布為ref1、null、mic1、mic2,倆路mic分別對應左右mic的音頻攝入,需要對mic陣列進行一定處理,

check相關原始音頻pcm檔案,ref通道攝入的是喇叭對應的音頻,收集到的是設備播放音樂的聲音,同時mic通道也會攝入設備播放的音樂聲音,需要通過回聲消除處理對設備音進行一定的處理,
針對麥克陣列排布不符合規定的代碼端處理,調整排列架構符合要求,
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config)
{
struct pcm *pcm;
struct snd_pcm_info info;
struct snd_pcm_hw_params params;
struct snd_pcm_sw_params sparams;
char fn[256];
int rc;
LOG("pcm_open card %d device %d channel %d period_size %d period_count %d format %d\n", card, device ,config->channels, config->period_size, config->period_count, config->format);
...
...
if(card == 0 && device == 2 && config->rate == 64000){
char *buffer;
unsigned int ch1_first = 0, ch3_first = 0, i = 0;
buffer = malloc(sizeof(char)*8);
for(i = 0; i < 10 && ch1_first < 2 && ch3_first < 2; i++){
pcm_mmap_read(pcm, buffer, 8);
/* LOG("buffer[2] = 0x%x. buffer[3] = 0x%x buffer[6] = 0x%x. buffer[7] = 0x%x",
*(buffer+2), *(buffer+i+3), *(buffer+6), *(buffer+7)); */
if((*(buffer+2) == 0x00)&&(*(buffer+3) == 0x00))
ch3_first++;
if((*(buffer+6) == 0x00)&&(*(buffer+7) == 0x00))
ch1_first++;
}
if(ch3_first > ch1_first){
LOG("start channel ch3/4, do the conversion\n");
printf("start channel ch3/4, do the conversion\n");
pcm_mmap_read(pcm, buffer, 4);
} else {
LOG("start channel ch1/2 \n");
}
free(buffer);
}
LOG("pcm_open done pcm->fd = %d\n", pcm->fd);
return pcm;
}
相關代碼執行log


調整后的音頻pcm檔案

3.音頻資料采樣精度、回采通道復用處理
原始錄取出來的音頻資料采樣精度為16bit,采樣頻率為16khz,且ref2因為硬體設計為null,為滿足麥克陣列的要求需對這樣的音頻資料進行應用層的處理,采樣精度:16bit -> 32bit,第二路回采信號復用第一路回采信號,
處理代碼如下:
//2mic: 4c 16k 16bit -> 4c 16k 32bit(copy 3ch -> 4ch)
public static byte[] addCnFor2MicN4(byte[] data) {
byte[] cpy=new byte[data.length*2];
int j=0;
//mic1 mic2 ref ref
while(j<data.length/8) {
cpy[16*j]=00;
cpy[16*j+1]= 00;
cpy[16 * j + 2] = data[8 * j +0];
cpy[16* j + 3] = data[8 * j +1];
cpy[16*j+4]=00;
cpy[16*j+5]= 00;
cpy[16 * j + 6] = data[8 * j +2];
cpy[16* j + 7] = data[8 * j +3];
cpy[16*j+8]=00;
cpy[16*j+9]= 00;
cpy[16 * j + 10] = data[8 * j +4];
cpy[16* j + 11] = data[8 * j +5];
cpy[16*j+12]=00;
cpy[16*j+13]= 00;
cpy[16 * j + 14] = data[8 * j +4];
cpy[16* j + 15] = data[8 * j +5];
j++;
}
return cpy;
}

以下是一些專案中用到的對音頻資料進行處理的方法:
//6mic 8ch 32bits
private byte[] addCnForMutiMic(byte[] data) {
int datasize=data.length;
byte[] newdata=new byte[datasize*2];//double to 16bit -> 32bit
int j=0;
int k=0;
int index= 0;
int step = datasize/2;
while(j<step) {
for (int i=1; i<9;i++) {
k = 4*j;
index= 2*j;
newdata[k]=00;
newdata[k+1]=00;
newdata[k+2]=data[index];
newdata[k+3]=data[index+1];
j++;
}
}
data = null;
return newdata;
}
//4mic 8ch->6ch
private byte[] adapeter4Mic(byte[] data) {
// int size = ((data.length/8)*2)*6;
int size = (data.length/8)*6;
byte[] cpy=new byte[size];
int j=0;
while(j<data.length/16) {
cpy[12 * j + 0] = data[16 * j +0];
cpy[12* j + 1] = data[16 * j +1];
cpy[12 * j + 2] = data[16 * j +2];
cpy[12* j + 3] = data[16 * j +3];
cpy[12 * j + 4] = data[16 * j +4];
cpy[12* j + 5] = data[16 * j +5];
cpy[12 * j + 6] = data[16 * j +6];
cpy[12* j + 7] = data[16 * j +7];
cpy[12 * j + 8] = data[16 * j +12];
cpy[12* j + 9] = data[16 * j +13];
cpy[12 * j + 10] = data[16 * j +14];
cpy[12* j + 11] = data[16 * j +15];
j++;
}
return cpy;
}
//4mic:8ch -> 6ch
private byte[] adapeter4Mic32bit(byte[] data) {
// int size = ((data.length/8)*2)*6;
int size = (data.length/8)*6*2;
byte[] cpy=new byte[size];
int j=0;
while(j<data.length/16) {
cpy[24 * j + 0] = 0x00;
cpy[24* j + 1] = 0x01;
cpy[24 * j + 2] = data[16 * j +0];
cpy[24* j + 3] = data[16 * j +1];
cpy[24 * j + 4] = 0x00;
cpy[24* j + 5] = 0x02;
cpy[24 * j + 6] = data[16 * j +2];
cpy[24* j + 7] = data[16 * j +3];
cpy[24 * j + 8] = 0x00;
cpy[24* j + 9] = 0x03;
cpy[24 * j + 10] = data[16 * j +4];
cpy[24* j + 11] = data[16 * j +5];
cpy[24 * j + 12] = 0x00;
cpy[24* j + 13] = 0x04;
cpy[24 * j + 14] = data[16 * j +6];
cpy[24* j + 15] = data[16 * j +7];
cpy[24 * j + 16] = 0x00;
cpy[24* j + 17] = 0x05;
cpy[24 * j + 18] = data[16 * j +12];
cpy[24* j + 19] = data[16 * j +13];
cpy[24 * j + 20] = 0x00;
cpy[24* j + 21] = 0x06;
cpy[24 * j + 22] = data[16 * j +14];
cpy[24* j + 23] = data[16 * j +15];
j++;
}
return cpy;
}
//6mic 16bit-> 2mic 32bit
private byte[] addCnFor2Mic(byte[] data) {
byte[] cpy=new byte[data.length];
int j=0;
//mic1 mic2 ref ref
while(j<data.length/16) {
cpy[16 * j] = 00;
cpy[16 * j + 1] = (byte) 1;
cpy[16 * j + 2] = data[16 * j + 0];
cpy[16 * j + 3] = data[16 * j + 1];
cpy[16 * j + 4] = 00;
cpy[16 * j + 5] = (byte) 2;
cpy[16 * j + 6] = data[16 * j + 2];
cpy[16 * j + 7] = data[16 * j + 3];
cpy[16 * j + 8] = 00;
cpy[16 * j + 9] = (byte) 3;
cpy[16 * j + 10] = data[16 * j + 12];
cpy[16 * j + 11] = data[16 * j + 13];
cpy[16 * j + 12] = 00;
cpy[16 * j + 13] = (byte) 4;
cpy[16 * j + 14] = data[16 * j + 14];
cpy[16 * j + 15] = data[16 * j + 15];
j++;
}
return cpy;
}
4.回聲消除效果
經過回聲消除之后輸出的音頻資料是16k、16bit、單聲道資料,經過與之前的pcm檔案對比可以看出資料的音樂聲音被消除,基本只留下了之前mic聲道里面說話的聲音,

總結
回聲消除和噪聲抑制都是音頻處理中必須要進行的一些程序,這篇只是對這些處理之前的音頻資料進行轉化的內容進行一下說明,回聲消除與噪聲抑制的具體處理涉及到演算法的優化與解決,很難搞!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/382027.html
標籤:其他
