Audio-音频降噪、回声消除处理

        对音频数据进行处理时经常会对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 %dn", 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 conversionn");
            printf("start channel ch3/4, do the conversionn");
            pcm_mmap_read(pcm, buffer, 4);
        } else {
            LOG("start channel ch1/2 n");
        }
        free(buffer);
    }

    LOG("pcm_open done pcm->fd = %dn", 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声道里面说话的声音。

 

总结

        回声消除和噪声抑制都是音频处理中必须要进行的一些过程,这篇只是对这些处理之前的音频数据进行转化的内容进行一下说明,回声消除与噪声抑制的具体处理涉及到算法的优化与解决,很难搞!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>