对音频数据进行处理时经常会对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文件
文章来源:https://www.toymoban.com/news/detail-403788.html
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.toymoban.com/news/detail-403788.html
到了这里,关于Audio-音频降噪、回声消除处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!