From f6a5c4d59a92d5604715a343dc73cdfbb5228a53 Mon Sep 17 00:00:00 2001 From: Jan Starzak Date: Tue, 11 Jun 2019 17:52:27 +0200 Subject: [PATCH] feat(casparcg): support VU meters on CCG mixer --- src/@types/osc/index.d.ts | 9 +---- src/constants/MixerProtocolPresets.ts | 15 ++++--- .../mixerProtocols/casparCGMaster.ts | 10 ++--- src/utils/CasparCGConnection.ts | 40 +++++++++++++++++-- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/@types/osc/index.d.ts b/src/@types/osc/index.d.ts index 76ba8950..6369fec6 100644 --- a/src/@types/osc/index.d.ts +++ b/src/@types/osc/index.d.ts @@ -9,7 +9,7 @@ declare module 'osc' { interface OSCMessage { address: string, - args: TypeAnnotatedArg | TypeAnnotatedArg[] + args: any[] } type OSCMessageOrBundle = OSCMessage | OSCBundle @@ -28,12 +28,6 @@ declare module 'osc' { a: number } - interface TypeAnnotatedArg { - type: string - value: any - } - - interface OSCPort extends EventEmitter { on(event: 'ready', handler: () => void): this on(event: 'message', handler: (message: OSCMessage, timeTag: TimeTag | undefined, info: any) => void): this @@ -64,5 +58,6 @@ declare module 'osc' { on(event: "raw", handler: (data: Uint8Array, info: any) => void): this on(event: "error", handler: (error: Error) => void): this send(packet: OSCMessage | OSCBundle): void + open(): void } } diff --git a/src/constants/MixerProtocolPresets.ts b/src/constants/MixerProtocolPresets.ts index 89fd2106..31054693 100644 --- a/src/constants/MixerProtocolPresets.ts +++ b/src/constants/MixerProtocolPresets.ts @@ -59,8 +59,13 @@ export interface ChannelLayerPair { export interface ICasparCGMixerGeometryFile { label?: string, channelLabels?: string[], - PGM_CHANNEL_FADER_LEVEL: Array, - MONITOR_CHANNEL_FADER_LEVEL: Array + fromMixer: { + CHANNEL_VU: Array, + } + toMixer: { + PGM_CHANNEL_FADER_LEVEL: Array, + MONITOR_CHANNEL_FADER_LEVEL: Array + } } export interface ICasparCGMixerGeometry extends IMixerProtocolGeneric { @@ -68,9 +73,9 @@ export interface ICasparCGMixerGeometry extends IMixerProtocolGeneric { leadingZeros: boolean, pingTime: number, fromMixer: { - CHANNEL_FADER_LEVEL: string, - CHANNEL_OUT_GAIN: string, - CHANNEL_VU: string, + // CHANNEL_FADER_LEVEL: ChannelLayerPair[], + // CHANNEL_OUT_GAIN: ChannelLayerPair[], + CHANNEL_VU: Array, }, toMixer: { PGM_CHANNEL_FADER_LEVEL: Array, diff --git a/src/constants/mixerProtocols/casparCGMaster.ts b/src/constants/mixerProtocols/casparCGMaster.ts index d032a0a9..e2f8950d 100644 --- a/src/constants/mixerProtocols/casparCGMaster.ts +++ b/src/constants/mixerProtocols/casparCGMaster.ts @@ -12,7 +12,7 @@ try { let inputObj = JSON.parse(fs.readFileSync(geometryFile, { encoding: 'utf-8' })) - if (inputObj.MONITOR_CHANNEL_FADER_LEVEL && inputObj.PGM_CHANNEL_FADER_LEVEL) { + if (inputObj.toMixer && inputObj.toMixer.PGM_CHANNEL_FADER_LEVEL) { geometry = inputObj } } catch (e) { @@ -29,12 +29,8 @@ if (geometry) { studio: "rk10", leadingZeros: false, pingTime: 0, - fromMixer: { - CHANNEL_FADER_LEVEL: "39", //PgmChange 0 - ignores this command - CHANNEL_OUT_GAIN: "0", //PgmChange 0 - ignores this command - CHANNEL_VU: "0", //PgmChange 0 - ignores this command - }, - toMixer: geometry, + fromMixer: geometry.fromMixer, + toMixer: geometry.toMixer, fader: { min: 0, max: 1.5, diff --git a/src/utils/CasparCGConnection.ts b/src/utils/CasparCGConnection.ts index 0e802501..346bcaef 100644 --- a/src/utils/CasparCGConnection.ts +++ b/src/utils/CasparCGConnection.ts @@ -8,11 +8,16 @@ import { IMixerProtocol, MixerProtocolPresets, ICasparCGMixerGeometry, ChannelLa import { IStore } from '../reducers/indexReducer'; import { IChannel } from '../reducers/channelsReducer'; +interface CommandChannelMap { + [key: string]: number +} + export class CasparCGConnection { store: IStore; mixerProtocol: ICasparCGMixerGeometry; connection: CasparCG; oscClient: osc.UDPPort | undefined; + oscCommandMap: { [key: string]: CommandChannelMap } = {}; constructor(mixerProtocol: ICasparCGMixerGeometry) { this.store = window.storeRedux.getState() as IStore; @@ -38,23 +43,44 @@ export class CasparCGConnection { console.log("CasparCG disconnected"); } this.connection.connect(); + + this.oscCommandMap.CHANNEL_VU = {} + this.mixerProtocol.fromMixer.CHANNEL_VU.forEach((paths, index) => { + this.oscCommandMap.CHANNEL_VU[paths[0]] = index + }) } setupMixerConnection() { if (!this.oscClient) { + const remotePort = parseInt(this.store.settings[0].devicePort + '') + 1000 this.oscClient = new osc.UDPPort({ localAddress: this.store.settings[0].localIp, - localPort: parseInt(this.store.settings[0].localOscPort + ''), + localPort: remotePort, remoteAddress: this.store.settings[0].deviceIp, - remotePort: parseInt(this.store.settings[0].devicePort + '') + 1000 + remotePort }) .on('ready', () => { - + console.log("Receiving state of mixer"); + }) + .on('message', (message: osc.OSCMessage) => { + const index = this.checkOscCommand(message.address, this.oscCommandMap.CHANNEL_VU) + if (index !== undefined && message.args) { + window.storeRedux.dispatch({ + type: 'SET_VU_LEVEL', + channel: index, + // CCG returns "produced" audio levels, before the Volume mixer transform + // We therefore want to premultiply this to show useful information about audio levels + level: Math.min(1, message.args[0] * this.store.channels[0].channel[index].faderLevel) + }); + } }) .on('error', (error: any) => { console.log("Error : ", error); console.log("Lost OSC connection"); }); + + this.oscClient.open(); + console.log("Listening for status on CasparCG: ", this.store.settings[0].deviceIp, remotePort) } // Restore mixer values to the ones we have internally @@ -75,6 +101,14 @@ export class CasparCGConnection { } } + checkOscCommand(address: string, commandSpace: CommandChannelMap): number | undefined { + const index = commandSpace[address] + if (index !== undefined) { + return index + } + return undefined + } + pingMixerCommand = () => { //Ping OSC mixer if mixerProtocol needs it. /* this.mixerProtocol.pingCommand.map((command) => {