1. 程式人生 > >音頻增益響度分析 ReplayGain 附完整C代碼示例【轉】

音頻增益響度分析 ReplayGain 附完整C代碼示例【轉】

.html ssi ifdef bar read IT 輸出 標準 avi

轉自: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\n", 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 \n", gain);
        free(wavBuffer);
    }
}

int main(int argc, char *argv[]) {
    printf("Replay Gain Analysis\n");
    printf("blog:http://cpuimage.cnblogs.com/\n");
    printf("e-mail:[email protected]\n");
    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. \n");
    return 0;
}

#ifdef __cplusplus
}
#endif
技術分享圖片

我的習慣,盡量少些註釋,代碼盡量幹凈整潔。

所以大家直接看代碼吧。

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

示例具體流程為:

加載wav(拖放wav文件到可執行文件上)->輸出結果->保存wav

得到對應的評估結果之後,接下來作何處理,就看各位看官的具體需求了。

若有其他相關問題或者需求也可以郵件聯系俺探討。

郵箱地址是:
[email protected]

音頻增益響度分析 ReplayGain 附完整C代碼示例【轉】