大話音頻變聲原理 附簡單示例代碼


關於音頻變聲算法,這個是一個很多人特別感興趣的話題。

當然也有不少開源算法可以參閱學習,有基於時域,也有基於頻域的算法。

最終算法想要達到的目的是一致。

最近也有不少網友問過關於變聲算法的一些細節問題,郵件詢問我。

要給出一個比較合理或者說通俗易懂的解釋,看似簡單,其實還蠻難的。

按照大概的一個邏輯思路,稍微理一理,所以這個主題必須加上“大話”這個前綴。

也不打算講特別高深的,當然也是因為講不來。

之於圖像算法領域,非常重要的算法是高斯模糊,

當然也可以認為是卷積,高斯模糊是卷積的一種特例,這里就不展開了。

而之於音頻,也許你也猜到了,基於時間的,毫無疑問,就是重采樣算法。

音頻采樣率是指錄音設備在一秒鍾內對聲音信號的采樣次數,

采樣頻率越高聲音的還原就越真實越自然。

在當今的主流采集卡上,采樣頻率一般共分為22.05KHz、44.1KHz、48KHz三個等級,

22.05KHz只能達到FM廣播的聲音品質,

44.1KHz則是理論上的CD音質界限,48KHz則更加精確一些。

看到這里,也許大多數人還是沒法理解采樣頻率大概是什么意思。

換個角度來說的話,就是假設一個人說“你好”,花了20毫秒,而機器在這20毫秒內,

采集的數據多少就可以理解為采樣率高低。

也就是說,20毫秒內,采集到的數據量就是可以大概認為目前的采樣率,數據量越大,精度越高,采樣率越高。

那么,我們再換一個思路,想一個問題。

如果在同樣的速率的情況下,

一個人的語速快,一個人的語速慢,那也可能造成采樣數據分布不一致。

這里就可以展開一個音頻算法,就是變速。

嗯,是的,就是變速。

從原理上來講的話,其實變速就是在同樣的采樣率環境下,對采樣數據進行拉伸或壓縮。

從算法的角度上來說的話,可以認為是插值或抽值。

如果你讓一個人講話的速度變得更快怎么做,

很明顯,就是在同樣的采樣率下,抽掉一些樣本。

反之,降速則是插入一些樣本。

最終決定變速效果的就是插入樣本和抽離樣本的權重計算。

例如原來采樣到的數據是

1234

加速的時候,抽離樣本 1 和 4

23

降速的時候,增加樣本 

11223344

當然只是舉個例子,便於大家理解這個概念邏輯。

看到這里,肯定有人會問,

那聲音的大小呢?或者說信號的強弱呢?

其實也就是提升音量和降低音量,我想這個應該不用解釋。

變速是時域變,空間不變。

而音量則反之,時域不變,空間變。

可以簡單粗暴地理解,就是線性拉伸。

例如原來采樣到的數據是

1234

每個樣本+4,直接拉伸為

5678

也有采用乘法進行拉伸的,

例如 乘以2

2468

上面是增大音量,降低音量反之就是減和除。

而最終不管變速還是音量調節,

最終算法要做的事情就是確定對應位置的對應權重。

當然也要看最終想要達到什么樣的效果,適配權重。

饒了這么一大圈,還是沒有說到變聲的問題。

其實,變聲就是變速+音量調節。

以上變速也好,音量調節也好,相對而言都是線性拉伸,

直接的加減乘除然后插值抽值就能達到的。

而變聲的概念其實也是類似的,

就是在在同一時域內同時調節對應時域的音量權重。

換言之就是在同一個采樣率內,同時控制語速和音量在一個特定的權重內。

其實就是一個時域和空間的二維拉伸。

理解這個邏輯確實有點繞。

用采樣算法來做一個簡單的示例。

參閱前面的文章《簡潔明了的插值音頻重采樣算法例子 (附完整C代碼)》

這個示例中的采樣函數是:

void resampler(char *in_file, char *out_file) {
    //音頻采樣率
    uint32_t in_sampleRate = 0;
    //總音頻采樣數
    uint64_t totalSampleCount = 0;
    int16_t *data_in = wavRead_int16(in_file, &in_sampleRate, &totalSampleCount);
    uint32_t out_sampleRate = in_sampleRate * 2;
    uint32_t out_size = (uint32_t) (totalSampleCount * ((float) out_sampleRate / in_sampleRate));
    int16_t *data_out = (int16_t *) malloc(out_size * sizeof(int16_t));
    //如果加載成功
    if (data_in != NULL && data_out != NULL) {
        resampleData(data_in, in_sampleRate, (uint32_t) totalSampleCount, data_out, out_sampleRate);
        wavWrite_int16(out_file, data_out, out_sampleRate, (uint32_t) out_size);
        free(data_in);
        free(data_out);
    } else {
        if (data_in) free(data_in);
        if (data_out) free(data_out);
    }
}

讓我們稍微變通一下,設一個采樣速率,用來調節聲音的速度,同時保證采樣率不變。

void resampler(char *in_file, char *out_file) {
    //音頻采樣率
    uint32_t in_sampleRate = 0;
    //總音頻采樣數
    uint64_t totalSampleCount = 0;
    int16_t *data_in = wavRead_int16(in_file, &in_sampleRate, &totalSampleCount);
    float speed = 0.88;//增加一個速度權重
    uint32_t out_sampleRate = in_sampleRate * speed;
    uint32_t out_size = (uint32_t) (totalSampleCount * ((float) out_sampleRate / in_sampleRate));
    int16_t *data_out = (int16_t *) malloc(out_size * sizeof(int16_t));
    //如果加載成功
    if (data_in != NULL && data_out != NULL) {
        resampleData(data_in, in_sampleRate, (uint32_t) totalSampleCount, data_out, out_sampleRate);
        //out_sampleRate改為輸出一樣的采樣率in_sampleRate
        wavWrite_int16(out_file, data_out, in_sampleRate, (uint32_t) out_size);
        free(data_in);
        free(data_out);
    } else {
        if (data_in) free(data_in);
        if (data_out) free(data_out);
    }
}

修改后是這個樣子的。

有心的朋友發現了。out_size數值有可能增大或縮小了。

以上示例代碼,就是一個簡單的變速算法。

變速就是這么一個原理,音量增大降低就不做示例了。

而變聲是一個什么算法呢?

說白了,就是變速的同時保證out_size還是原來的totalSampleCount。

那要怎么保證呢?

答案就是插值,如果簡單粗暴一點,補0或者刪0即可。

當然這樣做的話,可能會導致音量不一致,最終發聲不對的情況。

這肯定是不科學的,最終的插值時候的權重和對應的內容,產生的效果就看各家本領了。

以上原理,也說得差不多了,具體怎么實現的話,

大家自行參閱相關的開源代碼,再去理解一下。

另外說一下前面《聲音變調算法PitchShift(模擬湯姆貓) 附完整C++算法實現代碼》

這篇文章中的sin和cos 沒有在有效區間內,所以fastsin fastcos計算的結果是有問題的。

詳情大家還是參閱作者原算法吧。

當然,后面有時間我會放出,

簡單清晰的變聲算法的完整c代碼和對應的示例代碼。

而關於基於傅里葉變換的重采樣算法,《基於傅里葉變換的音頻重采樣算法 (附完整c代碼)》

在對應的github 項目fftResample上,我也做了算法邏輯上的修正。

發表過的文章一般很少進行二次編輯了,

關於后期的一些修正和變更,大家還是關注一下github項目的更新比較直接一點。

具體變聲的實現原理,

如上所述,希望通過這篇文章,

大家對音頻變聲算法能有比較直觀的理解和認識。

以上,權當拋磚引玉。

獨樂樂不如一起玩樂。

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM