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 n"); printf("blog:http://cpuimage.cnblogs.com/ n"); printf("Pitch Shifting Using The Fourier Transformn"); 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,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 msn ",(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",ext); wavWrite_s16(out_file,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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |