音頻算法之小黃人變聲 附完整C代碼

前面說起到《大話音頻變聲原理 附簡單示例代碼》與《聲音變調算法PitchShift(模擬湯姆貓) 附完整C++算法實現代碼html

都稍微講過變聲的原理和具體實現。python

你們都知道,算法從實現到最後工程應用,中間的環節和問題特別多。c++

尤爲是編碼的架構設計,好的數據結構和代碼邏輯封裝確定是可複用,組件化的。git

前幾天寫完《音頻識別算法思考與階段性小結》的時候,github

我也說起到了。算法

會作一些算法編碼優化相關的分享。編程

而有時候我總以爲文字表達很蒼白,c#

因此我儘量地把代碼寫得簡潔易懂,數據結構

一方面是便於基礎差的朋友學習。架構

另外一方面也是爲了本身在編碼以及思考的時候,能更加清晰。

固然,變聲算法絕大多數朋友都會選擇一些開源的或者商業sdk去作二次開發。

例如:

https://www.fmod.com/

https://www.surina.net/soundtouch/

但若是僅僅停留在使用的階段,它就是一個黑盒子。

知其然,殊不知其因此然。

是遠遠不夠的。

有時候咱們是要站在巨人的肩膀上去看到更美麗的風景。

可是,我但願是一羣人,而不是一我的。

也許你們也發現了,我寫的大多數算法,是純c無第三方依賴的。

是否是就會懷疑,我就只會寫c語言?

不是的,我所掌握的編程語言:

主要: c,c++,python,彙編 

其次:pascal,c#,js,lua,go等

編程語言只是一個工具,關鍵仍是算法思路。

用純c寫的主要目的,是爲了破除一些第三方依賴,

不要只知其一;不知其二地使用黑盒子。

固然,其次的好處就是跨平臺,便攜,可複用。

這樣,一切瞭然於心。

爲何不能夠造輪子呢?

只要你造的輪子是有用的,

無論是用於觀賞用於學習仍是其餘用途。

在我瞭解到一些音頻算法的思路以後,

變聲算法的思路,

我以爲它的思路很是適用於擴展到大多數音頻算法實現,

並且可複用度比較高。

因此,將它梳理開源,就顯得特別有意義。

而你們能夠基於這個實現,進一步去改進或者學習 音頻算法,

例如降噪,增益等等。

由於這個編碼實現的設計是徹底能夠適用到音頻算法應用場景的。

邏輯也很是清晰。

項目地址:

https://github.com/cpuimage/pitchshift

固然爲了便於一些朋友的學習使用,

示例代碼提供一個簡易的實現,

模擬變聲爲小黃人。

int main(int argc, char *argv[]) {
    printf("Audio Processing \n");
    printf("blog:http://cpuimage.cnblogs.com/ \n");
    printf("Pitch Shifting Using The Fourier Transform\n");

    if (argc < 2)
        return -1;

    char *in_file = argv[1];
    uint32_t sampleRate = 0;
    uint64_t totalSampleCount = 0;
    uint32_t channels = 0;
    short *data_in = wavRead_s16(in_file, &sampleRate, &totalSampleCount, &channels);
    if (data_in != NULL) {
        float pitchShift = 0.9f;
        size_t ms = 50;
        size_t overSampling = 4;
        size_t frameSize = sampleRate * ms / 1000;
        frameSize += frameSize % 2;
        planData pitchPlanData = {0};
        double startTime = now();
        makePlanData(frameSize, overSampling, sampleRate, &pitchPlanData);
        pitchshift(pitchShift, data_in, data_in, totalSampleCount, &pitchPlanData);
        // turn to minion pitch
        {
            totalSampleCount /= 2;
            short *samples = data_in;
            for (int i = 0; i < totalSampleCount; i++) {
                data_in[i] = samples[0];
                samples += 2;
            }
        }
        double time_interval = calcElapsed(startTime, now());
        freePlanData(&pitchPlanData);
        printf("time interval: %f ms\n ", (time_interval * 1000));
    }
    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_s16(out_file, data_in, sampleRate, totalSampleCount);
    if (data_in) {
        free(data_in);
    }
    printf("press any key to exit.\n");
    getchar();
    return 0;
}

不作多解釋,你們能夠參閱pitchshift函數的實現,

主要實現位於文件PitchShift.h。

整個算法不到200行,邏輯很是清晰,

已經作了必定程度上的工程化優化。

固然還有很大的改進空間,

不過這份代碼,更多的意義在於學習。

授人以魚不如授人以漁。

如有其餘相關問題或者需求也能夠郵件聯繫俺探討。

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

相關文章
相關標籤/搜索