Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a $(SQ:sceneRecalledTrigger) variable whose value changes every time a scene is recalled #70

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions companion/HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Controls the Allen & Heath SQ.
## Special Functions:

- Current scene display variable
- Scene recall variable (usable in triggers to respond to scene recalls)
- Current dB Fader Level display variables
- Current Pan level display variables
- Talkback macro
Expand All @@ -35,6 +36,7 @@ New in v.2.1.0
- Add an action to make active/inactive an FX return in LR/mixes
- Define pan/balance variables on-demand as pan/balance change messages are sent by the mixer
- Restart module instances in response to configuration changes only if absolutely required
- Add a `sceneRecalledTrigger` variable whose value changes every time a scene is recalled, suitable for use in triggers

New in v.2.0.0 (not released)

Expand Down
6 changes: 4 additions & 2 deletions src/instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getFeedbacks } from './feedbacks/feedbacks.js'
import { Mixer } from './mixer/mixer.js'
import { canUpdateOptionsWithoutRestarting, noConnectionOptions, optionsFromConfig } from './options.js'
import { getPresets } from './presets.js'
import { getVariables } from './variables.js'
import { CurrentSceneId, getVariables, SceneRecalledTriggerId } from './variables.js'

import api from './api.js'

Expand Down Expand Up @@ -97,10 +97,12 @@ export class sqInstance extends InstanceBase {
this.setVariableDefinitions(getVariables(this, model))

this.setVariableValues({
[SceneRecalledTriggerId]: 0,

// This value may very well be wrong, but there's no defined way to
// query what the current scene is, nor to be updated if it changes
// and this module didn't do it.
currentScene: 1,
[CurrentSceneId]: 1,
})
}

Expand Down
30 changes: 23 additions & 7 deletions src/midi/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MixerMessageParser } from './parse/parse.js'
import { MidiTokenizer } from './tokenize/tokenize.js'
import { prettyByte, prettyBytes } from '../utils/pretty.js'
import { asyncSleep, sleep } from '../utils/sleep.js'
import { CurrentSceneId, SceneRecalledTriggerId } from '../variables.js'

/**
* The port number used for MIDI-over-TCP connections to SQ mixers.
Expand Down Expand Up @@ -129,6 +130,26 @@ export class MidiSession {
})
}

/**
* React to a mixer scene being recalled.
*
* @param newScene
* The zero-indexed scene that was recalled.
*/
#sceneRecalled(newScene: number): void {
this.#mixer.currentScene = newScene

const instance = this.#instance
const sceneRecalledTrigger = Number(instance.getVariableValue(SceneRecalledTriggerId)!)
instance.setVariableValues({
[SceneRecalledTriggerId]: sceneRecalledTrigger + 1,

// The currentScene variable is 1-indexed, consistent with how
// the current scene is displayed to users in mixer UI.
[CurrentSceneId]: newScene + 1,
})
}

/** Read and process mixer reply messages from `socket`. */
async #processMixerReplies(socket: TCPHelper) {
const mixer = this.#mixer
Expand All @@ -144,14 +165,9 @@ export class MidiSession {

const mixerChannelParser = new MixerChannelParser(verboseLog)
mixerChannelParser.on('scene', (newScene: number) => {
verboseLog(`Scene changed: ${newScene}`)
verboseLog(`Scene recalled: ${newScene}`)

mixer.currentScene = newScene
instance.setVariableValues({
// The currentScene variable is 1-indexed, consistent with how
// the current scene is displayed to users in mixer UI.
currentScene: newScene + 1,
})
this.#sceneRecalled(newScene)
})
mixerChannelParser.on('mute', (msb: number, lsb: number, vf: number) => {
verboseLog(`Mute received: MSB=${prettyByte(msb)}, LSB=${prettyByte(lsb)}, VF=${prettyByte(vf)}`)
Expand Down
28 changes: 22 additions & 6 deletions src/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@ import type { CompanionVariableDefinition } from '@companion-module/base'
import type { SQInstanceInterface as sqInstance } from './instance-interface.js'
import type { Model } from './mixer/model.js'

export function getVariables(instance: sqInstance, model: Model): CompanionVariableDefinition[] {
const variables: CompanionVariableDefinition[] = []
/**
* The variable ID for the variable containing the last recalled scene
* (1-indexed).
*/
export const CurrentSceneId = 'currentScene'

/**
* The variable ID for the variable updated every time a scene is recalled
* intended for use in triggers.
*/
export const SceneRecalledTriggerId = 'sceneRecalledTrigger'

variables.push({
name: 'Scene - Current',
variableId: 'currentScene',
})
export function getVariables(instance: sqInstance, model: Model): CompanionVariableDefinition[] {
const variables: CompanionVariableDefinition[] = [
{
name: 'Scene - Scene Recalled',
variableId: SceneRecalledTriggerId,
},
{
name: 'Scene - Current',
variableId: CurrentSceneId,
},
]

model.forEachInputChannel((channel, channelLabel) => {
model.forEachMixAndLR((mix, _mixLabel, mixDesc) => {
Expand Down