• 基于WebRTC实现iOS端音频降噪功能


    https://www.jianshu.com/p/c8d79056c6fc?tdsourcetag=s_pcqq_aiomsg

    WebRTC下载要很麻烦,并且学会使用一个库也要花费不少时间,另一方面导入一个第三方库app的体积会加大,因此用了一位大神从WebRTC提出来的模块,但因为是c的所以还要转一次。

    WebRTC降噪有两部分代码,一套是定点算法(noise_suppression_x.h),一套是浮点算法(noise_suppression.h)。相对来说浮点算法精度更高,但是耗系统资源更多,特别是浮点计算能力较弱的低端ARM CPU上。

    音频处理的时候webrtc一次仅能处理10ms数据,小于10ms的数据不要传入,如果是传入小于10ms的数据最后传入也是按照10ms的数据传出,此时会出现问题。另外支持采样率也只有8K,16K,32K三种,不论是降噪模块,或者是回声消除增益等等均是如此。对于8000采样率,16bit的音频数据,10ms的时间采样点就是80个,一个采样点16bit也就是两个字节,那么需要传入WebRtcNsx_Process的数据就是160字节。对于8000和16000采样率的音频数据在使用时可以不管高频部分,只需要传入低频数据即可,但是对于32K采样率的数据就必须通过滤波接口将数据分为高频和低频传入,传入降噪后再组合成音频数据。大于32K的音频文件就必须要通过重采样接口降频到对应的采样率再处理。

    部分代码

    - (void)viewDidLoad {
        
        [super viewDidLoad];
        
        NSString *inpath  = @"/Users/apple/Desktop/a.wav";
        NSString *outpath = @"/Users/apple/Desktop/b.wav";
        
        const char *in_file  = [inpath  UTF8String];
        const char *out_file = [outpath UTF8String];
        
        char in_f[1024];
        //把从src地址开始且含有''结束符的字符串复制到以dest开始的地址空间,返回值的类型为char*
        strcpy(in_f,in_file);
        
        char out_f[1024];
        strcpy(out_f,out_file);
        
        [self noise_suppression:in_f and:out_f];
    }
    
    
    - (void)noise_suppression:(char *)in_file and:(char *)out_file {
        //音频采样率
        uint32_t sampleRate = 0;
        //总音频采样数
        uint64_t inSampleCount = 0;
        
        int16_t *inBuffer = [self wavRead_int16:in_file :&sampleRate :&inSampleCount];
        
        //如果加载成功
        if (inBuffer != nullptr) {
            double startTime = now();
            [self nsProcess:inBuffer :sampleRate :(int)inSampleCount :kModerate];
            double time_interval = calcElapsed(startTime, now());
            printf("time interval: %d ms
     ", (int) (time_interval * 1000));
            [self wavWrite_int16:out_file :inBuffer :sampleRate :inSampleCount];
            free(inBuffer);
        }
    }
    
    //写wav文件
    - (void)wavWrite_int16:(char *)filename :(int16_t *)buffer :(size_t)sampleRate :(size_t)totalSampleCount {
        drwav_data_format format = {};
        format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
        format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
        format.channels = 1;
        format.sampleRate = (drwav_uint32)sampleRate;
        format.bitsPerSample = 16;
        drwav *pWav = drwav_open_file_write(filename, &format);
        if (pWav) {
            drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer);
            drwav_uninit(pWav);
            if (samplesWritten != totalSampleCount) {
                fprintf(stderr, "ERROR
    ");
                exit(1);
            }
        }
    }
    
    //读取wav文件
    - (int16_t *)wavRead_int16:(char *)filename :(uint32_t *)sampleRate :(uint64_t *)totalSampleCount{
        unsigned int channels;
        int16_t *buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
        if (buffer == nullptr) {
            printf("ERROR.");
        }
        return buffer;
    }
    
    -(int)nsProcess:(int16_t *)buffer :(uint32_t)sampleRate :(int)samplesCount :(enum nsLevel)level {
        if (buffer == nullptr) return -1;
        if (samplesCount == 0) return -1;
        size_t samples = MIN(160, sampleRate / 100);
        if (samples == 0) return -1;
        uint32_t num_bands = 1;
        int16_t *input = buffer;
        size_t nTotal = (samplesCount / samples);
        NsHandle *nsHandle = WebRtcNs_Create();
        int status = WebRtcNs_Init(nsHandle, sampleRate);
        if (status != 0) {
            printf("WebRtcNs_Init fail
    ");
            return -1;
        }
        status = WebRtcNs_set_policy(nsHandle, level);
        if (status != 0) {
            printf("WebRtcNs_set_policy fail
    ");
            return -1;
        }
        for (int i = 0; i < nTotal; i++) {
            int16_t *nsIn[1] = {input};   //ns input[band][data]
            int16_t *nsOut[1] = {input};  //ns output[band][data]
            WebRtcNs_Analyze(nsHandle, nsIn[0]);
            WebRtcNs_Process(nsHandle, (const int16_t *const *) nsIn, num_bands, nsOut);
            input += samples;
        }
        WebRtcNs_Free(nsHandle);
        
        return 1;
    }
    
    

    oc代码

    参考:单独编译和使用webrtc音频降噪模块
    参考:音频降噪算法

     
     
    22人点赞
     
    iOS
     
     


    作者:长空幻月
    链接:https://www.jianshu.com/p/c8d79056c6fc
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    使用Angular CLI生成 Angular 5项目
    asp.net core 2.0 web api + Identity Server 4 + angular 5 可运行前后台源码
    依赖反转原则DIP 与使用了Repository模式的asp.net core项目结构
    Git基本命令 -- 别名 + 忽略 + 推送
    Git基本命令 -- 历史
    多线程,论多核时代爱恨情仇
    凛冬将至,用几款特效暖暖身
    HTML5游戏开发引擎,初识CreateJS
    详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)
    详解设计模式六大原则
  • 原文地址:https://www.cnblogs.com/itlover2013/p/14414249.html
Copyright © 2020-2023  润新知