我喜欢电子音乐,我对这一切都很感兴趣。 我发现了很多关于库的堆栈溢出的有用问题,可以用来播放音频,过滤器等。但我真正好奇的是实际上是什么样的:数据如何在效果和振荡器之间传递?我已经研究了dsp的数学方面,我已经解决了问题的结束,但我不确定使用什么缓冲系统等。最终的目标是有一个简单的对象层次效果和振荡器传递数据彼此之间(如果我最终没有拉出所有的头发试图实现它,可能使用多线程)。它不会成为下一个Propellerhead Reason,但我对它的运作方式感兴趣,这更像是一种运动而不是最终产品。
目前我使用.net和C#,我最近学习了F#(可能会或可能不会导致一些有趣的处理数据的方式),但如果这些不适合这项工作,我可以在必要时学习另一个系统。
问题是:使用缓冲区通过程序获取大量信号数据的最佳方法是什么?例如,我会更好地使用队列,数组,链接列表等?我是否应该使样本不可变并在每次将效果应用于系统或仅编辑缓冲区中的值时创建一组新数据? Shoud我有一个调度程序/线程池样式对象来组织传递数据,或者效果函数是否应该直接在彼此之间传递数据?
感谢。
编辑:另一个相关的问题是我如何使用Windows API来播放这个数组?我真的不想使用DirectShow,因为微软已经让它现在死了EDIT2:感谢所有答案。看完所有技术之后,我将使用XNA 4(我花了一段时间在网上搜索,发现this site解释了怎么做)或NAudio输出音乐...不确定哪一个,取决于关于系统最终的进展程度。当C#5.0问世时,我将使用其异步功能来创建一个效果架构。我几乎平等地使用了每个人的答案,所以现在我有一个难以给予赏金的难题......
答案 0 :(得分:7)
你看过VST.NET(http://vstnet.codeplex.com/)了吗?它是一个使用C#编写VST的库,它有一些例子。您也可以考虑编写VST,以便可以从任何主机应用程序使用您的代码(但即使您不想要,也可以查看它们的代码)。
信号数据通常很大,需要大量处理。不要使用链表!我知道的大多数库只是使用一个数组来放置所有音频数据(毕竟,这就是声卡所期望的)。
来自VST.NET示例:
public override void Process(VstAudioBuffer[] inChannels, VstAudioBuffer[] outChannels)
{
VstAudioBuffer audioChannel = outChannels[0];
for (int n = 0; n < audioChannel.SampleCount; n++)
{
audioChannel[n] = Delay.ProcessSample(inChannels[0][n]);
}
}
audioChannel是非托管float *缓冲区的包装。
您可能将样本存储在不可变数组中。然后,当您想要播放它们时,您可以复制输出缓冲区中的数据(如果需要,可以更改频率)并在此缓冲区中执行效果。请注意,您可以使用多个输出缓冲区(或通道)并在结尾处对它们求和。
修改强>
我知道有两种低级方式来播放你的数组:来自Windows API的DirectSound和WaveOut。 C# Example using DirectSound。 C# example with WaveOut。但是,您可能更喜欢使用外部更高级别的库,例如NAudio。 NAudio便于.NET音频操作 - 请参阅此blog post以将正弦波发送到声卡。你可以看到他们也在使用浮点数组,这是我推荐的(如果你使用字节进行计算,你最终会在声音中出现很多混叠)。
答案 1 :(得分:4)
F#可能是一个很好的选择,因为它非常适合操作函数。函数可能是用于信号创建和处理的良好构建块。
由于数组模块中的高阶函数,F#也擅长操纵集合,特别是数组。这些品质使F#在金融领域很受欢迎,对于信号处理也很有用,我猜。
Visual F# 2010 for Technical Computing有一个专门用于傅立叶变换的部分,它可能与您想要做的事情相关。我想有很多关于网上转换的免费信息。
最后,要播放示例,您可以使用XNA。我认为最新版本的API(4.0)也允许录制,但我从未使用过。 Xbox有一个名为ezmuse+ Hamst3r Edition的着名音乐编辑应用程序,它使用XNA,所以它绝对有可能。
答案 2 :(得分:2)
关于缓冲和异步/线程/同步问题,我建议你看看新的TPL数据流库。凭借其块原语,并发数据结构,数据流网络,异步消息访问和TPL基于任务的抽象(可与async / await C#5功能一起使用),它非常适合此类应用程序。
答案 3 :(得分:2)
我不知道这是否真的是你想要的,但这是我在大学时的个人项目之一。在我自己实现之前,我并没有真正理解声音和DSP是如何工作的。我试图尽可能接近说话者,所以我只使用libsndfile来处理文件格式错综复杂。
基本上,我的第一个项目是创建一个大型的双精度数组,用正弦波填充它,然后使用sf_writef_double()将该数组写入文件以创建我可以播放的内容,并查看结果波形编辑器。
接下来,我在正弦调用和写调用之间添加了另一个函数来添加效果。
这样你开始玩非常低级别的振荡器和效果,你可以立即看到结果。另外,只需很少的代码就可以实现这样的工作。
就个人而言,我会从最简单的解决方案开始,然后慢慢补充。尝试只写出一个文件并使用你的音频播放器来播放它,这样你就不必处理音频apis了。只需使用单个数组即可启动和修改。绝对是从单线程开始的。随着项目的增长,您可以开始转向其他解决方案,例如管道而不是阵列,多线程,或使用音频API。
如果你想创建一个你可以发布的项目,具体取决于它是什么,你可能不得不转向更复杂的库,比如一些实时音频处理。但是,当你达到这一点时,通过上述简单方法学习的基础知识肯定会有所帮助。
祝你好运!答案 4 :(得分:2)
我已经完成了相当多的实时DSP,尽管没有音频。虽然您的任何想法(不可变缓冲区)与(可修改的缓冲区就位)都可以工作,但我更喜欢为信号路径中的每个链路创建一个永久缓冲区。由于每个输入样本都会影响多个输出样本,因此大多数效果都不适合在适当的位置进行修改。当你有重新采样阶段时,每个链接缓冲技术的效果特别好。
这里,当样本到达时,第一个缓冲区被覆盖。然后第一个过滤器从其输入缓冲区(第一个缓冲区)读取新数据并写入其输出(第二个缓冲区)。然后它调用第二个阶段从第二个缓冲区读取并写入第三个阶段。
此模式完全消除了动态分配,允许每个阶段保留可变数量的历史记录(因为效果需要一些内存),并且只要能够重新排列路径中的过滤器,就会非常灵活。
答案 5 :(得分:1)
好吧,我还会对赏金进行抨击然后:)
我实际情况非常相似。我多年来一直在制作电子音乐,但仅在过去的几年里,我才开始探索实际的音频处理。
你提到你已经研究了数学。我认为这至关重要。我目前正在通过Ken Steiglitz的“数字信号处理入门 - 与数字音频和计算机音乐的应用”进行斗争。如果您不知道您的复数和相量,那将非常困难。
我是一个Linux人,所以我开始在C中编写LADSPA插件。我认为从这个基本级别开始,真正了解正在发生的事情是很好的。如果我在Windows上,我会从Steinberg下载VST SDK并编写一个简单的概念证明插件,它只会增加噪音或其他任何内容。
选择VST或LADSPA等框架的另一个好处是,您可以立即在普通音频套件中使用插件。将您的第一个自制插件应用于音轨的满意度是无与伦比的。此外,您还可以与其他音乐家分享您的插件。
有可能在C#/ F#中执行此操作,但如果您打算编写VST插件,我建议使用C ++,以避免任何不必要的开销。这似乎是行业标准。
在缓冲方面,我一直在使用循环缓冲区(这里有一篇好文章:http://www.dspguide.com/ch28/2.htm)。一个很好的练习就是实现一个有限响应滤波器(Steiglitz称之为前馈滤波器) - 这些滤波器依赖于缓冲并且非常有趣。
我在Github上有一些非常基本的LADSPA插件的回购。除了架构差异之外,它们也可能对编写VST插件的人有用。 https://github.com/andreasjansson/my_ladspa_plugins
示例代码的另一个很好的来源是CSound项目。那里有大量的DSP代码,该软件主要针对音乐家。
答案 6 :(得分:0)
答案 7 :(得分:0)
您可以查看BYOND。它是C#中程序化音频/ midi乐器和效果创建的环境。它可以作为独立版本使用,也可以作为VST指示和效果。
完全披露我是BYOND的开发者。