从头开始创建DSP系统

本文关键字:系统 DSP 创建 从头开始 | 更新日期: 2023-09-27 17:59:07

我喜欢电子音乐,我对它的运作方式很感兴趣。我在Stack Overflow上发现了很多有用的问题,这些问题涉及可以用来播放音频、过滤器等的库。但我真正好奇的是实际发生了什么:数据是如何在效果和振荡器之间传递的?我已经对dsp的数学方面进行了研究,我已经找到了问题的答案,但我不确定该使用什么缓冲系统等。最终目标是拥有一个简单的对象层次结构,包括在彼此之间传递数据的效果和振荡器(如果我最终没有竭尽全力实现它,可能会使用多线程)。这不会是下一个螺旋桨头原因,但我对它的工作原理很感兴趣,这更多的是一种练习,而不是产生最终产品的东西。

目前我使用.net和C#,我最近学习了F#(这可能会也可能不会导致一些有趣的数据处理方法),但如果这些不适合这份工作,我可以在必要时学习另一个系统。

问题是:使用缓冲区通过程序获取大量信号数据的最佳方式是什么?例如,使用队列、数组、链表等会更好吗?我应该让样本不可变,并在每次对系统应用效果时创建一组新的数据,还是只编辑缓冲区中的值?我应该有一个调度程序/线程池风格的对象来组织传递的数据吗?或者效果函数应该直接在彼此之间传递数据吗?

谢谢。

编辑:另一个相关的问题是如何使用windows API来播放这个数组?我真的不想使用DirectShow,因为微软现在已经让它死了

第二版:谢谢你的回答。在看了所有的技术后,我会使用XNA 4(我花了一段时间在互联网上搜索,找到了这个解释如何做到这一点的网站)或NAudio来输出音乐。。。目前还不确定是哪一个,这取决于系统最终的先进程度。当C#5.0问世时,我将使用它的异步功能在此基础上创建一个效果架构。我几乎平等地使用了每个人的答案,所以现在我有一个难题,那就是该把赏金交给谁…

从头开始创建DSP系统

你看过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*缓冲区的包装器。

您可能将样本存储在一个不可变的数组中。然后,当您想播放它们时,您可以复制输出缓冲区中的数据(如果需要,可以更改频率),并在该缓冲区中执行效果。请注意,您可以使用多个输出缓冲区(或通道),并在最后对它们求和。

编辑

我知道两种低级的方法来播放你的数组:DirectSound和WaveOut从Windowsneneneba API。C#使用DirectSound的示例。带有WaveOut的C#示例。但是,您可能更喜欢使用外部高级库,如NAudio。NAudio对.NET音频操作很方便——请参阅这篇关于向声卡发送正弦波的博客文章。你可以看到他们也在使用浮点数组,这是我建议的(如果你使用字节进行计算,你会在声音中出现很多混叠)。

F#可能是一个不错的选择,因为它非常适合操作函数。函数可能是信号创建和处理的良好构建块。

F#还擅长处理集合,尤其是数组,这要归功于Array模块中的高阶函数。

这些品质使F#在金融行业很受欢迎,我想对信号处理也很有用。

Visual F#2010 for Technical Computing有一节专门介绍傅立叶变换,它可能与您想要做的事情有关。不过,我想网上有很多关于傅立叶变换的免费信息。

最后,要播放示例,可以使用XNA。我认为最新版本的API(4.0)也允许录音,但我从未使用过。Xbox上有一款著名的音乐编辑应用程序,名为ezmuse+Hamst3r Edition,它使用XNA,所以这绝对是可能的。

关于缓冲和异步/线程/同步问题,我建议您查看新的TPL数据流库。凭借其块基元、并发数据结构、数据流网络、异步消息处理和TPL的基于任务的抽象(可与async/await C#5特性一起使用),它非常适合这类应用程序。

我不知道这是否真的是你想要的,但这是我在大学时的个人项目之一。直到我自己实现了声音和DSP,我才真正理解它是如何工作的。我试图尽可能接近演讲者,所以我只使用libsndfile来处理复杂的文件格式

基本上,我的第一个项目是创建一个大的double数组,用正弦波填充它,然后使用sf_writef_double()将该数组写入一个文件,以创建我可以播放的内容,并在波形编辑器中查看结果。

接下来,我在正弦调用和写调用之间添加了另一个函数,以添加效果。

通过这种方式,你可以开始使用非常低级别的振荡器和效果,你可以立即看到结果。另外,让这样的东西工作起来只需要很小的代码。

就我个人而言,我会从你能找到的最简单的解决方案开始,然后慢慢添加。试着只写一个文件,然后用你的音频播放器播放它,这样你就不必处理音频api了。只需使用单个数组即可启动,并在适当的位置进行修改。一定要从单线程开始。随着项目的发展,您可以开始转向其他解决方案,如管道而不是数组、多线程或使用音频API。

如果你想创建一个可以交付的项目,具体取决于它是什么,你可能不得不转移到更复杂的库,比如一些实时音频处理。但是,当你达到这一点时,通过以上简单的方法学习的基本知识肯定会有所帮助。

祝你好运!

我做了很多实时DSP,尽管没有音频。虽然您的想法(不可变缓冲区)和(可变缓冲区就地修改)中的任何一个都可以工作,但我更喜欢为信号路径中的每个链接创建一个永久缓冲区。大多数效果都不适合就地修改,因为每个输入样本都会影响多个输出样本。当您有重新采样阶段时,每种链接技术的缓冲区工作得特别好。

这里,当样本到达时,第一个缓冲区被覆盖。然后,第一滤波器从其输入缓冲器(第一缓冲器)读取新数据,并写入其输出(第二缓冲器)。然后它调用第二个阶段从第二个缓冲区中读取并写入第三个缓冲区。

这种模式完全消除了动态分配,允许每个阶段保留可变数量的历史(因为效果需要一些内存),并且在重新排列路径中的过滤器方面非常灵活。

好吧,我也要试试赏金:)

事实上,我的处境非常相似。我制作电子音乐已经很长时间了,但直到最近几年我才开始探索实际的音频处理。

你提到你研究过数学。我认为这是至关重要的。我目前正在努力完成Ken Steiglitz的《数字信号处理入门——数字音频和计算机音乐的应用》。如果你不知道你的复数和相量,这将是非常困难的。

我是一个Linux爱好者,所以我已经开始在C中编写LADSPA插件。我认为从这个基本级别开始,真正了解发生了什么是很好的。如果我在Windows上,我会从Steinberg下载VST SDK,并编写一个快速的概念验证插件,只会添加噪音或其他东西。

选择像VST或LADSPA这样的框架的另一个好处是,您可以立即在普通音频套件中使用插件。将您的第一个自制插件应用于音轨的满足感是无与伦比的。此外,您还可以与其他音乐人共享您的插件。

在C#/F#中可能有一些方法可以做到这一点,但如果您计划编写VST插件,我建议使用C++,以避免任何不必要的开销。这似乎是行业标准。

在缓冲方面,我一直在使用循环缓冲区(这里有一篇很好的文章:http://www.dspguide.com/ch28/2.htm)。一个很好的练习是实现有限响应滤波器(Steiglitz称之为前馈滤波器)——这些滤波器依赖于缓冲,玩起来很有趣。

我在Github上有一个repo,里面有一些非常基本的LADSPA插件。撇开架构差异不谈,它们可能对编写VST插件的人也很有用。https://github.com/andreasjansson/my_ladspa_plugins

示例代码的另一个好来源是CSound项目。里面有大量的DSP代码,该软件主要针对音乐家。

从阅读这个和这个开始。

这会让你知道你必须做什么。

然后,学习DirectShow架构-并学习如何不这样做,而是尝试创建它的简化版本。

p>您可以看看BYOND。它是一个用C#进行程序化音频/midi乐器和效果创建的环境。它可以独立使用,也可以作为VST指令和效果使用。

完整披露我是BYOND的开发人员。