diff --git a/src/actions/common.ts b/src/actions/common.ts index 1da32d2..07faa3d 100644 --- a/src/actions/common.ts +++ b/src/actions/common.ts @@ -14,6 +14,7 @@ import { GetPanoramaDeltaSlider, GetColorDropdown, GetNumberField, + GetSoloDropdown, } from '../choices/common.js' import { getNodeNumber, getNumber, runTransition } from './utils.js' import { InstanceBaseExt } from '../types.js' @@ -45,6 +46,9 @@ export enum CommonActions { RestorePanorama = 'restore-panorama', DeltaPanorama = 'panorama-delta', UndoDeltaPanorama = 'undo-panorama', + // Solo + SetSolo = 'set-solo', + ClearSolo = 'clear-solo', //////////// SEND SetSendMute = 'set-send-mute', // Send Fader @@ -409,6 +413,50 @@ export function createCommonActions(self: InstanceBaseExt): Companio ensureLoaded(cmd) }, }, + //////////////////////////////////////////////////////////////// + // Solo + //////////////////////////////////////////////////////////////// + [CommonActions.SetSolo]: { + name: 'Set Solo', + description: 'Set the solo state for a channel, aux, bux, matrix or main', + options: [GetDropdown('Selection', 'sel', allChannels), GetSoloDropdown('solo')], + callback: async (event) => { + const sel = event.options.sel as string + const cmd = ActionUtil.getSoloCommand(sel, getNodeNumber(event, 'sel')) + const val = ActionUtil.getNumber(event, 'solo') + const currentVal = StateUtil.getBooleanFromState(cmd, state) + if (val < 2) { + send(cmd, val) + } else { + send(cmd, Number(!currentVal)) + } + }, + subscribe: (event) => { + const sel = event.options.sel as string + const cmd = ActionUtil.getSoloCommand(sel, getNodeNumber(event, 'sel')) + ensureLoaded(cmd) + }, + }, + [CommonActions.ClearSolo]: { + name: 'Clear Solo', + description: 'Clear the Solo from all channels, auxes, busses, matrices and mains.', + options: [], + callback: async (_) => { + const extractNumber = (id: string): number | null => { + const match = id.match(/\/(\d+)$/) + return match ? parseInt(match[1], 10) : null + } + + for (const channel of allChannels) { + const id = channel.id as string + const number = extractNumber(id) + if (number !== null) { + const cmd = ActionUtil.getSoloCommand(id, number) + send(cmd, 0) + } + } + }, + }, //////////////////////////////////////////////////////////////// // Send Fader diff --git a/src/actions/config.ts b/src/actions/config.ts new file mode 100644 index 0000000..04d1365 --- /dev/null +++ b/src/actions/config.ts @@ -0,0 +1,131 @@ +import { CompanionActionDefinition } from '@companion-module/base' +import { SetRequired } from 'type-fest' // eslint-disable-line n/no-missing-import + +export type CompanionActionWithCallback = SetRequired + +import { CompanionActionDefinitions } from '@companion-module/base' +import { GetDropdown, GetMuteDropdown } from '../choices/common.js' +import { InstanceBaseExt } from '../types.js' +import { WingConfig } from '../config.js' +import * as ActionUtil from './utils.js' +import { ConfigurationCommands } from '../commands/config.js' +import { StateUtil } from '../state/index.js' +import { getIdLabelPair } from '../choices/utils.js' + +export enum CommonActions { + // Solo + SetSoloMute = 'set-solo-mute', + SetSoloDim = 'set-solo-dim', + SetSoloMono = 'set-solo-mono', + SetSoloLRSwap = 'set-solo-swap', +} + +export function createConfigurationActions(self: InstanceBaseExt): CompanionActionDefinitions { + const send = self.sendCommand + const ensureLoaded = self.ensureLoaded + const state = self.state + + const actions: { [id in CommonActions]: CompanionActionWithCallback | undefined } = { + //////////////////////////////////////////////////////////////// + // Solo + //////////////////////////////////////////////////////////////// + [CommonActions.SetSoloMute]: { + name: 'Set Solo Mute', + description: 'Set or toggle the mute state of the solo output.', + options: [GetMuteDropdown('mute')], + callback: async (event) => { + const cmd = ConfigurationCommands.SoloMute() + const val = ActionUtil.getNumber(event, 'mute') + const currentVal = StateUtil.getBooleanFromState(cmd, state) + if (val >= 2) { + send(cmd, Number(!currentVal)) + } else { + send(cmd, val) + } + }, + subscribe: (_) => { + const cmd = ConfigurationCommands.SoloMute() + ensureLoaded(cmd) + }, + }, + [CommonActions.SetSoloDim]: { + name: 'Set Solo Dim', + description: 'Set or toggle the dim state of the solo output.', + options: [ + GetDropdown( + 'Dim', + 'dim', + [getIdLabelPair('1', 'On'), getIdLabelPair('0', 'Off'), getIdLabelPair('2', 'Toggle')], + '1', + ), + ], + callback: async (event) => { + const cmd = ConfigurationCommands.SoloDim() + const val = ActionUtil.getNumber(event, 'dim') + const currentVal = StateUtil.getBooleanFromState(cmd, state) + if (val >= 2) { + send(cmd, Number(!currentVal)) + } else { + send(cmd, val) + } + }, + subscribe: (_) => { + const cmd = ConfigurationCommands.SoloDim() + ensureLoaded(cmd) + }, + }, + [CommonActions.SetSoloMono]: { + name: 'Set Solo Mono', + description: 'Set or toggle the mono state of the solo output.', + options: [ + GetDropdown( + 'Mono', + 'mono', + [getIdLabelPair('1', 'On'), getIdLabelPair('0', 'Off'), getIdLabelPair('2', 'Toggle')], + '1', + ), + ], + callback: async (event) => { + const cmd = ConfigurationCommands.SoloMono() + const val = ActionUtil.getNumber(event, 'mono') + const currentVal = StateUtil.getBooleanFromState(cmd, state) + if (val >= 2) { + send(cmd, Number(!currentVal)) + } else { + send(cmd, val) + } + }, + subscribe: (_) => { + const cmd = ConfigurationCommands.SoloMono() + ensureLoaded(cmd) + }, + }, + [CommonActions.SetSoloLRSwap]: { + name: 'Set Solo LR Swap', + description: 'Set the left-right channel swap of the solo channel.', + options: [ + GetDropdown( + 'Swap', + 'swap', + [getIdLabelPair('1', 'Swap'), getIdLabelPair('0', "Don't Swap"), getIdLabelPair('2', 'Toggle')], + '1', + ), + ], + callback: async (event) => { + const cmd = ConfigurationCommands.SoloLRSwap() + const val = ActionUtil.getNumber(event, 'swap') + const currentVal = StateUtil.getBooleanFromState(cmd, state) + if (val >= 2) { + send(cmd, Number(!currentVal)) + } else { + send(cmd, val) + } + }, + subscribe: (_) => { + const cmd = ConfigurationCommands.SoloLRSwap() + ensureLoaded(cmd) + }, + }, + } + return actions +} diff --git a/src/actions/index.ts b/src/actions/index.ts index 7636a49..c12cca8 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -1,5 +1,6 @@ import { CompanionActionDefinitions } from '@companion-module/base' import { createChannelActions } from '../actions/channel.js' +import { createConfigurationActions } from '../actions/config.js' import { GetOtherActions as createOtherActions } from './other.js' import { createBusActions as createBusActions } from './bus.js' import { InstanceBaseExt } from '../types.js' @@ -16,6 +17,7 @@ export function createActions(self: InstanceBaseExt): CompanionActio ...createBusActions(self), ...createAuxActions(self), ...createMainActions(self), + ...createConfigurationActions(self), } return actions diff --git a/src/actions/utils.ts b/src/actions/utils.ts index 785aeb2..c77fc5f 100644 --- a/src/actions/utils.ts +++ b/src/actions/utils.ts @@ -129,6 +129,22 @@ export function getMuteCommand(sel: string, val: number): string { return cmd } +export function getSoloCommand(sel: string, val: number): string { + let cmd = '' + if (sel.startsWith('/ch')) { + cmd = ChannelCommands.Solo(val) + } else if (sel.startsWith('/aux')) { + cmd = AuxCommands.Solo(val) + } else if (sel.startsWith('/bus')) { + cmd = BusCommands.Solo(val) + } else if (sel.startsWith('/mtx')) { + cmd = MatrixCommands.Solo(val) + } else if (sel.startsWith('/main')) { + cmd = MainCommands.Solo(val) + } + return cmd +} + export function getFaderCommand(sel: string, val: number): string { let cmd = '' if (sel.startsWith('/ch')) { diff --git a/src/choices/common.ts b/src/choices/common.ts index e047658..3bc0d95 100644 --- a/src/choices/common.ts +++ b/src/choices/common.ts @@ -80,7 +80,20 @@ export function GetMuteDropdown(id: string, label?: string, includeToggle?: bool const dropdown = GetDropdown( label ?? 'Mute', id, - [getIdLabelPair('0', 'Unmute'), getIdLabelPair('1', 'Mute')], + [getIdLabelPair('1', 'Mute'), getIdLabelPair('0', 'Unmute')], + '1', + 'Select whether to Mute, Unmute or Toggle your selected target', + ) + if (includeToggle == false) return dropdown + + return { ...dropdown, choices: [...dropdown.choices, getIdLabelPair('2', 'Toggle')] } +} + +export function GetSoloDropdown(id: string, label?: string, includeToggle?: boolean): CompanionInputFieldDropdown { + const dropdown = GetDropdown( + label ?? 'Solo', + id, + [getIdLabelPair('1', 'On'), getIdLabelPair('0', 'Off')], '1', 'Select whether to Mute, Unmute or Toggle your selected target', ) diff --git a/src/commands/config.ts b/src/commands/config.ts index 51a32fd..e2aa202 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -102,91 +102,115 @@ export namespace ConfigurationCommands { // Commands //////////////////////////////////////////////// + export function ConfigNode(): string { + return `/cfg` + } + export function ClockRate(): string { - return '/cfg/clkrate' + return `${ConfigNode}/clkrate` } export function ClockSource(): string { - return '/cfg/clksrc' + return `${ConfigNode}/clksrc` } export function MainLink(): string { - return '/cfg/mainlink' + return `${ConfigNode}/mainlink` } export function DcaGroup(): string { - return '/cfg/dcamgrp' + return `${ConfigNode}/dcamgrp` } export function MuteOverride(): string { - return '/cfg/muteovr' + return `${ConfigNode}/muteovr` } export function StartMute(): string { - return '/cfg/startmute' + return `${ConfigNode}/startmute` } export function UsbConfig(): string { - return '/cfg/usbacfg' + return `${ConfigNode}/usbacfg` } export function ScConfig(): string { - return '/cfg/sccfg' + return `${ConfigNode}/sccfg` } export function MonitorEqGain(node: MonitorNode, band: MonitorEqBand): string { - return `/cfg/mon/${node}/eq/${band}g` + return `${ConfigNode}/mon/${node}/eq/${band}g` } export function MonitorEqFrequency(node: MonitorNode, band: MonitorEqBand): string { - return `/cfg/mon/${node}/eq/${band}f` + return `${ConfigNode}/mon/${node}/eq/${band}f` } export function MonitorEqQ(node: MonitorNode, band: MonitorEqBand): string { - return `/cfg/mon/${node}/eq/${band}q` + return `${ConfigNode}/mon/${node}/eq/${band}q` } export function MonitorEqHighShelfGain(node: MonitorNode): string { - return `/cfg/mon/${node}/eq/hsg` + return `${ConfigNode}/mon/${node}/eq/hsg` } export function MonitorEqHighShelfFrequency(node: MonitorNode): string { - return `/cfg/mon/${node}/eq/hsf` + return `${ConfigNode}/mon/${node}/eq/hsf` } export function MonitorLimiterLevel(node: MonitorNode): string { - return `/cfg/mon/${node}/lim` + return `${ConfigNode}/mon/${node}/lim` } export function MonitorDelayOn(node: MonitorNode): string { - return `/cfg/mon/${node}/dly/on` + return `${ConfigNode}/mon/${node}/dly/on` } export function MonitorDelayMeters(node: MonitorNode): string { - return `/cfg/mon/${node}/dly/m` + return `${ConfigNode}/mon/${node}/dly/m` } export function MonitorDelayDimLevel(node: MonitorNode): string { - return `/cfg/mon/${node}/dim` + return `${ConfigNode}/mon/${node}/dim` } export function MonitorPflDim(node: MonitorNode): string { - return `/cfg/mon/${node}/pfldim` + return `${ConfigNode}/mon/${node}/pfldim` } export function MonitorEqBandSoloTrim(node: MonitorNode): string { - return `/cfg/mon/${node}/eqbdtrim` + return `${ConfigNode}/mon/${node}/eqbdtrim` } export function MonitorSourceLevel(node: MonitorNode): string { - return `/cfg/mon/${node}/srclvl` + return `${ConfigNode}/mon/${node}/srclvl` } export function MonitorSourceMix(node: MonitorNode): string { - return `/cfg/mon/${node}/srcmix` + return `${ConfigNode}/mon/${node}/srcmix` } export function MonitorSource(node: MonitorNode): string { - return `/cfg/mon/${node}/src` + return `${ConfigNode}/mon/${node}/src` + } + + export function SoloNode(): string { + return `${ConfigNode()}/solo` + } + + export function SoloMute(): string { + return `${SoloNode()}/mute` + } + + export function SoloDim(): string { + return `${SoloNode()}/$dim` + } + + export function SoloMono(): string { + return `${SoloNode()}/$mono` + } + + export function SoloLRSwap(): string { + return `${SoloNode()}/$flip` } }