专栏首页算法+分享用于学习C++音频处理的代码示例

分享用于学习C++音频处理的代码示例

与《分享用于学习C++图像处理的代码示例》为姊妹篇。

为了便于学习C++音频处理并研究音频算法,

俺写了一个适合初学者学习的小小框架。

麻雀虽小五脏俱全,仅仅考虑单通道处理。

采用Decoder and Encoder:dr_wav

https://github.com/mackron/dr_libs/blob/master/dr_wav.h 

关于wav格式的解析移步至:

http://soundfile.sapp.org/doc/WaveFormat/

个人习惯,采用int16的处理方式,也可以通过简单的修改,改为float类型。

 wav音频样本可以从维基百科上(https://en.wikipedia.org/wiki/WAV)下载。

注:少数wav格式不支持

Format

Bitrate (kbit/s)

1 minute (KiB)

Sample

11,025 Hz 16 bit PCM

176.4

1292

11k16bitpcm.wav

8,000 Hz 16 bit PCM

128

938

8k16bitpcm.wav

11,025 Hz 8 bit PCM

88.2

646

11k8bitpcm.wav

11,025 Hz µ-Law

88.2

646

11kulaw.wav

8,000 Hz 8 bit PCM

64

469

8k8bitpcm.wav

8,000 Hz µ-Law

64

469

8kulaw.wav

11,025 Hz 4 bit ADPCM

44.1

323

11kadpcm.wav

8,000 Hz 4 bit ADPCM

32

234

8kadpcm.wav

11,025 Hz GSM 06.10

18

132

11kgsm.wav

8,000 Hz MP3 16 kbit/s

16

117

8kmp316.wav

8,000 Hz GSM 06.10

13

103

8kgsm.wav

8,000 Hz Lernout & Hauspie SBC 12 kbit/s

12

88

8ksbc12.wav

8,000 Hz DSP Group Truespeech

9

66

8ktruespeech.wav

8,000 Hz MP3 8 kbit/s

8

60

8kmp38.wav

8,000 Hz Lernout & Hauspie CELP

4.8

35

8kcelp.wav

附带处理耗时计算,示例演示了一个简单的将音频前面一半静音处理,并简单注释了一下部分逻辑。

完整代码:

#include <stdio.h>
#include <stdlib.h>    
#include <stdint.h>    
#include <time.h> 
#include <iostream> 
//采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"

auto const epoch = clock();
static double now()
{
    return  (clock() - epoch);
};

template <typename FN>
static double bench(const FN &fn)
{
    auto took = -now();
    return (fn(), took + now()) / 1000;
}

//写wav文件
void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_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 = 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);
    } 
}
//读取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 == NULL) {
        printf("读取wav文件失败.");
    }
    //仅仅处理单通道音频
    if (channels != 1)
    {
        drwav_free(buffer);
        buffer = NULL;
        *sampleRate = 0;
        *totalSampleCount = 0;
    }
    return buffer;
}

//分割路径函数
void splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
{
    const char* end;
    const char* p;
    const char* s;
    if (path[0] && path[1] == ':') {
        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';
    }
}

int main(int argc, char* argv[])
{
    std::cout << "Audio Processing " << std::endl;
    std::cout << "博客:http://tntmonks.cnblogs.com/" << std::endl;
    std::cout << "支持解析单通道wav格式." << std::endl;

    if (argc < 2) return -1;
    char* in_file = argv[1];

    //音频采样率
    uint32_t sampleRate = 0;
    //总音频采样数
    uint64_t totalSampleCount = 0;
    int16_t* wavBuffer = NULL;
    double nLoadTime = bench([&]
    {
        wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);
    });
    std::cout << " 加载耗时: " << int(nLoadTime * 1000) << " 毫秒" << std::endl;

    //如果加载成功
    if (wavBuffer != NULL)
    {
        //将前面一般进行静音处理,直接置零即可
        for (uint64_t i = 0; i < totalSampleCount / 2; i++)
        {
            wavBuffer[i] = 0;
        }
    }
    //保存结果
    double nSaveTime = bench([&]
    {
        char drive[3];
        char dir[256];
        char fname[256];
        char ext[256];
        char out_file[1024];
        splitpath(in_file, drive, dir, fname, ext);
        sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);
        wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount);
    });
    std::cout << " 保存耗时: " << int(nSaveTime * 1000) << " 毫秒" << std::endl;
    if (wavBuffer)
    {
        free(wavBuffer);
    }
    getchar();
    std::cout << "按任意键退出程序 \n" << std::endl;
    return 0;
}

示例具体流程为:

加载wav(拖放wav文件到可执行文件上)->简单静音处理->保存wav

并对 加载,保存 这2个环节都进行了耗时计算并输出。

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • mp3格式转wav格式 附完整C++算法实现代码

    近期偶然间看到一个开源项目minimp3 Minimalistic MP3 decoder single header library 项目地址: https:...

    cpuimage
  • 简洁明了的插值音频重采样算法例子 (附完整C代码)

    近一段时间在图像算法以及音频算法之间来回游走。 经常有一些需求,需要将音频进行采样转码处理。 现有的知名开源库,诸如: webrtc , sox等, 代码阅读起...

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

    静音检测 在WebRTC中 是采用计算GMM (Gaussian Mixture Model,高斯混合模型)进行特征提取的。

    cpuimage
  • SpringBoot系列教程web篇之Get请求参数解析姿势汇总

    一般在开发web应用的时候,如果提供http接口,最常见的http请求方式为GET/POST,我们知道这两种请求方式的一个显著区别是GET请求的参数在url中,...

    一灰灰blog
  • Q28 Implement strStr()

    Implement strStr(). Return the index of the first occurrence of needle in haysta...

    echobingo
  • Jquery 跨域访问 Lightswitch OData Service

    修改lightswitch .server project web.config。添加如下内容就可以实现对ApplicationData.svc/跨域访问 <s...

    阿新
  • 走进Java接口测试之测试框架TestNG数据驱动(入门篇)

    我们在前面的文章中,和大家分享过接口自动化测试一些基本的实现方法,但是,你很快就会发现,如果在测试脚本中硬编码测试数据的话,测试脚本灵活性会非常低。而且,对于那...

    高楼Zee
  • C++ 字符串分割

        java和C#中字符串都可以使用split进行分割,但是C++中却没有这个方法,之前总是自己写一个函数自己进行分割,倒也不麻烦,今天在网上找了类似的函数...

    用户1215536
  • C语言中的字符串可以怎么处理?

    char strncpy(char s1,const char *s2,size_t n);

    闫小林
  • 新闻动态|“中国式过马路”怎么破?北京交管正式采用“腾讯优图人脸识别技术”

    近日,北京市公安交通管理局与腾讯优图实验室正式开展合作,在处理非机动车驾驶员和行人违法行为时,试点采用优图人脸识别技术实现对违法人员信息的快速核实。

    优图实验室

扫码关注云+社区

领取腾讯云代金券