经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
音频算法之小黄人变声 附完整C代码
来源:cnblogs  作者:cpuimage  时间:2018/9/25 20:32:52  对本文有异议

前面提及到《大话音频变声原理 附简单示例代码》与《声音变调算法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

当然为了便于一些朋友的学习使用,

示例代码提供一个简易的实现,

模拟变声为小黄人。

  1. int main(int argc, char *argv[]) {
  2. printf("Audio Processing \n");
  3. printf("blog:http://cpuimage.cnblogs.com/ \n");
  4. printf("Pitch Shifting Using The Fourier Transform\n");
  5. if (argc < 2)
  6. return -1;
  7. char *in_file = argv[1];
  8. uint32_t sampleRate = 0;
  9. uint64_t totalSampleCount = 0;
  10. uint32_t channels = 0;
  11. short *data_in = wavRead_s16(in_file, &sampleRate, &totalSampleCount, &channels);
  12. if (data_in != NULL) {
  13. float pitchShift = 0.9f;
  14. size_t ms = 50;
  15. size_t overSampling = 4;
  16. size_t frameSize = sampleRate * ms / 1000;
  17. frameSize += frameSize % 2;
  18. planData pitchPlanData = {0};
  19. double startTime = now();
  20. makePlanData(frameSize, overSampling, sampleRate, &pitchPlanData);
  21. pitchshift(pitchShift, data_in, data_in, totalSampleCount, &pitchPlanData);
  22. // turn to minion pitch
  23. {
  24. totalSampleCount /= 2;
  25. short *samples = data_in;
  26. for (int i = 0; i < totalSampleCount; i++) {
  27. data_in[i] = samples[0];
  28. samples += 2;
  29. }
  30. }
  31. double time_interval = calcElapsed(startTime, now());
  32. freePlanData(&pitchPlanData);
  33. printf("time interval: %f ms\n ", (time_interval * 1000));
  34. }
  35. char drive[3];
  36. char dir[256];
  37. char fname[256];
  38. char ext[256];
  39. char out_file[1024];
  40. splitpath(in_file, drive, dir, fname, ext);
  41. sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);
  42. wavWrite_s16(out_file, data_in, sampleRate, totalSampleCount);
  43. if (data_in) {
  44. free(data_in);
  45. }
  46. printf("press any key to exit.\n");
  47. getchar();
  48. return 0;
  49. }

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

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

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

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

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

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

授人以鱼不如授人以渔。

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

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号