效果处理器:关于软件架构,编程语言选择,API

时间:2016-02-05 21:45:42

标签: architecture signal-processing real-time low-latency jack

我目前正在开展一个项目,其中一个主要元素是一个可以实时进行信号处理的软件。

基本思想/概念如下。从(USB)音频接口(以96 kHz,24位运行)连续捕获音频数据。然后它通过一个"处理链" (如"虚拟效果链"),其中每个元素可以对数据执行任意处理。数据从一个元素传递到下一个元素,直到它到达接收器。流入接收器的数据被发送回音频接口以进行输出。

信号链由"对象组成"实施一些"处理"方法,适用于1920个样本(20毫秒)大小的数据块(尽管可能会更改此数字)。

"伪代码"。

中的基本思想
while (true) {
   float[] samples = audio.read(BLOCK_SIZE);

   foreach (Effect e in signal_flow)
      e.process(samples);

   audio.write(samples);
}

第一个原型已经在Python中实现,它使用ALSA API进行音频I / O.启动了三个单独的线程。

第一个是从ALSA连续读取(这是一个阻塞操作)并将数据放入队列,然后继续读取下一个块。 (ALSA要求我至少每隔20毫秒阅读(...)"所以我需要一个非常轻量级的线程,除了读取和存储数据之外什么都不做,所以我可以满足我的时间约束。)

第二个从该队列的输入中读取样本,将它们放入信号链,最后进入另一个队列进行输出。

第三个线程从此输出队列(这是阻塞操作)读取并将块写入ALSA。

我基本上有两个"数字"这里的变量,一个是块大小,另一个是I" pre-post"在我开始处理之前到输出队列,这给了我一些时间来提供更多样本"没有输出缓冲区欠载。另外,我可以决定在单独的线程中或在单独的进程中执行这些操作。

经过一些严肃的调试(包括使用信号发生器和示波器!),我终于开始运行这种方法。最大的问题是ALSA API中的一个错误,即" period_size",其被指定为"读取/写入的的数量"实际上似乎是读取的数量,但写入的字节数。当我为输入和输出指定1920(20毫秒音频,96 kHz采样率)时,我只得到输出的1/4,然后是3/4的静音,然后是1/4的输出。当我为输入和输出指定1920 * 4 = 7680时,我得到一个错误,即设备的缓冲区不够大,无法读取这么多帧。当我指定1920输入和7680输出时,它完美地工作(我的队列不会#34;溢出"或者)。

解决后,我遇到了一个严重的问题,那就是:延迟!

我基本上开始了整个项目以创建我自己的效果,所以我希望这个软件作为舞台/现场使用的效果单元运行。我读过当两个事件相距不到30毫秒时,e。 G。两个频闪灯相隔30毫秒发射,人类的大脑再也无法分辨出哪一个是第一个,哪个是第二个。所以30毫秒或更短的延迟基本上会被认为是"瞬间"。这是事件"合并"的门槛。并被认为是"一个"。如果延迟很低,你就无法判断哪个事件是第一个,所以e。 G。一个吉他手再也无法分辨,如果他敲击琴弦然后声音来自PA,或者声音来自PA,然后他击中了弦乐,那么它基本上会感觉像是零延迟"因此就像一个真正的放大器。

现在我已经达到的延迟是......嗯......我还没有机会准确地测量它们,但它的大小是十分之一秒,比如说200或300毫秒。太过分了!我为I / O尝试了两个单独的线程和进程(因为在Python中你永远不会知道线程是否真的会因为"全局解释器锁定而变得更快")并且进程明显变慢,这是由于与进程间通信相关的开销以及两个I / O进程不做任何事情而导致的密集期"。他们只是等待阻塞操作并执行快速I / O.

作为另一个评论,我想说我希望我的应用程序托管一个Web服务器(当然是在一个单独的线程甚至进程中),以允许用户配置信号路径并调整效果的参数和#34;装置"以直观的方式。

所以显然我需要减少延迟!我现在有几条路可以跟随。

  1. 我的第一个想法是用JACK代替ALSA,据说这是低延迟"。缺点是我失去了对ADC / DAC精确电平的控制(JACK总是与浮点数一起使用,浮点数已经缩放到[-1.0,1.0],无论硬件做什么)和过采样率(就我而言)知道,JACK"指示"采样率 - 我再也不能选择 - 使用ALSA我可以选择我想要使用的采样率,如果硬件偏离,我会透明地对我进行上采样/下采样) ,阻塞I / O(我发现一个非常好的范例)被一个回调机制所取代,并且时序约束可能更难以满足。 (我不能"缓冲"我自己使用JACK。它总是需要在一定的时间内完成处理。)此外,JACK API通常比ALSA API更复杂。我可能用JACK替换ALSA,但我不确定我能做多少"赢得",因为ALSA已经是一个漂亮的低水平" API和JACK建立在,但可能以非常具体的方式使用以保持低延迟。说实话,我并不完全确定ALSA和#34;以及"以及"更高层"。

  2. 我目前使用解释的垃圾收集语言。这对实时要求不利。但有哪些替代方案?嗯,当然在考虑实时应用程序时会想到C,但是存在严重的缺点。

  3. 2.1 - 我希望该软件具有基于Web的UI。用Python创建Web服务器很简单。 Python标准库中有一个类。在C中创建Web服务器很痛苦。在C中基本上没什么可以做" web"。除了套接字API之外,我必须从头开始。祝好运! : - (

    2.2 - Python支持数字。它有numpy和scipy,因此矢量数据类型,矩阵乘法,快速傅里叶变换,快速卷积,插值(样条等)。这对于此处的问题非常有用。在C中,我失去了所有这一切,这意味着我要么必须完成工作,这是非常不可能的,或者我必须在C中自己重新创建所有这些,这既耗时又容易出错。

    2.3 - Python有"高级"支持多处理和多线程。我可以通过同步队列在进程和线程之间进行通信,以线程池/复制工作者方式实现我的解决方案,这对于手头的问题是一个极其有用的范例这里。在C中,我不得不求助于POSIX线程和低级同步原语,如mutices。 (这是" mutex"正确的复数" Unix" - >" Unices"?)同样,这既费时又错误易发。

    有关使用哪种语言的建议?我熟悉的语言包括Python,C-Sharp,Java,C,Go,C ++的一点点(我从不需要那种语言 - 它是低级的,然后我使用C,或者它的高级,然后我使用垃圾收集,解释器或字节码编译语言),以及一些Web技术(尤其是带有AJAX的JavaScript等,当它使用它时会很有用)来到UI)。

    所有这些必须在Linux发行版下运行,最好只使用尽可能少的依赖项/库。 "标准"因此,图书馆优于“异国情调”。那些。平台独立性,尤其是在Windows下运行的能力,是一个优势,但不是严格要求。

    我可以用不同的语言实现用户界面(想想网络服务器),而不是实际处理(可能"必须完成在C"如果它需要是实时的?),虽然这带来了很多额外的复杂性,因为它们将在不同的进程中运行并通过Unix Domain Sockets进行通信,这需要传递所有数据来回表示为字节流(因为它是所有套接字传输),因此需要设计进程间通信协议并在此级别进行大量解析。有没有机会避免这种巨大的开销并用一种语言来做?

    还有其他想法吗?具体来说,从ALSA到JACK我能获得什么吗?还有其他我尚未考虑的替代方案,这可能更适合这项任务吗?

    非常感谢你的时间!

0 个答案:

没有答案