zoukankan      html  css  js  c++  java
  • 音频算法之小黄人变声 附完整C代码

    前面提及到《大话音频变声原理 附简单示例代码》与《声音变调算法PitchShift(模拟汤姆猫) 附完整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 
    ");
        printf("blog:http://cpuimage.cnblogs.com/ 
    ");
        printf("Pitch Shifting Using The Fourier Transform
    ");
    
        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
     ", (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.
    ");
        getchar();
        return 0;
    }

    不做多解释,大家可以参阅pitchshift函数的实现,

    主要实现位于文件PitchShift.h。

    整个算法不到200行,逻辑非常清晰,

    已经做了一定程度上的工程化优化。

    当然还有很大的改进空间,

    不过这份代码,更多的意义在于学习。

    授人以鱼不如授人以渔。

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

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

  • 相关阅读:
    JS 数组
    JS 模拟彩票
    C++ 动态内存
    计算机网络--OSI七层模型
    C++ 异常处理
    C++ 文件和流
    数据库学习教程网站
    数据结构--哈夫曼树
    数据结构--红黑树
    数据结构--伸展树
  • 原文地址:https://www.cnblogs.com/cpuimage/p/9690112.html
Copyright © 2011-2022 走看看