54

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

 5 years ago
source link: http://www.cocoachina.com/ios/20180824/24687.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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地址开始且含有'\0'结束符的字符串复制到以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\n ", (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\n");
            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\n");
        return -1;
    }
    status = WebRtcNs_set_policy(nsHandle, level);
    if (status != 0) {
        printf("WebRtcNs_set_policy fail\n");
        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代码

作者:李境沛
链接:https://www.jianshu.com/p/c8d79056c6fc


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK