使用 Pd 管理音频
Pure Data (Pd) 是一个用于音频和其他多媒体应用程序的实时可视化编程环境。 您可以使用它制作对音频和视频数据执行操作的补丁。 这些补丁以可视化方式表示;您“绘制”您希望信号数据流向的位置以及您希望对其执行的操作。 此过程类似于您如何编程模块化模拟合成器。 此过程也非常适合您最终如何编程声音和视频应用程序;信号输入和输出,您在此过程中操作各种信号。 由于篇幅限制,本文仅涵盖 Pd 中更成熟的音频功能。 如果您以后想尝试视频处理插件,您应该会发现许多概念与音频的概念相似。
Pd 使用两种主要类型的数据:消息和音频信号。 消息是零星的,就像 MIDI 音符事件一样。 它们可以包含数字或字符串,用于传递信息,例如“将输出的增益设置为 x”。 音频信号是恒定的;只要 DSP 代码打开,音频就会被传输。 在 Pd 内部,音频由 32 位浮点数表示。 这意味着与传统的模拟或数字声音处理不同,Pd 信号可以具有您想要的几乎任何幅度。 在处理过程中,您可以使音频信号在一个阶段非常安静,并在另一个阶段放大它,而不会损失质量。 当然,当信号发送到硬件输出时,您必须确保它在 -1 到 1 的可用范围内,否则音频会被削波。
这些消息和音频信号由下面描述的各种类型的框进行操作。 当放在一起时,这个连接框的集合称为补丁。
框完成所有工作。 Pd 有四种主要类型的框:对象、消息、GUI 和注释。 这些框对消息和音频执行操作,提供用户输入的方式并记录已完成的操作。 对象框又分为两种类型:控制对象和波浪号对象。 控制对象处理消息,因此零星地执行其功能。 波浪号对象处理音频数据,并不断执行其功能。

图 1. 对象框
消息框在用户单击它们或在它们的输入端接收到消息时,将其内容发送到它们的输出端口。

图 2. 消息框
GUI 仅指您可以与之交互的框,例如左侧的数字框。

图 3. GUI 框
最后,注释允许您将文本放入补丁中。 它们实际上不影响任何内容。

图 4. 注释框
假设您现在已经编译并安装了 Pd,您应该尝试启动它。 首先,确保您已在 Pd 可执行文件上设置了 setuid 位,并确保它归 root 所有。 虽然这可能存在安全风险,但如果您想以 root 以外的任何用户身份运行 Pd,您需要执行此操作以启用实时调度。 如果您不这样做并且未激活实时调度,那么每当任何其他进程(甚至是 X 服务器)尝试执行任何操作时,您都会听到很多咔哒声和噼啪声。
使用 -rt 选项和您设置中需要的任何其他选项运行 Pd。 我建议使用 -verbose,因为 Pd 本身不是很健谈,而 verbose 选项确实提供了一些有用的信息。 完成后,您应该会看到类似于图 5 所示的窗口。 IN 和 OUT 框分别是输入和输出的峰值表,可以通过单击峰值表选项来启用。 如果任何一个削波,相应的 CLIP 框将变为红色。 如果输入或输出中存在任何同步错误,DIO 错误按钮会闪烁。 单击它以查看最近错误的列表。 最后,compute audio 复选框打开或关闭音频处理。

图 5. 主窗口
首先,让我们创建一个新的空白补丁以进行工作(文件→新建)。 从这里我们将创建一个简单的补丁,将“Hello World!”打印到标准输出。 因此,我们需要一个消息框来保存消息“Hello World!”和一个对象框来执行打印操作。 这两个都可以从“放置”菜单创建。 您也可以使用快捷键:Crtl-1 放置对象框,Crtl-2 放置消息框。 完成后,要在框中输入正确的文本,请单击它们并键入。 您还需要将消息框底部的出口端口连接到对象框顶部的入口端口。 您的补丁应该如图 6 所示。 按 Crtl-E 退出编辑模式。 现在尝试单击“Hello World!”消息框;如果一切顺利,一条消息会打印到您启动 Pd 的终端中。

图 6. 标准“Hello World!”示例
现在,让我们尝试一个更复杂的示例,制作一个将两个数字相加并显示结果的补丁。 制作一个如图 7 所示的补丁,顶部使用两个数字框,中间使用一个对象框,底部使用一个数字框。 接下来,退出编辑模式(再次按 Crtl-E),并尝试更改顶部的数字。 您可以通过单击并键入或单击并拖动来执行此操作;向上移动以增加数字,向下移动以减少数字。 正如您可能已经注意到的,更改左侧的数字会使总和立即更改,但更改右侧的数字不会执行任何操作。 为什么?

图 7. 相加两个数字
Pd 中几乎所有对象都将其最左侧的入口视为热入口,这意味着其值的任何更改都会立即影响输出。 其他入口是冷入口。 其值的更改不会触发输出中的任何更改。 新值只是放入存储中,直到热入口触发计算,此时将使用新值。
但是,如果您确实希望冷出口中的更改触发输出中的更改怎么办? 一种实现此目的的方法是插入一个消息框。 在图 8 中,我将右侧数字框的出口连接到消息框的入口。 然后,该消息框的出口连接到下面加法对象框的热入口。 当消息框在其入口处接收到任何消息时,它们会将所有内容作为新消息发送到其出口。 因此,当最右侧的数字框更改时,它会向 bang 消息框发送消息,然后 bang 消息框向下面的加法对象框发送 bang 消息。 Bang 消息的意思是“执行某些操作!”,因此任何在其热入口处接收到 bang 消息的对象框都会立即执行它被告知要执行的任何计算。 我们在这里使用此行为使我们的加法对象框的行为就像它有两个热入口一样。

图 8. 处理热和冷的幼稚方法
但是等等,这是否意味着 bang 消息必须在数字之后到达? 如果没有,补丁将无法工作,对吗? 嗯,是的;根据您建立连接的顺序,您可能已经注意到它不起作用。 实际上,在图 8 中,数字没有精确相加,正是由于这个问题。 因此,我们需要一种方法来确保 bang 消息在数字之后到达。 一种简单的方法是插入延迟,如图 9 所示。 有趣的是,延迟 0 实际上有效。 消息只是延迟一个 DSP 周期,从而确保 bang 消息第二个到达。

图 9. 正确处理热和冷
最基本的音频功能是输入和输出。 adc~ 波浪号对象(代表模数转换器)执行第一个任务;而 dac~ 对象(数模转换器)执行第二个任务。 默认情况下,这两个对象都在前两个通道上运行。 如果您想更改此设置(例如,如果您有 Hammerfall HDSP 等多通道声卡),您可以输入通道号作为参数,然后相应的通道将映射到其相应的入口或出口。 图 10 显示了一个简单的示例,其中立体声输入被翻转并路由到输出。 由于立体声输入是默认设置,因此示例中的通道号是冗余的,但无论如何我们都将其包含在内以进行演示。

图 10. 在立体声信号中翻转左右声道
声音数据是特定采样率下的数字序列,因此可以将算术运算符应用于声音数据。 您所要做的只是在您要使用的运算符末尾添加一个波浪号。 例如,图 11 通过将左右声道加在一起将立体声信号转换为单声道信号。 另一个有用的运算符是乘法 *~,它充当增益控制。 但是请记住,如果信号超出 -1 和 1 的值,则在输出到硬件时信号会被削波。

图 11. 将立体声转换为单声道
图 12 显示了一个更复杂的示例。 您可能需要在运行此示例之前将扬声器调低一些,因为它声音很大。 首先,顶部的 osc~ 对象是正弦波发生器,在本例中以 440Hz 运行。 此信号分为两个,左侧直接进入加法,右侧首先通过乘法。
现在尝试在数字框中输入 -1。 声音停止了,为什么? 如果您还记得高中时的波动物理学,您就会知道波可以相互抵消。 在这种情况下,-1 创建了原始信号的完美逆信号。 因此,当原始信号为 1 时,逆信号为 -1。 当您将这两个信号加在一起时,您会得到 0,即静音。 您也可以尝试按住 Shift 键并在数字框上拖动;数字应该变化得足够慢,以便您可以听到声音在接近 -1 时逐渐变小,然后最终停止。

图 12. 使用反转来抵消两个信号
让我们将这些组件组合在一起,并尝试用它们做一些有用的事情; 让我们制作一个简单的混响滤波器,使用上述技术和一个新技术,即延迟线。 如果您已经有设计音效的经验,您可能知道什么是延迟线; 如果不知道,可以将其视为声音的缓冲区。 进入延迟线入口的声音会在存储一段固定的时间后再次输出。 各种复杂的技术已被用于在模拟领域实现延迟线,其中一些涉及特殊的弹簧和磁带环。 对我们来说幸运的是,我们正在处理数字信号,其中延迟线可以用 FIFO(先进先出)缓冲区来实现。
混响是一种自然现象,当声音从其环境中的表面反射时会产生这种现象。 由于距离增加,这些反射会在听到初始声音后稍晚到达。 这些反射的声音也会被反射。 大多数环境都有一定程度的混响,事实上,在音乐厅中,精心控制的混响水平是一个广受欢迎的功能。 没有混响的房间会让人感到不舒服,因为您发出的每一个声音都好像是从空气中抓出来的一样。
此滤波器的核心是延迟线。 图 13 显示了一个延迟线,它向声音输入添加了一秒(1,000 毫秒)的延迟。 Pd 中的延迟线是命名的,这意味着要使用延迟线,您需要两个单独的对象,一个写入器和一个读取器。 写入器 delwrite~ 接受两个参数:第一个是延迟线的名称,第二个是您要使用的最大延迟(以毫秒为单位)。 每个延迟线只能有一个写入器。 第二部分是读取器 delread~,它也接受两个参数:延迟线的名称和您想要的延迟量。 与写入器部分不同,您可以拥有任意数量的读取器,并具有您想要的任何延迟时间。 另一种类型的读取器,即可变延迟对象 (vd~),可以响应音频信号而更改其延迟,但这超出了本文的范围。

图 13. 延迟线
回顾一下,混响滤波器需要一个直通信号路径(主信号)和一个或多个延迟信号路径(混响)。 混响是递归的,因此系统中需要某种形式的反馈。 最后,虽然我们的输入和输出是立体的,但为了节省空间,我们只实现单声道混响滤波器。 为此,传入的左右声道需要混合在一起,并在另一端分开。 图 14 显示了这样的滤波器。 如果我们从输入端跟踪信号补丁,您首先应该注意到的是 *~ 1 对象。 包含此对象是为了使补丁更简洁一些。 它将信号乘以 1,这本身是无用的,但它也为我们提供了一个入口来连接左右声道并将它们混合成一个。 您可以在补丁的底部看到类似的结构。 然后,混响信号被发送到另一个乘法器以衰减混响,然后再进行另一个混响循环。 delwrite~ 和 delread~ 形成一个混响循环。 最后,乘法器的出口被发送回 dac~。

图 14. 简单的混响滤波器
确保您要使用的 MIDI 设备(最好是 Evolution UC-16 等控制设备)当前正在工作。 验证 Pd 是否正在接收 MIDI 事件的一种简单方法是转到任何窗口右上角“帮助”菜单中的“测试音频和 MIDI”菜单项。 打开它们并生成一些 MIDI 事件。 如果您的控制器工作正常并发送控制消息(而不是音符事件),您应该会看到窗口底部 ctlin(控制输入)对象下的数字发生变化。 您可能需要使用 -midi 命令行参数来使 Pd 正常工作;此外,请务必使用 verbose 选项阅读 Pd 启动时显示的调试消息。
如果这一切都有效,请尝试图 15 所示的补丁。 它与图 14 中的混响补丁相同,只是混响和延迟现在由 MIDI 而不是 GUI 控制。 此切换是通过 ctlin 对象实现的,该对象在本例中采用一个参数,即您要使用的控件的控制器编号。 输出是来自控制器的原始值。 假设您使用的是 UC-16 或类似的控制器,这是一个从 0 到 127 的值。 其他对象需要对此值进行一些数学运算才能使其进入所需的范围。 在混响的情况下,我们想要的范围是 0 到 1,000,因此我们除以 127 以获得 0 到 1 之间的值,然后乘以 1,000 以获得最终值。 对于衰减,0 到 1 的值是好的,因此我们只需要除法。 在视觉上反馈您的效果设置的值是一个好习惯,因此此补丁将混响和衰减的副本发送到标记为此目的的数字框。

图 15. 使用 MIDI 控制补丁
这就是您所拥有的——一个完全计算机化、MIDI 控制的声音效果,仅由几个连接在一起的 Pd 对象制成。 这仅仅是可能性的开始。 有 MIDI 键盘吗? 您可以将其用作控制设备,并制作一个实际合成音符的补丁。 或者,制作一个补丁来控制 MIDI 键盘。 您甚至可以制作一个完整的可重新编程的效果器盒。 此外,您不必满足于 Pd 中的现有对象;您可以使用 C 甚至 Pd 本身编写自己的对象。 借助 Linux 和 Pd,唯一的限制是您的技能和 CPU 的速度。
本文中的所有示例都可以从 Linux Journal FTP 站点 ftp.linuxjournal.com/pub/lj/listings/issue116/7062.tgz 获取。
Peter Todd 从 14 岁起就开始使用 Linux。 他在一家小型基于 Linux 的录音棚兼职担任首席技术员。 当他不工作时,他在 Wexford Collegiate 上学,目前在那里学习陶瓷和平面设计。