之前有大概介绍了音频采样相关的思路,详情见《简洁明了的插值音频重采样算法例子 (附完整C代码)》。

音频方面的开源项目很多很多。

最知名的莫过于谷歌开源的WebRTC,

其中的音频模块就包含有

AGC自动增益补偿(Automatic Gain Control)
自动调麦克风的收音量,使与会者收到一定的音量水平,不会因发言者与麦克风的距离改变时,声音有忽大忽小声的缺点。

ANS背景噪音抑制(Automatic Noise Suppression)
探测出背景固定频率的杂音并消除背景噪音。

AEC是回声消除器(Acoustic Echo Canceller)
对扬声器信号与由它产生的多路径回声的相关性为基础,建立远端信号的语音模型,利用它对回声进行估计,并不断地修改滤波器的系数,使得估计值更加逼近真实的回声。然后,将回声估计值从话筒的输入信号中减去,从而达到消除回声的目的,AEC还将话筒的输入与扬声器过去的值相比较,从而消除延长延迟的多次反射的声学回声。根椐存储器存放的过去的扬声器的输出值的多少,AEC可以消除各种延迟的回声。

在《音频增益响度分析 ReplayGain 附完整C代码示例》也提及到了。

不过本文还不是着重于这三个算法,还是先从采样算法来。

当然有兴趣的小伙伴,建议去看下 WebRTC中与signal_processing_library相关的操作算法。

有不少优化的思路可以学习之。

这里也不展开了。

之前说过采样可以采用简单的插值的方式进行模拟处理,在精度要求不高的情况下。

但是若是对精度有所要求,那就另论了。

好在前人踩坑,后人走路。

WebRTC中有一个音频采样器的类,虽然有一定的使用限制,但是在大多数应用场景下,也够用了。

WebRTC的代码是很干净,奈何,各个头文件之间的依赖,实在混乱。

不过稍微耐心,还是能把代码理出个七七八八。

稍微花了时间,造福下大家。

将WebRTC中的采样器代码单独抽离出来,

并编写了C++示例代码。

完整示例代码:

#include <cstdio>
#include <cstdlib>
#include <cstdint>
//采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
#define DR_WAV_IMPLEMENTATION

#include "dr_wav.h"
#include "resampler.h"

//写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 = ;
    format.sampleRate = (drwav_uint32) sampleRate;
    format.bitsPerSample = ;
    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();
        }
    }
}

//读取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("读取wav文件失败.");
    }
    //仅仅处理单通道音频
    ) {
        drwav_free(buffer);
        buffer = nullptr;
        *sampleRate = ;
        *totalSampleCount = ;
    }
    return buffer;
}

//分割路径函数
void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
    const char *end;
    const char *p;
    const char *s;
    ] && path[] == ':') {
        if (drv) {
            *drv++ = *path++;
            *drv++ = *path++;
            *drv = '\0';
        }
    } else if (drv)
        *drv = '\0';
    for (end = path; *end && *end != ':';)
        end++;
    for (p = end; p > path && *--p != '\\' && *p != '/';)
        if (*p == '.') {
            end = p;
            break;
        }
    if (ext)
        for (s = end; (*ext = *s++);)
            ext++;
    for (p = end; p > path;)
        if (*--p == '\\' || *p == '/') {
            p++;
            break;
        }
    if (name) {
        for (s = p; s < end;)
            *name++ = *s++;
        *name = '\0';
    }
    if (dir) {
        for (s = path; s < p;)
            *dir++ = *s++;
        *dir = '\0';
    }
}

int16_t *resampler(int16_t *data_in, size_t totalSampleCount, size_t in_sample_rate, size_t out_sample_rate) {
    if (data_in == nullptr)
        return nullptr;
    ) return nullptr;
    size_t lengthIn = in_sample_rate / ;
    size_t maxLen = out_sample_rate / ;
    ;
    Resampler rs;
    size_t outLen = (size_t) (totalSampleCount * out_sample_rate / in_sample_rate);
    int16_t *data_out = (int16_t *) malloc(outLen * sizeof(int16_t));
    if (data_out == nullptr) return nullptr;
    size_t nCount = (totalSampleCount / lengthIn);
    size_t nLast = totalSampleCount - (lengthIn * nCount);
    int16_t *samplesIn = data_in;
    int16_t *samplesOut = data_out;
    rs.Reset(in_sample_rate, out_sample_rate, channels);
    outLen = ;
    ; i < nCount; i++) {
        rs.Push(samplesIn, lengthIn, samplesOut, maxLen, outLen);
        samplesIn += lengthIn;
        samplesOut += outLen;
    }
    ) {
        ;
        int16_t samplePatchIn[max_samples] = {};
        int16_t samplePatchOut[max_samples] = {};
        memcpy(samplePatchIn, samplesIn, nLast * sizeof(int16_t));
        rs.Push(samplesIn, nLast, samplePatchOut, maxLen, outLen);
        memcpy(samplesOut, samplePatchOut, (nLast * out_sample_rate / in_sample_rate) * sizeof(int16_t));
    }
    return data_out;
}

) {
    //音频采样率
    uint32_t sampleRate = ;
    //总音频采样数
    uint64_t inSampleCount = ;
    int16_t *inBuffer = wavRead_int16(in_file, &sampleRate, &inSampleCount);
    //如果加载成功
    if (inBuffer != nullptr) {
        int16_t *outBuffer = resampler(inBuffer, (size_t) inSampleCount, sampleRate, out_sample_rate);
        if (outBuffer != nullptr) {
            size_t outSampleCount = (size_t) (inSampleCount * (out_sample_rate * 1.0f / sampleRate));
            wavWrite_int16(out_file, outBuffer, out_sample_rate, outSampleCount);
            free(outBuffer);
        }
        free(inBuffer);
    }
}

int main(int argc, char *argv[]) {
    printf("WebRtc Resampler\n");
    printf("博客:http://tntmonks.cnblogs.com/\n");
    printf("音频插值重采样\n");
    printf("支持采样率: 8k、16k、32k、48k、96k\n");
    )
        ;
    ];
    ];
    ];
    ];
    ];
    ];
    splitpath(in_file, drive, dir, fname, ext);
    sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);
    ResampleTo(in_file, out_file, );
    getchar();
    printf("按任意键退出程序 \n");
    ;
}

项目地址:https://github.com/cpuimage/WebRTC_Resampler

采样器的代码很简单,详情见resampler.cpp

示例具体流程为:

加载wav(拖放wav文件到可执行文件上)->重采样->保存为_out.wav文件

示例比较简单,用cmake即可进行编译示例代码,详情见CMakeLists.txt。

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

WebRTC 音频采样算法 附完整C++示例代码的更多相关文章

  1. 人脸姿态校正算法 附完整C++示例代码

    在一些特殊情况下,经常需要依据图像中的人脸,对图片进行倾斜矫正. 例如拍照角度幅度过大之类的情况,而进行人工矫正确实很叫人头大. 那是不是可以有一种算法,可以根据人脸的信息对图片进行角度的修复呢? 答 ...

  2. 基于傅里叶变换的音频重采样算法 (附完整c代码)

    前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

  3. 音频降噪算法 附完整C代码

    降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...

  4. 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...

  5. 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)

    webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...

  6. 基于RNN的音频降噪算法 (附完整C代码)

    前几天无意间看到一个项目rnnoise. 项目地址: https://github.com/xiph/rnnoise 基于RNN的音频降噪算法. 采用的是 GRU/LSTM 模型. 阅读下训练代码,可 ...

  7. mser 最大稳定极值区域(文字区域定位)算法 附完整C代码

    mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...

  8. WebRTC 音频算法 附完整C代码

    WebRTC提供一套音频处理引擎, 包含以下算法: AGC自动增益控制(Automatic Gain Control) ANS噪音抑制(Automatic Noise Suppression) AEC ...

  9. 音频自动增益 与 静音检测 算法 附完整C代码

    前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...

随机推荐

  1. iOS移动端直连数据库

    一个可以直接连接服务器MySQL的工具包(极不安全,如非特殊需求,不推荐使用) 这种直接连接服务器数据的方式是极为不安全的,但因为我们这个项目特殊情况,只在局域网内使用, 且只有一个pad对一台设备进 ...

  2. codeforce round #467(div.2)

    A. Olympiad 给出n个数,让你找出有几个非零并且不重复的数 所以用stl的set //#define debug #include<stdio.h> #include<ma ...

  3. 如何用Word编辑参考文献------这是引用一位大师的

    如何用Word编辑参考文献修改文献是一件非常痛苦的事情,虽然现在也有很多软件可以编排参考文献,其实word本身就可以. 采用合适的编辑方法会方便地做到整齐,规范,自动排序和交叉引用.1.以尾注的方式插 ...

  4. 转载--MYSQL5.7:Access denied for user 'root'@'localhost' (using password:YES)解决方法

    1.打开MySQL目录下的my.ini文件,在文件的最后添加一行"skip-grant-tables",保存并关闭文件; 2.重启MySQL服务; 3.通过cmd行进入MySQL的 ...

  5. Java基础学习笔记六 Java基础语法之类和ArrayList

    引用数据类型 引用数据类型分类,提到引用数据类型(类),其实我们对它并不陌生,如使用过的Scanner类.Random类.我们可以把类的类型为两种: 第一种,Java为我们提供好的类,如Scanner ...

  6. 实验四 Android程序设计 实验报告

    实验四 Android程序设计 实验报告 目录 代码托管地址 Android程序设计-1 Android程序设计-2 Android程序设计-3 Android程序设计-4 Android程序设计-5 ...

  7. 安装iis8

    -------------------- @echo off     echo 正在添加IIS8.0 功能,依据不同的网络速率,全程大约需要5分钟时间...     start /w pkgmgr / ...

  8. 201621123060《JAVA程序设计》第三周学习总结

    1. 本周学习总结 1.1写出你认为本周学习中比较重要的知识点关键词,如类.对象.封装等. 关键词:类.方法.属性.对象.多态.继承.封装.面向对象.> 1.2 用思维导图或者Onenote或其 ...

  9. python3变量和数据类型

        变量和数据类型 知识点 python 关键字 变量的定义与赋值 input() 函数 字符串的格式化 实验步骤 每一种编程语言都有它们自己的语法规则,就像我们所说的外语. 1. 关键字和标识符 ...

  10. scrapy 爬取当当网产品分类

    #spider部分import scrapy from Autopjt.items import AutopjtItem from scrapy.http import Request class A ...