我目前正在开发一个个人项目:在Flash中创建一个用于实时音频合成的库。简而言之:用于连接波形发生器,滤波器,混频器等的工具,并为声卡提供原始(实时)数据。比如max / msp或Reaktor。
我已经有一些工作,但我想知道我写的基本设置是否正确。我不想在以后遇到问题迫使我改变我的应用程序的核心(虽然这总是会发生)。
基本上,我现在所做的是从链的末尾开始,在(原始)声音数据“跳出”(到声卡)的地方。要做到这一点,我需要将一块字节(ByteArrays)写入一个对象,并获得该块,我要求连接到我的'Sound Out'模块的任何模块给我他的块。该模块对连接到其输入的模块执行相同的请求,并且一直持续到链的开始为止。
这是正确的做法吗?如果有反馈循环,或者如果有另一个模块没有输出,我可以想象遇到问题:如果我要在某处连接一个spectrumanalyzer,那将是链中的死胡同(一个没有输出的模块,只是一个输入)。在我目前的设置中,这样的模块无法工作,因为我只从声音输出模块开始计算。
有没有人有这样的编程经验?我对正确方法的一些想法非常感兴趣。 (为清楚起见:我不是在寻找特定的Flash实现,这就是为什么我没有在flash或actionscript下标记这个问题)
答案 0 :(得分:1)
我前段时间做了类似的事情,我使用了与你相同的方法 - 从虚拟线开始,并将信号追溯到顶部。我按照每个样本做了这个,而不是每个缓冲区;如果我今天要编写相同的应用程序,我可能会选择per-buffer,因为我怀疑它会表现得更好。
光谱仪被设计为插入模块,也就是说,它只有在输入和输出都连接的情况下才能工作,它会将输入传递给输出。
为了处理反馈,我有一个特殊的辅助模块,它引入了1个样本的延迟,并且每个周期只能获取一次输入。
另外,我认为使用浮点数进行所有内部处理,因此浮点数组作为缓冲区,比字节数组容易得多,并且它可以节省您在整数和浮点数之间进行转换的额外工作量
答案 1 :(得分:0)
在以后的版本中,您可能在网络的不同部分使用不同的数据包速率。
一个例子是扩展它以将数据传输到磁盘或从磁盘传输数据。另一个例子 可能是低数据速率控制变量(例如一个控制回声延迟)可能会在以后成为您网络的一部分。您可能不希望以与处理音频数据包相同的频率处理控制变量,但它们仍然是“实时”并且是功能网络的一部分。例如,他们可能需要平滑以避免突然过渡。
只要您以相同的速率调用所有函数,并且所有函数基本上都是恒定时间,那么您的数据拉取方法将正常工作。这里将 在拉数据和推送之间做一点选择。拉动对于播放音频来说更自然一些,推送对于录制来说更自然一些,但是无论是工作还是最终对底层音频处理功能进行相同的调用。
对于光谱仪,您已经拥有了 多个接收器的问题 数据,但这不是问题。 从中引入虚拟链接 真正的水槽。虚链接可以 导致请求不是的数据 荣幸。只要虚拟链接知道 它是一个假人而不关心 缺乏数据,一切都会如此 好。这是一种将多个接收器或源减少到一个接收器的标准技术。
使用这种网络,您不希望在一次完整更新中执行两次相同的计算。例如,如果混合信号的高通和低通版本,则不希望两次评估原始信号。您必须执行某些操作,例如使用每个缓冲区记录计时器刻度值,并在看到当前刻度值已经存在时停止拉取传播。同样的机制也可以保护您免受评估中的反馈循环。
因此,您可以在当前框架内轻松解决您关心的两个问题。
速率匹配 如果网络的不同部分存在不同的数据包速率,则会启动当前方法的问题。如果您正在将音频写入磁盘,那么为了提高效率,您需要不经常写大块。在这些写入期间,您不希望阻止对更频繁的小型音频输入和输出处理数据包的服务。单凭拉动或推动策略本身是不够的。
请接受,在某些时候,您可能需要比单速率网络更复杂的更新方式。当发生这种情况时,您将需要运行不同速率的线程,或者您将编写自己的简单调度程序,可能就像在n中调用不常用的评估函数一样简单,以使速率匹配。您无需为此提前计划。您的音频功能几乎肯定已经承担了确保其输入缓冲区已准备好用于其他功能的责任,并且它只是那些需要更改的其他功能,而不是音频功能本身。
我在这个阶段建议的一件事是小心集中音频缓冲区 分配,注意缓冲区就像fenceposts。它们不属于音频 功能,它们位于音频功能之间。集中缓冲区分配将使在网络的不同部分以不同的速率回溯修改更新策略变得容易。