首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分享用于学习C++音频处理的代码示例

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

作者头像
cpuimage
发布2018-04-12 15:41:22
2.4K0
发布2018-04-12 15:41:22
举报
文章被收录于专栏:算法+算法+

与《分享用于学习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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-01-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档