基于WebRTC實(shí)現(xiàn)iOS端音頻降噪功能

WebRTC下載要很麻煩,并且學(xué)會(huì)使用一個(gè)庫(kù)也要花費(fèi)不少時(shí)間,另一方面導(dǎo)入一個(gè)第三方庫(kù)app的體積會(huì)加大,因此用了一位大神從WebRTC提出來(lái)的模塊,但因?yàn)槭莄的所以還要轉(zhuǎn)一次。

WebRTC降噪有兩部分代碼,一套是定點(diǎn)算法(noise_suppression_x.h),一套是浮點(diǎn)算法(noise_suppression.h)。相對(duì)來(lái)說(shuō)浮點(diǎn)算法精度更高,但是耗系統(tǒng)資源更多,特別是浮點(diǎn)計(jì)算能力較弱的低端ARM CPU上。

音頻處理的時(shí)候webrtc一次僅能處理10ms數(shù)據(jù),小于10ms的數(shù)據(jù)不要傳入,如果是傳入小于10ms的數(shù)據(jù)最后傳入也是按照10ms的數(shù)據(jù)傳出,此時(shí)會(huì)出現(xiàn)問(wèn)題。另外支持采樣率也只有8K,16K,32K三種,不論是降噪模塊,或者是回聲消除增益等等均是如此。對(duì)于8000采樣率,16bit的音頻數(shù)據(jù),10ms的時(shí)間采樣點(diǎn)就是80個(gè),一個(gè)采樣點(diǎn)16bit也就是兩個(gè)字節(jié),那么需要傳入WebRtcNsx_Process的數(shù)據(jù)就是160字節(jié)。對(duì)于8000和16000采樣率的音頻數(shù)據(jù)在使用時(shí)可以不管高頻部分,只需要傳入低頻數(shù)據(jù)即可,但是對(duì)于32K采樣率的數(shù)據(jù)就必須通過(guò)濾波接口將數(shù)據(jù)分為高頻和低頻傳入,傳入降噪后再組合成音頻數(shù)據(jù)。大于32K的音頻文件就必須要通過(guò)重采樣接口降頻到對(duì)應(yīng)的采樣率再處理。

部分代碼

- (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地址開(kāi)始且含有'\0'結(jié)束符的字符串復(fù)制到以dest開(kāi)始的地址空間,返回值的類(lèi)型為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;
    //總音頻采樣數(shù)
    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);
    }
}

//寫(xiě)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代碼

參考:?jiǎn)为?dú)編譯和使用webrtc音頻降噪模塊
參考:音頻降噪算法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容