• 音频增益响度分析 ReplayGain 附完整C代码示例【转】


    转自:http://www.cnblogs.com/cpuimage/p/8846951.html

    人们所熟知的图像方面的3A算法有:

    AF自动对焦(Automatic Focus)
    自动对焦即调节摄像头焦距自动得到清晰的图像的过程

    AE自动曝光(Automatic Exposure)
    自动曝光的是为了使感光器件获得合适的曝光量

    AW自动白平衡(Automatic White Balance)
    白平衡的本质是使白色物体在任何光源下都显示白色

    与之相对应的音频方面的3A算法是:

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

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

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

     图像方面的算法就不多说了,图像方面的3a算法,本人都实现了。

    自动白平衡的主要思路,就是如何判断图像是否偏色,偏色后如何修复的问题。

    常见的有直方图均衡,自动对比度,自动色阶等等。

    自动曝光也是要做曝光评估,常见的有gama调节等等。

    后续有时间,再陆续贴出相应的代码。

    在这里,先卖个关子,占个坑。

    而在音频算法方面,自动增益补偿的算法有点类似图像的自动曝光算法。

    主要要考虑的是多长的音频,怎么分析当前音频的音量或者强度。

    根据这个强度对整个音频做一个归一化拉伸,诸如此类。

    图像与音频殊途同归。

    而历史悠久的算法,莫过于,ReplayGain

    ReplayGain是David Robinson在2001年发布的一项建议标准,用于衡量计算机音频格式 中音频的响度

    相关的维基资料:

    https://en.wikipedia.org/wiki/ReplayGain

    现在大多数的音频播放器都支持这个特性。

    根据维基上的说明,现在大多数使用的开源实现是  MP3Gain

    资料见:

    http://wiki.hydrogenaud.io/index.php?title=Replaygain#Players_support

    开源项目地址:

    http://mp3gain.sourceforge.net/

    项目是C代码,非常干净。

    主要的算法实现文件见:gain_analysis.h 与 gain_analysis.c

    算法是根据传入的音频数据,分析需要进行增益的分贝值。

    不需要增益则为0,需要增益则为对应的浮点正数或负数。

    当然,不能传入太少的音频样本,否则无法客观分析。

    算法只需要传入音频的数据和指定需要分析的样本长度即可。

    最终输出一个 推荐增益的分贝值。

    根据这个分贝值进行换算,即可以对目标音频做一些特定的音频处理。

    贴上完整的C代码:

    复制代码
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    //采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
    #define DR_WAV_IMPLEMENTATION
    
    #include "dr_wav.h"
    #include "gain_analysis.h"
    
    
    #ifndef min
    #define min(a, b)            (((a) < (b)) ? (a) : (b))
    #endif
    
    //读取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;
    }
    
    
    float getGaindB(int16_t *buffer, size_t totalSampleCount, int sampleRate, size_t analyzeSamples) {
        float ret = -0.00000000001f;
        if (totalSampleCount == 0) return ret;
        if (analyzeSamples == 0) return ret;
        const int maxSamples = 2400;
        analyzeSamples = min(maxSamples, analyzeSamples);
        ret = 1.0f;
        int num_channels = 1;
        Float_t inf_buffer[maxSamples];
        size_t totalCount = totalSampleCount / analyzeSamples;
        if (InitGainAnalysis(sampleRate) == INIT_GAIN_ANALYSIS_OK) {
            int16_t *input = buffer;
            for (int i = 0; i < totalCount; i++) {
                for (int n = 0; n < analyzeSamples; n++) {
                    inf_buffer[n] = input[n];
                }
                if (AnalyzeSamples(inf_buffer, NULL, analyzeSamples, num_channels) != GAIN_ANALYSIS_OK)
                    break;
                GetTitleGain();
                //    printf("Recommended dB change for analyzeSamples %d: %+6.2f dB
    ", i, titleGain);
                input += analyzeSamples;
            }
            ret = GetAlbumGain();
        }
        if ((int) ret == GAIN_NOT_ENOUGH_SAMPLES) {
            ret = -0.00000000001f;
        }
        return ret;
    }
    
    
    void analyze(char *in_file, int ref_ms) {
        uint32_t sampleRate = 0;
        uint64_t totalSampleCount = 0;
        int16_t *wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);
        if (wavBuffer != NULL) {
            size_t analyzeSamples = ref_ms * (sampleRate / 1000);
            float gain = getGaindB(wavBuffer, totalSampleCount, sampleRate, analyzeSamples);
    
            printf("recommended dB change: %f 
    ", gain);
            free(wavBuffer);
        }
    }
    
    int main(int argc, char *argv[]) {
        printf("Replay Gain Analysis
    ");
        printf("blog:http://cpuimage.cnblogs.com/
    ");
        printf("e-mail:gaozhihan@vip.qq.com
    ");
        if (argc < 2)
            return -1;
        char *in_file = argv[1];
        //指定分析长度1秒
        int ref_ms = 1000;
        analyze(in_file, ref_ms);
        getchar();
        printf("press any key to exit. 
    ");
        return 0;
    }
    
    #ifdef __cplusplus
    }
    #endif
    复制代码

    我的习惯,尽量少些注释,代码尽量干净整洁。

    所以大家直接看代码吧。

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

    示例具体流程为:

    加载wav(拖放wav文件到可执行文件上)->输出结果->保存wav

    得到对应的评估结果之后,接下来作何处理,就看各位看官的具体需求了。

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

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

  • 相关阅读:
    Centos 通过yum的方式升级内核
    docker入门——镜像简介
    docker入门——管理容器
    docker入门——安装及简单操作
    docker入门——简介
    Centos 6安装 Jenkins
    Centos 7 搭建OpenStack 私有云——(1)基础环境配置
    Python正则表达式
    多选控件multipicker
    绝对定位 软键盘弹出时顶起底部按钮
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8910173.html
Copyright © 2020-2023  润新知