TouchDesigner 摇摆光束灯控制与视觉同步系统

项目版本: v2.4 Live Sync 目标设备: Ableton Push2 & Beam Light 通信协议: DMX512 / Art-Net / WebSocket

一、 系统总体信号链路拓扑 (System Topology)

本工程采用“MIDI 触发门控锁存”、“Push2 8轴物理手感包络算法”与“DMX 8位数值标定输出”三大核心模块并行协同架构:

[MIDI / Ableton 硬件输入 (midiin1)]
       │
       ├─> [门控选择器 (select_long / select_short / select_beam / select_reset / select2)]
       │         │
       │         ▼
       │   [CHOP Execute 事件回调脚本 (chopexec_*)]
       │         │
       │         ▼
       │   [状态锁存与模式切换 (target_* / switch_* / gate_* / override_mode)]
       │         │
       │         ├─> [实时写入通信文件 (send_gates -> Gates.json)]
       │         └─> [音频门控切分 (audio_long / audio_short -> audiodevout*)]
       │
       └─> [Push2 8轴力感打击垫 (final_punch ~ final_float)] (0.0 - 1.0)
                 │
                 ▼
           [Physical Envelope 状态机算法 (beam_pad_effects / Script CHOP)]
                 │
                 ▼ (生成 chan1 ~ chan5 0.0 - 1.0 物理包络)
           [Override 信号融合 (override1 / Override CHOP)]
                 │
                 ▼ (替换 chan1~chan5,透传 chan6~chan13,组合成 13 通道 0.0 - 1.0 信号)
           [DMX 8位数值标定器 (math2: Multiply 255)]
                 │
                 ▼ (转换为 0 - 255 DMX 标准整型)
           [Art-Net / DMX 硬件输出 (dmx_out)] ──> 【现场物理摇摆光束灯 (Beam Light)】

二、 Physical Envelope 状态机物理算法 (`beam_pad_effects`)

该模块基于 Script CHOP 实现,负责将 Ableton Push2 打击垫的 8 轴力感输入转换为光束灯的物理包络动作,并保证与前端墙面视觉 (SoloEffects.ts) 毫秒级对齐。

1. 核心状态机算法 (`step_pad`)

  • 触发判定 (Onset):当原始输入 raw > 0.02 时,瞬间拉满包络 env = 1.0,记录 onsetTime 触发时间戳。若为 wring 效果,则翻转正反向标志位 dirSign。
  • 去抖窗口 (Release Debounce):当按压释放后,引入 RELEASE_DEBOUNCE_MS = 70 毫秒的去抖保持期,防止手抖引发的多次误触发。
  • 指数级帧率归一化衰减:去抖结束后,按公式 env *= 0.82 ** (dt_ms / 16.67) 进行指数衰减,低于 0.015 时强行归零,确保不同帧率(掉帧)下手感绝对恒定。

2. 8 种手感物理模型 (FX Functions)

  • punch (频闪冲击):调光 ch3 = env 拉满,触发灯具自带高频频闪 ch4 = 0.75 * env,基于 onset 伪随机种子产生瞬时轴向冲击 ch1_offset。
  • slash (侧抛甩击):持续 480ms,以 (1 - p)^0.85 幂次陡峭衰减,产生较大幅度摆动偏移 ch1_throw 及电机颤抖 ch2_jitter。
  • press (缓升压感):使用 hold_ramp 缓升包络 1 - exp(-dt / 400ms),驱动亮度 ch3 在 0.4 ~ 1.0 之间平滑增强。
  • wring (正反扭转摆频):强度按 Ramp 缓升,叠加 6Hz 正弦波摆动 wobble 及颤抖 ch2_jitter,每次触发自动翻转 ch5(正转/反转)。
  • dab (轻触点亮):140ms 超短衰减,亮度最高达 0.6,伴随极小幅度轴向偏移。
  • flick (侧甩闪击):前 35ms 产生高亮闪烁,伴随反向侧甩偏移 ch1_offset 与电机抖动。
  • glide (限制压感):与 press 类似的 Ramp 缓升包络,但亮度上限被封顶限制在 0.5(cap=0.5)。
  • float (正弦漂浮):连续正弦波漂浮摆动,驱动 ch1 大范围摇摆、ch3 呼吸调光及 ch2 微幅漂移。

3. 多力效多通道融合逻辑

  • 调光/频闪通道 (ch3 / ch4):采用 Max Pooling(最大值胜出) 算法,即 ch3 = max(contribs),防止多个打击垫同时按压时叠加爆表。
  • 位置/抖动通道 (ch1 / ch2):采用 Vector Sum(矢量叠加) 算法,在中心点 0.5 基础上求和,即 ch1 = clamp01(0.5 + sum(ch1_offset)),模拟多个物理力同时作用于机械轴。
  • 旋转方向通道 (ch5):响应最后一次触发的 wring 旋转状态,无触发时默认保持正向(CH5_FORWARD = 0.25)。

三、 完整 13 通道 DMX 计算与数值映射表 (DMX Channel Map)

光束灯控制通道在 TD 中经 Override CHOP 融合后,统一在 math2 (Math CHOP) 节点乘以 255,转换为 0 ~ 255 标准 8 位 DMX 帧:

DMX 通道 信号来源 原始数值范围 Math2 标定 最终 DMX 值 物理灯具控制功能描述
chan1 beam_pad_effects 0.0 ~ 1.0 × 255 0 ~ 255 (中点 127.5) Pan 水平摇摆行程(0.5 对应物理居中)
chan2 beam_pad_effects 0.0 ~ 1.0 × 255 0 ~ 255 (中点 127.5) Pan Fine 微调/高频 Jitter
chan3 beam_pad_effects 0.0 ~ 1.0 × 255 0 ~ 255 Dimmer 总调光亮度(0 为关,255 为最亮)
chan4 beam_pad_effects 0.0 ~ 1.0 × 255 0 ~ 255 Strobe 频闪速率(灯具硬件频闪发生器)
chan5 beam_pad_effects 0.25 / 0.75 × 255 64 / 191 Motor Dir 电机转向(<128 正转,>128 反转)
chan6 beam_channels (透传) 0.0 ~ 1.0 × 255 0 ~ 255 Color Macro 色彩宏/前景色选色表
chan7 beam_channels (透传) 0.0 ~ 1.0 × 255 0 ~ 255 Gobo 图案片选择/旋转
chan8 beam_channels (透传) 0.0 ~ 1.0 × 255 0 ~ 255 Prism 棱镜展开/旋转
chan9 beam_channels (透传) 1.0 (基准) × 255 255 Red 红色通道(满功率输出)
chan10 beam_channels (透传) 1.0 (基准) × 255 255 Green 绿色通道(满功率输出)
chan11 beam_channels (透传) 1.0 (基准) × 255 255 Blue 蓝色通道(满功率输出)
chan12 beam_channels (透传) 1.0 (基准) × 255 255 White 白色通道(满功率输出)
chan13 beam_channels (透传) 0.0 (基准) × 255 0 ~ 255 Lamp Control / Reset 复位与控制宏

四、 CHOP Execute 事件回调逻辑 (`chopexec_*`)

系统通过 5 个 CHOP Execute DAT 节点实时监听硬件 MIDI 通道(On Off to On 上升沿),控制全局状态及信号路由:

1. `chopexec_long` (长触发门控)

监听节点: select_long

def onOffToOn(channel, sampleIndex, val, prev):
    op('target_long').par.value0 = 1
    return

2. `chopexec_short` (短触发门控)

监听节点: select_short

def onOffToOn(channel, sampleIndex, val, prev):
    op('target_short').par.value0 = 1
    return

3. `chopexec_beam` (光束模式 Toggle 开关)

监听节点: select_beam

def onOffToOn(channel, sampleIndex, val, prev):
    c = op('target_beam')
    c.par.value0 = 1 if c.par.value0 == 0 else 0
    return

4. `chopexec_reset` (紧急复位)

监听节点: select_reset

def onOffToOn(channel, sampleIndex, val, prev):
    op('target_long').par.value0 = 0
    op('target_short').par.value0 = 0
    return

5. `chopexec_override` (手动覆盖 Toggle 开关)

监听节点: select2

def onOffToOn(channel, sampleIndex, val, prev):
    c = op('override_mode')
    c.par.value0 = 0 if c.par.value0 == 1 else 1
    return