跳转至

Channel Map Module Design (channel_map_v1)

概述

channel_map_v1 是多通道路由映射模块。每个输出通道可配置 N 个输入通道源(顺序列表 + 下拉选择),支持多 Port 输入,支持通道名称编辑。

参数

参数 ID 类型 默认值 说明
enable bool true 模块启用/禁用
mapOutCount int 20 输出通道数
mapSrcCount#${outCh} int 0 输出通道 outCh 的源槽数量
mapSrc#${outCh}_${slotIdx} int -1 输出 outChslotIdx 槽的绝对输入通道索引(-1 = 未分配)
outputName#${outCh} string '' 输出通道名称(可编辑)

绝对通道索引

输入通道按连入 Port 顺序扁平化编号:

Port 0 (2ch):  absIdx 0 → P0-Ch0,absIdx 1 → P0-Ch1
Port 1 (4ch):  absIdx 2 → P1-Ch0,absIdx 3 → P1-Ch1,absIdx 4 → P1-Ch2,absIdx 5 → P1-Ch3

显示名称优先使用导线(连线)上携带的 channelNames[ch],无名称时显示 P{portIdx}-Ch{chIdx}

多 Port 输入检测

const inputPorts = computed(() =>
  linkStore.connections
    .filter(c => c.target.instanceId === instanceId)
    .map((c, portIdx) => {
      const srcDef = linkStore.getModuleDef(c.source.instanceId)
      const srcMod = linkStore.getModule(c.source.instanceId)
      const ch = srcMod?.config?.channels ?? srcDef?.outputs?.[0]?.channels ?? 2
      return { portIdx, conn: c, channels: ch }
    })
)

const availableInputChannels = computed(() => {
  const list: { absIdx: number; label: string }[] = []
  let absIdx = 0
  inputPorts.value.forEach(port => {
    for (let ch = 0; ch < port.channels; ch++) {
      const wireName = port.conn.channelNames?.[ch]
      const displayName = wireName?.trim() || `P${port.portIdx}-Ch${ch}`
      list.push({ absIdx, label: `[P${port.portIdx}] ${displayName}` })
      absIdx++
    }
  })
  return list
})

UI 布局

┌─ Channel Map 调音 ─────────────────────────────────┐
│ 输出通道数: [20]  输入: 4ch (2 ports)  ⚠ 无输入连线 │
├────────────────────────────────────────────────────┤
│ ┌──── Out 1 ─── [1 源] [+ 添加源] [✕清空] ────┐   │
│ │  ①  [P0] L (左)           ▼            [✕]  │   │
│ └────────────────────────────────────────────────┘   │
│ ┌──── Out 2 ─── [0 源] [+ 添加源] [✕清空] ────┐   │
│ │  无混入源(静音)                               │   │
│ └────────────────────────────────────────────────┘   │
└────────────────────────────────────────────────────┘
  • 每个输出通道为独立卡片,可展开源列表
  • 「+ 添加源」增加一个槽(初始为"未分配")
  • 每个槽:序号圆点 + 下拉框(选择输入通道)+ 「✕」移除按钮
  • 「✕清空」一键清空该输出所有源槽(设为静音)
  • 头部显示活跃源数量(源 absIdx ≥ 0 的槽数)
  • 可选字段:输出通道名称(inline text input,保存至 outputName#${outCh}

操作逻辑

添加源

function addSource(outCh: number) {
  const count = getSourceCount(outCh)
  setSourceCount(outCh, count + 1)  // mapSrcCount#outCh += 1
  setMapSrc(outCh, count, -1)       // mapSrc#outCh_count = -1 (未分配)
}

移除源(槽位前移)

function removeSource(outCh: number, slotIdx: number) {
  const count = getSourceCount(outCh)
  for (let i = slotIdx; i < count - 1; i++) {
    setMapSrc(outCh, i, getMapSrc(outCh, i + 1))  // 前移
  }
  setSourceCount(outCh, count - 1)
}

清空输出

function clearRow(outCh: number) {
  setSourceCount(outCh, 0)  // mapSrcCount#outCh = 0
}

持久化

// 输出通道数
linkStore.setParamValue(instanceId, 'mapOutCount', outputCount)
send({ type: 'set_param', instanceId, paramId: 'mapOutCount', value: outputCount })

// 槽数
linkStore.setParamValue(instanceId, `mapSrcCount#${outCh}`, count)
send({ type: 'set_param', instanceId, paramId: `mapSrcCount#${outCh}`, value: count })

// 源映射
linkStore.setParamValue(instanceId, `mapSrc#${outCh}_${slotIdx}`, absInputIdx)
send({ type: 'set_param', instanceId, paramId: `mapSrc#${outCh}_${slotIdx}`, value: absInputIdx })

// 通道名
linkStore.setParamValue(instanceId, `outputName#${outCh}`, name)
send({ type: 'set_param', instanceId, paramId: `outputName#${outCh}`, value: name })

DSP 内存布局

Offset Size 说明
0 1 enable
1 4 mapOutCount
5 64 × 4 srcCount[0..63] (int,每输出通道的源数量)
261 64 × 64 × 4 srcMap[outCh][slotIdx] (int,绝对输入通道索引)

Total: ~16645 bytes(支持最大 64 输出 × 64 槽)

与旧版差异

特性 旧版(checkbox 矩阵) 新版(源列表 + 下拉框)
参数 key mapCell#${outCh}_${inCh} mapSrc#${outCh}_${slotIdx}
显示方式 N×M 表格(列数随输入通道数增加) 每行独立卡片,槽数可配置
可读性 输入通道多时列过宽 始终紧凑,支持命名显示
顺序语义 无(集合) 有(槽 0 优先级最高)