zoukankan      html  css  js  c++  java
  • 分享用于学习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格式不支持

    FormatBitrate (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 = '';
            }
        }
        else if (drv)
            *drv = '';
        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 = '';
        }
        if (dir) {
            for (s = path; s < p;)
                *dir++ = *s++;
            *dir = '';
        }
    }
    
    int main(int argc, char* argv[])
    {
        std::cout << "Audio Processing " << std::endl;
        std::cout << "博客:http://cpuimage.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 << "按任意键退出程序 
    " << std::endl;
        return 0;
    }

    示例具体流程为:

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

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

      

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

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

    若此博文能帮到您,欢迎扫码小额赞助。

    微信:  

     

    支付宝: 

  • 相关阅读:
    ORA-12560:TNS:协议适配器错误
    oracledbconsole db启动问题
    安装tomcat出现failed to install tomcat6 service错误及解决方法(转载)
    关于Eclipse配置tomcat
    js indexof用法indexOf()定义和用法
    手机被没收事件。。。
    一维数组,求最大子数组!!!
    用n(0)次求一个数组里面最大子数组的和(数组可以输入负数)
    jwt认证
    序列化组件
  • 原文地址:https://www.cnblogs.com/cpuimage/p/8278451.html
Copyright © 2011-2022 走看看