抽象层破绽:Behringer Wing 混音器与 DigiMixer 的技术适配挑战
当抽象层破绽:Behringer Wing 混音器与 DigiMixer 的集成挑战
在我撰写上一篇 DigiMixer 预览文章时,正在等待最新混音设备 Behringer Wing Rack 的到货。几天后设备抵达,我很高兴地宣布它很快便与 DigiMixer 完成了集成(现已成为我的主力混音器)。虽然大部分集成过程一帆风顺,但 Wing 的某个特性却无法完美契合抽象模型——这使其成为博客文章的绝佳题材。
Wing 输出通道的抽象困境
现实世界(与课程中人为设计的示例不同)中,抽象层时刻面临细微的破裂。世界无法如我们期望的那样完美契合预设框架。关键在于区分故意丢失细节的抽象与真正的抽象层"破绽":前者忽略了对当前使用场景不重要的细节,而后者无法呈现我们真正关心的方面。
以 DigiMixer 为例,它对混音器功能进行了高度抽象:不尝试建模混音路由、可应用的效果器,或输入配置(如前置放大器增益、微调、立体声平衡等)。这些抽象都是合理的。尽管 Wing 拥有大量未被抽象层捕获的功能,但这并不构成问题。
真正的破绽出现在抽象层无法表现我们关心的核心特性时。对于 Wing 而言,这个问题体现在主输出通道上。让我们回顾之前提到的通道模型:
每个通道包含:
名称
推子电平(输入通道为"每个输出通道一个推子电平"),可由应用程序控制
静音状态,可由应用程序控制
计量信息(当前输入/输出电平)
音频信号路径解析
为了更好地理解问题,需要明确音频信号的工作机制。假设一个简单混音器:两个输入,一个主输出(暂忽略单声道/立体声区别)。
我们将有三个物理推子:
输入 1 推子
输入 2 推子
输出推子
这意味着当麦克风接入输入 1,电吉他接入输入 2 时,你可以:
通过调整输入推子改变人声与吉他的平衡
通过调整输出推子改变整体音量
同时存在三个静音按钮:每个输入一个,输出一个。如果麦克风产生反馈,可以单独静音(保持吉他 audible),或通过输出静音切断所有声音。
若有两个输出(主输出和辅助输出),逻辑上需要六个推子:
输入 1 到主输出的信号推子
输入 1 到辅助输出的信号推子
输入 2 到主输出的信号推子
输入 2 到辅助输出的信号推子
主输出推子
辅助输出推子
这种为不同输出配置不同输入电平的能力在实际场景中极为重要。例如在教堂应用中:一个麦克风采集会众歌声发送到 Zoom,但不需要在教堂建筑内放大;某人讲话时可能在建筑内放大更多,或在 Zoom 中放大更多。
Wing 的 Main LR 与 Main 1-4 通道问题
Behringer Wing 拥有 48 个立体声输入通道和 20 个立体声输出通道(简化模型,忽略矩阵混音等复杂功能)。输出分为四个主通道(M1-M4)和 16 个总线通道(B1-B16)。每个输出都有各自的输入推子序列、总输出推子和静音按钮——至此一切正常。
但"Main LR"通道出现了问题。
"Main LR"听起来应该是个常规立体声主输出通道(通道 ID 100 和 101)。每个输入都有对应 Main LR 的推子——这部分工作正常。
但 Main LR 本身并不是一个真正的输出通道:它没有自己的"总"推子、没有静音按钮、没有计量表、无法路由到任何设备。通过推子调整的输入电平会应用到所有 M1-M4 通道,之后还会被输入到 M1-M4 的推子再次调整。
因此,如果一个输入信号通过 M1 发送到扬声器,有三个推子可以调整其电平:
该输入的 Main LR 推子
该输入的 M1 推子
总 M1 推子
该场景下有两个静音选项:
输入静音
M1 静音
DigiMixer 中的 Main LR 处理
所有这些都可以在 DigiMixer 中表示——我们可以为 Main LR 添加一个"虚拟"输出通道,这样做确实有用(如 X-Touch Mini 上的旋转编码器控制的"主输入"推子)。
但随之产生了三个在混音器上没有实际对应物的 UI 元素:
Main LR 总推子
Main LR 计量表
Main LR 静音按钮
抽象层缺乏足够的粒度来表示这种"仅用于输入推子的输出通道"概念。这三个多余的元素在 DigiMixer 中显示为无用的 UI 组件。
解决抽象层破绽的三种方案
方案一:忽略问题
UI 会显示从不更新的计量表,以及看似可用但实际上不调整混音器的推子和静音按钮。但所有应该工作的 UI 元素都能正常工作,这比完全缺少 Main LR 通道(会减少功能)要好得多。
有时忽略问题是完全合理的——需要权衡抽象破绽的实际影响与解决成本。这时需要考虑对抽象使用方式的了解程度:DigiMixer 应用程序(全由我编写)是抽象层的唯一消费者,我可以推理破绽的所有影响。
方案二:扩展抽象
让 DigiMixer 核心抽象提供更多信息并不困难:只需更新 DetectMixerConfiguration 返回的 MixerChannelConfiguration,包含更多每通道详细信息。但这只是起点:这些信息需要被中间层使用,并再次暴露给应用层。
我担心的是未来可能出现的其他变化:为完美适配 Wing 而扩展抽象,可能在未来其他混音器以不同方式破坏模型时增加困难。我倾向于等待更多数据点后再做决定。
方案三:接受漏洞(当前选择)
我选择在底层保持抽象破绽,仅在应用层解决问题。已有的 WPF 用户控件通过数据绑定可以轻松条件化静音和计量表的可见性。推子处理稍复杂,因为 DigiMixer 应用有两种模式:按输出分组输入,或按输入分组输出。
关键是如何为视图模型提供正确信息。我采用了直接检测硬件类型的方案:
这段代码违反了抽象的核心原则——视图模型不应该知道或关心它在与什么硬件交互!但它确实有效。
这不是通用的正确方法,但有时很实用。这是我故意承担的技术债务,希望未来能有更多信息指导转向方案二。
结论
我一直希望 DigiMixer 能展示抽象层的现实问题与整洁面。没想到在上篇文章后这么快就获得了如此清晰的案例。
在下一篇文章中(如果一切按计划),我将探讨一个听起来简单但花费我很长时间才找到当前解决方案的设计挑战:我们将一起研究推子和计量表的"单位"问题。希望那会比这段描述听起来更有趣...更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)公众号二维码

评论