Add Group and Aux master actions, feedbacks and preset sections

Groups were only reachable through the generic "Buss:" actions, whose
dropdown mixes all 25 busses, so users could not find group fader
control.

- New "Group:" and "Aux master:" mute, solo, set fader (with fade time)
  and adjust fader actions; their dropdowns list only busses of that
  type. Matching muted, solo, fader text/position, meter, signal and
  peak feedbacks.
- The old buss_* actions and feedbacks keep working for existing
  buttons and are now labelled "Any buss (aux or group)".
- Presets: "Busses" is split into "Groups" and "Aux masters", and the
  bus meters into "Group meters" and "Aux meters". A bus that changes
  type on the console moves section on the next rebuild.

npm test: 542 checks pass on Node 25 and on Companion's Node 22.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 12:57:01 -04:00
co-authored by Claude Opus 5.5
parent 205f91e7d2
commit f81d581bf2
6 changed files with 263 additions and 75 deletions
+36 -28
View File
@@ -19,6 +19,12 @@ const ON_GREEN = 0x00a050 // a send is on / an input is assigned
const MUTED_RED = 0xb01010 // muted, peak
const SIGNAL_BG = 0x00501e // signal present on a meter button
/** The two kinds of buss, each with its own actions, feedbacks and preset sections (the console's aux or group side of a buss). */
const BUSS_KINDS = [
{ kind: 'group', prefix: 'group', section: 'groups', meterSection: 'meters_groups', title: 'Group', meterTitle: 'Group' },
{ kind: 'aux', prefix: 'aux', section: 'aux_masters', meterSection: 'meters_aux', title: 'Aux master', meterTitle: 'Aux' },
]
const fb = (feedbackId, options, bg, color = WHITE) => ({ feedbackId, options, style: { bgcolor: bg, color } })
const act = (actionId, options) => ({ actionId, options })
@@ -209,27 +215,27 @@ const METER_TRACK_AMOUNT = 20
}
}
// ---- Busses
{
// ---- Groups and aux masters: per named buss of that type, a mute button and a fader knob
for (const { kind, prefix, section, title } of BUSS_KINDS) {
const muteIds = []
const knobIds = []
for (const n of s.named('buss')) {
const tag = `${n} · ${s.displayName('buss', n)} (${s.bussMode(n)})`
presets[`buss_mute_${n}`] = simple(`Master mute: ${tag}`, nameVar('buss', n), [act('buss_mute', { busses: [n], state: 'toggle' })], [fb('buss_muted', { buss: n }, RED)])
presets[`buss_knob_${n}`] = layeredKnob({
name: `Master fader (knob): ${tag}`,
for (const n of s.namedBusses(kind)) {
const tag = `${n} · ${s.displayName('buss', n)}`
presets[`${prefix}_mute_${n}`] = simple(`${title} mute: ${tag}`, nameVar('buss', n), [act(`${prefix}_mute`, { busses: [n], state: 'toggle' })], [fb(`${prefix}_muted`, { buss: n }, RED)])
presets[`${prefix}_knob_${n}`] = layeredKnob({
name: `${title} fader (knob): ${tag}`,
title: nameVar('buss', n),
press: [act('buss_mute', { busses: [n], state: 'toggle' })],
adjust: ['buss_fader_adjust', { buss: n }],
level: ['buss_fader_value', { buss: n }],
pos: ['buss_fader_pos', { buss: n }],
feedbacks: [tint('buss_muted', { buss: n }, MUTED_RED)],
press: [act(`${prefix}_mute`, { busses: [n], state: 'toggle' })],
adjust: [`${prefix}_fader_adjust`, { buss: n }],
level: [`${prefix}_fader_value`, { buss: n }],
pos: [`${prefix}_fader_pos`, { buss: n }],
feedbacks: [tint(`${prefix}_muted`, { buss: n }, MUTED_RED)],
})
muteIds.push(`buss_mute_${n}`)
knobIds.push(`buss_knob_${n}`)
muteIds.push(`${prefix}_mute_${n}`)
knobIds.push(`${prefix}_knob_${n}`)
}
if (muteIds.length) {
structure.push({ id: 'busses', name: 'Busses', definitions: [group('busses_mute', 'Master mute', muteIds), group('busses_knob', 'Master fader (knob)', knobIds)] })
structure.push({ id: section, name: `${title}s`, definitions: [group(`${section}_mute`, 'Mute', muteIds), group(`${section}_knob`, 'Fader (knob)', knobIds)] })
}
}
@@ -362,19 +368,21 @@ const METER_TRACK_AMOUNT = 20
// ---- Output meters: one layered meter per buss and per matrix output
{
const bussIds = []
for (const n of s.named('buss')) {
presets[`buss_meter_${n}`] = layeredMeter({
name: `Buss meter: ${n} · ${s.displayName('buss', n)} (${s.bussMode(n)})`,
title: nameVar('buss', n),
posFeedback: ['buss_meter_pos', { buss: n }],
signal: ['buss_signal', { buss: n, thresholdDb: -50 }],
peak: ['buss_peak', { buss: n, peakDb: -1, hold: 2 }],
})
bussIds.push(`buss_meter_${n}`)
}
if (bussIds.length) {
structure.push({ id: 'buss_meters', name: 'Buss meters', description: 'Meters subscribe on the console when the button first renders.', definitions: [group('buss_meters_level', 'Level', bussIds)] })
for (const { kind, prefix, meterSection, meterTitle } of BUSS_KINDS) {
const ids = []
for (const n of s.namedBusses(kind)) {
presets[`${prefix}_meter_${n}`] = layeredMeter({
name: `${meterTitle} meter: ${n} · ${s.displayName('buss', n)}`,
title: nameVar('buss', n),
posFeedback: [`${prefix}_meter_pos`, { buss: n }],
signal: [`${prefix}_signal`, { buss: n, thresholdDb: -50 }],
peak: [`${prefix}_peak`, { buss: n, peakDb: -1, hold: 2 }],
})
ids.push(`${prefix}_meter_${n}`)
}
if (ids.length) {
structure.push({ id: meterSection, name: `${meterTitle} meters`, description: 'Meters subscribe on the console when the button first renders.', definitions: [group(`${meterSection}_level`, 'Level', ids)] })
}
}
const matrixIds = []
for (const n of s.numbers('matrix')) {