From ee6384ef383b8766d8bddb06acbd7a8ea435e236 Mon Sep 17 00:00:00 2001 From: olzzon Date: Sat, 2 May 2020 14:08:50 +0200 Subject: [PATCH] feat: Skaarhoj - abstract remote controllers for other support that HUI --- server/mainClasses.ts | 8 +- server/utils/HuiMidiRemoteConnection.ts | 203 ---- server/utils/MixerConnection.ts | 6 +- .../mixerConnections/EmberMixerConnection.ts | 637 ++++++------ .../mixerConnections/MidiMixerConnection.ts | 526 +++++----- .../mixerConnections/OscMixerConnection.ts | 6 +- .../mixerConnections/SSLMixerConnection.ts | 956 ++++++++++-------- .../mixerConnections/StuderMixerConnection.ts | 682 +++++++------ .../mixerConnections/YamahaQlClConnection.ts | 780 +++++++------- 9 files changed, 1957 insertions(+), 1847 deletions(-) delete mode 100644 server/utils/HuiMidiRemoteConnection.ts diff --git a/server/mainClasses.ts b/server/mainClasses.ts index 3ca1a589..2625ed63 100644 --- a/server/mainClasses.ts +++ b/server/mainClasses.ts @@ -4,7 +4,7 @@ import { } from './constants/MixerProtocolPresets' import { MixerGenericConnection } from './utils/MixerConnection' import { AutomationConnection } from './utils/AutomationConnection' -import { HuiMidiRemoteConnection } from './utils/HuiMidiRemoteConnection' +import { RemoteConnection } from './utils/RemoteConnection' import { state } from './reducers/store' let mixerProtocolPresets = MixerProtocolPresets @@ -12,9 +12,9 @@ let mixerProtocolList = MixerProtocolList let mixerGenericConnection = new MixerGenericConnection() let automationConnection = new AutomationConnection() -let huiRemoteConnection: HuiMidiRemoteConnection | null = null +let remoteConnections: RemoteConnection | null = null if (state.settings[0].enableRemoteFader) { - huiRemoteConnection = new HuiMidiRemoteConnection() + remoteConnections = new RemoteConnection() } export { @@ -22,5 +22,5 @@ export { mixerProtocolPresets, mixerGenericConnection, automationConnection, - huiRemoteConnection, + remoteConnections, } diff --git a/server/utils/HuiMidiRemoteConnection.ts b/server/utils/HuiMidiRemoteConnection.ts deleted file mode 100644 index 97f6fb15..00000000 --- a/server/utils/HuiMidiRemoteConnection.ts +++ /dev/null @@ -1,203 +0,0 @@ -//Node Modules: -import WebMidi from 'webmidi' -import { store, state } from '../reducers/store' -import { mixerGenericConnection } from '../mainClasses' - -import { - SET_FADER_LEVEL, - TOGGLE_PGM, - TOGGLE_PFL, -} from '../reducers/faderActions' - -//Utils: -import { - IRemoteProtocol, - RemoteFaderPresets, - MidiReceiveTypes, -} from '../constants/RemoteFaderPresets' -import { MixerProtocolPresets } from '../constants/MixerProtocolPresets' - -export class HuiMidiRemoteConnection { - store: any - remoteProtocol: IRemoteProtocol - midiReceiveTypes = MidiReceiveTypes - mixerProtocol: any - midiInput: any - midiOutput: any - activeHuiChannel: number = 0 - - constructor() { - this.convertFromRemoteLevel = this.convertFromRemoteLevel.bind(this) - this.convertToRemoteLevel = this.convertToRemoteLevel.bind(this) - this.updateRemoteFaderState = this.updateRemoteFaderState.bind(this) - - this.remoteProtocol = RemoteFaderPresets.hui - this.mixerProtocol = - MixerProtocolPresets[state.settings[0].mixerProtocol] || - MixerProtocolPresets.genericMidi - - if (!state.settings[0].enableRemoteFader) { - return - } - - WebMidi.enable((err) => { - if (err) { - console.log( - 'Remote MidiController connection could not be enabled.', - err - ) - } - - this.midiInput = WebMidi.getInputByName( - state.settings[0].remoteFaderMidiInputPort - ) - this.midiOutput = WebMidi.getOutputByName( - state.settings[0].remoteFaderMidiOutputPort - ) - - if (this.midiInput && this.midiOutput) { - console.log('Remote Midi Controller connected on port') - console.log( - 'Midi input :', - state.settings[0].remoteFaderMidiInputPort - ) - console.log( - 'Midi output :', - state.settings[0].remoteFaderMidiOutputPort - ) - - this.setupRemoteFaderConnection() - } else { - console.log( - 'Remote Midi Controller not found or not configured.' - ) - } - }) - } - - setupRemoteFaderConnection() { - this.midiInput.addListener( - this.midiReceiveTypes[ - this.remoteProtocol.fromRemote.CHANNEL_FADER_LEVEL.type - ], - undefined, - (message: any) => { - if (message.data[1] < 9) { - //Fader changed: - console.log( - 'Received Fader message (' + message.data + ').' - ) - store.dispatch({ - type: SET_FADER_LEVEL, - channel: message.data[1], - level: this.convertFromRemoteLevel(message.data[2]), - }) - mixerGenericConnection.updateOutLevel(message.data[1]) - this.updateRemoteFaderState( - message.data[1], - this.convertFromRemoteLevel(message.data[2]) - ) - } else if ((message.data[1] = 15)) { - console.log('Received message (' + message.data + ').') - if (message.data[2] < 9) { - //Set active channel for next midi message: - this.activeHuiChannel = message.data[2] - } else if (message.data[2] && message.data[2] === 65) { - //SELECT button - toggle PGM ON/OFF - store.dispatch({ - type: TOGGLE_PGM, - channel: this.activeHuiChannel, - }) - mixerGenericConnection.updateOutLevel( - this.activeHuiChannel - ) - this.updateRemotePgmPstPfl(this.activeHuiChannel) - } else if (message.data[2] && message.data[2] === 67) { - //SOLO button - toggle PFL ON/OFF - store.dispatch({ - type: TOGGLE_PFL, - channel: this.activeHuiChannel, - }) - mixerGenericConnection.updateOutLevel( - this.activeHuiChannel - ) - this.updateRemotePgmPstPfl(this.activeHuiChannel) - } - } - } - ) - //for testing: - this.midiInput.addListener('noteon', 'all', (error: any) => { - console.log( - "Received 'noteon' message (" + - error.note.name + - error.note.octave + - ').' - ) - }) - } - - convertToRemoteLevel(level: number) { - let oldMin = this.mixerProtocol.fader.min - let oldMax = this.mixerProtocol.fader.max - let newMin = this.remoteProtocol.fader.min - let newMax = this.remoteProtocol.fader.max - - let indexLevel = (level / (oldMax - oldMin)) * (newMax - newMin) - let newLevel = newMin + indexLevel - return newLevel //convert from mixer min-max to remote min-max - } - - convertFromRemoteLevel(level: number) { - let oldMin = this.remoteProtocol.fader.min - let oldMax = this.remoteProtocol.fader.max - let newMin = this.mixerProtocol.fader.min - let newMax = this.mixerProtocol.fader.max - - let indexLevel = (level / (oldMax - oldMin)) * (newMax - newMin) - let newLevel = newMin + indexLevel - - return newLevel //convert from mixer min-max to remote min-max - } - - updateRemoteFaderState(channelIndex: number, outputLevel: number) { - if (!this.midiOutput) { - return - } - console.log( - 'Send fader update :', - 'Channel index : ', - channelIndex, - 'OutputLevel : ', - this.convertToRemoteLevel(outputLevel) - ) - this.midiOutput.sendControlChange( - channelIndex, - this.convertToRemoteLevel(outputLevel), - 1 - ) - this.midiOutput.sendControlChange(32 + channelIndex, 0, 1) - this.updateRemotePgmPstPfl(channelIndex) - } - - updateRemotePgmPstPfl(channelIndex: number) { - if (!this.midiOutput) { - return - } - //Update SELECT button: - this.midiOutput.sendControlChange(12, channelIndex, 1) - this.midiOutput.sendControlChange( - 44, - 1 + 64 * (state.faders[0].fader[channelIndex].pgmOn ? 1 : 0), - 1 - ) - - //Update SOLO button: - this.midiOutput.sendControlChange(12, channelIndex, 1) - this.midiOutput.sendControlChange( - 44, - 3 + 64 * (state.faders[0].fader[channelIndex].pflOn ? 1 : 0), - 1 - ) - } -} diff --git a/server/utils/MixerConnection.ts b/server/utils/MixerConnection.ts index e4d1bcc1..3196b04c 100644 --- a/server/utils/MixerConnection.ts +++ b/server/utils/MixerConnection.ts @@ -1,5 +1,5 @@ import { store, state } from '../reducers/store' -import { huiRemoteConnection } from '../mainClasses' +import { remoteConnections } from '../mainClasses' //Utils: import { MixerProtocolPresets } from '../constants/MixerProtocolPresets' @@ -124,8 +124,8 @@ export class MixerGenericConnection { } } ) - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState( + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( faderIndex, state.faders[0].fader[faderIndex].faderLevel ) diff --git a/server/utils/mixerConnections/EmberMixerConnection.ts b/server/utils/mixerConnections/EmberMixerConnection.ts index 93259909..aaa64d8a 100644 --- a/server/utils/mixerConnections/EmberMixerConnection.ts +++ b/server/utils/mixerConnections/EmberMixerConnection.ts @@ -1,300 +1,337 @@ -//@ts-ignore -import { EmberClient } from 'node-emberplus' -import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' - -//Utils: -import { IMixerProtocol } from '../../constants/MixerProtocolInterface'; -import { - SET_FADER_LEVEL, - SET_CHANNEL_LABEL -} from '../../reducers/faderActions' -import { logger } from '../logger'; - - -export class EmberMixerConnection { - mixerProtocol: IMixerProtocol - emberConnection: EmberClient - deviceRoot: any; - emberNodeObject: Array; - - - constructor(mixerProtocol: IMixerProtocol) { - this.sendOutMessage = this.sendOutMessage.bind(this); - this.pingMixerCommand = this.pingMixerCommand.bind(this); - - this.emberNodeObject = new Array(200); - this.mixerProtocol = mixerProtocol; - - logger.info("Setting up Ember connection") - this.emberConnection = new EmberClient( - state.settings[0].deviceIp, - state.settings[0].devicePort - ); - - this.emberConnection.on('error', (error: any) => { - if ( - (error.message + '').match(/econnrefused/i) || - (error.message + '').match(/disconnected/i) - ) { - logger.error('Ember connection not establised') - } else { - logger.error('Ember connection unknown error' + error.message) - } - }) - this.emberConnection.on('disconnected', () => { - logger.error('Lost Ember connection') - }) - logger.info('Connecting to Ember') - let deviceRoot: any; - this.emberConnection.connect() - .then(() => { - console.log("Getting Directory") - return this.emberConnection.getDirectory(); - }) - .then((r: any) => { - console.log("Directory :", r); - this.deviceRoot = r; - this.emberConnection.expand(r.elements[0]) - .then(() => { - this.setupMixerConnection(); - }) - }) - .catch((e: any) => { - console.log(e.stack); - }); - } - - setupMixerConnection() { - logger.info('Ember connection established - setting up subscription of channels') - - let ch: number = 1; - state.settings[0].numberOfChannelsInType.forEach((numberOfChannels, typeIndex) => { - for (let channelTypeIndex=0; channelTypeIndex < numberOfChannels ; channelTypeIndex++) { - this.subscribeFaderLevel(ch, typeIndex, channelTypeIndex); - ch++; - } - }) -/* - .CHANNEL_VU)){ - store.dispatch({ - type:SET_VU_LEVEL, - channel: ch - 1, - level: message.args[0] - }); - */ - - - //Ping OSC mixer if mixerProtocol needs it. - if (this.mixerProtocol.pingTime > 0) { - let emberTimer = setInterval( - () => { - this.pingMixerCommand(); - }, - this.mixerProtocol.pingTime - ); - } - } - - subscribeFaderLevel(ch: number, typeIndex: number, channelTypeIndex: number) { - let command = this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.replace("{channel}", String(channelTypeIndex+1)) - this.emberConnection.getElementByPath(command) - .then((node: any) => { - logger.info('Subscription of channel : ' + command) - this.emberNodeObject[ch-1] = node; - this.emberConnection.subscribe(node, (() => { - logger.verbose('Receiving Level from Ch ' + String(ch)) - if (!state.channels[0].channel[ch-1].fadeActive - && !state.channels[0].channel[ch - 1].fadeActive - && node.contents.value > this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_OUT_GAIN[0].min) { - store.dispatch({ - type: SET_FADER_LEVEL, - channel: ch-1, - level: node.contents.value - }); - global.mainThreadHandler.updatePartialStore(ch-1) - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(ch-1, node.contents.value); - } - } - - }) - ) - }) - .catch((error: any) => { - logger.error(error) - }) - - } - - subscribeChannelName(ch: number, typeIndex: number, channelTypeIndex: number) { - this.emberConnection.getNodeByPath(this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_NAME[0].mixerMessage.replace("{channel}", String(channelTypeIndex+1))) - .then((node: any) => { - this.emberConnection.subscribe(node, (() => { - store.dispatch({ - type: SET_CHANNEL_LABEL, - channel: ch-1, - level: node.contents.value - }); - }) - ) - }) - } - - pingMixerCommand() { - //Ping Ember mixer if mixerProtocol needs it. - return; - this.mixerProtocol.pingCommand.map((command) => { - this.sendOutMessage( - command.mixerMessage, - 0, - command.value, - command.type - ); - }); - } - - sendOutMessage(mixerMessage: string, channel: number, value: string | number, type: string) { - let channelString = this.mixerProtocol.leadingZeros ? ("0"+channel).slice(-2) : channel.toString(); - - let message = mixerMessage.replace( - "{channel}", - channelString - ) - - this.emberConnection.getElementByPath(message) - .then((element: any) => { - logger.verbose('Sending out message : ' + message) - this.emberConnection.setValue( - this.emberNodeObject[channel-1], - typeof value === 'number' ? value : parseFloat(value) - ) - }) - .catch((error: any) => { - console.log("Ember Error ", error) - }) - } - - sendOutLevelMessage(channel: number, value: number) { - logger.verbose('Sending out Level: ' + String(value) + ' To Path : ' + JSON.stringify(this.emberNodeObject[channel])) - this.emberConnection.setValueNoAck( - this.emberNodeObject[channel-1], - value - ) - .catch((error: any) => { - console.log("Ember Error ", error) - }) - } - - sendOutRequest(mixerMessage: string, channel: number) { - let channelString = this.mixerProtocol.leadingZeros ? ("0"+channel).slice(-2) : channel.toString(); - let message = mixerMessage.replace( - "{channel}", - channelString - ); - if (message != 'none') { -/* - this.oscConnection.send({ - address: message - }); -*/ - } - } - - updateOutLevel(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let protocol = this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0] - let level = (state.channels[0].channel[channelIndex].outputLevel - protocol.min) * (protocol.max - protocol.min) - this.sendOutLevelMessage( - channelTypeIndex+1, - level, - ); - } - - updateFadeIOLevel(channelIndex: number, outputLevel: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let protocol = this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0] - let level = (outputLevel - protocol.min) * (protocol.max - protocol.min) - - this.sendOutLevelMessage( - channelTypeIndex+1, - level - ) - } - - updatePflState(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - - if (state.faders[0].fader[channelIndex].pflOn === true) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].mixerMessage, - channelTypeIndex+1, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].type - ); - } else { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].mixerMessage, - channelTypeIndex+1, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].type - ); - } - } - - updateMuteState(channelIndex: number, muteOn: boolean) { - return true - } - - updateNextAux(channelIndex: number, level: number) { - return true - } - - - updateThreshold(channelIndex: number, level: number) { - return true - } - updateRatio(channelIndex: number, level: number) { - return true - - } - updateDelayTime(channelIndex: number, level: number) { - return true - } - updateLow(channelIndex: number, level: number) { - return true - } - updateLoMid(channelIndex: number, level: number) { - return true - } - updateMid(channelIndex: number, level: number) { - return true - } - updateHigh(channelIndex: number, level: number) { - return true - } - updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { - return true - } - - updateChannelName(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let channelName = state.faders[0].fader[channelIndex].label; - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0].mixerMessage, - channelTypeIndex+1, - channelName, - "string" - ); - } - - injectCommand(command: string[]) { - return true - } - -} - +//@ts-ignore +import { EmberClient } from 'node-emberplus' +import { store, state } from '../../reducers/store' +import { remoteConnections } from '../../mainClasses' + +//Utils: +import { IMixerProtocol } from '../../constants/MixerProtocolInterface' +import { SET_FADER_LEVEL, SET_CHANNEL_LABEL } from '../../reducers/faderActions' +import { logger } from '../logger' + +export class EmberMixerConnection { + mixerProtocol: IMixerProtocol + emberConnection: EmberClient + deviceRoot: any + emberNodeObject: Array + + constructor(mixerProtocol: IMixerProtocol) { + this.sendOutMessage = this.sendOutMessage.bind(this) + this.pingMixerCommand = this.pingMixerCommand.bind(this) + + this.emberNodeObject = new Array(200) + this.mixerProtocol = mixerProtocol + + logger.info('Setting up Ember connection') + this.emberConnection = new EmberClient( + state.settings[0].deviceIp, + state.settings[0].devicePort + ) + + this.emberConnection.on('error', (error: any) => { + if ( + (error.message + '').match(/econnrefused/i) || + (error.message + '').match(/disconnected/i) + ) { + logger.error('Ember connection not establised') + } else { + logger.error('Ember connection unknown error' + error.message) + } + }) + this.emberConnection.on('disconnected', () => { + logger.error('Lost Ember connection') + }) + logger.info('Connecting to Ember') + let deviceRoot: any + this.emberConnection + .connect() + .then(() => { + console.log('Getting Directory') + return this.emberConnection.getDirectory() + }) + .then((r: any) => { + console.log('Directory :', r) + this.deviceRoot = r + this.emberConnection.expand(r.elements[0]).then(() => { + this.setupMixerConnection() + }) + }) + .catch((e: any) => { + console.log(e.stack) + }) + } + + setupMixerConnection() { + logger.info( + 'Ember connection established - setting up subscription of channels' + ) + + let ch: number = 1 + state.settings[0].numberOfChannelsInType.forEach( + (numberOfChannels, typeIndex) => { + for ( + let channelTypeIndex = 0; + channelTypeIndex < numberOfChannels; + channelTypeIndex++ + ) { + this.subscribeFaderLevel(ch, typeIndex, channelTypeIndex) + ch++ + } + } + ) + /* + .CHANNEL_VU)){ + store.dispatch({ + type:SET_VU_LEVEL, + channel: ch - 1, + level: message.args[0] + }); + */ + + //Ping OSC mixer if mixerProtocol needs it. + if (this.mixerProtocol.pingTime > 0) { + let emberTimer = setInterval(() => { + this.pingMixerCommand() + }, this.mixerProtocol.pingTime) + } + } + + subscribeFaderLevel( + ch: number, + typeIndex: number, + channelTypeIndex: number + ) { + let command = this.mixerProtocol.channelTypes[ + typeIndex + ].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.replace( + '{channel}', + String(channelTypeIndex + 1) + ) + this.emberConnection + .getElementByPath(command) + .then((node: any) => { + logger.info('Subscription of channel : ' + command) + this.emberNodeObject[ch - 1] = node + this.emberConnection.subscribe(node, () => { + logger.verbose('Receiving Level from Ch ' + String(ch)) + if ( + !state.channels[0].channel[ch - 1].fadeActive && + !state.channels[0].channel[ch - 1].fadeActive && + node.contents.value > + this.mixerProtocol.channelTypes[typeIndex].fromMixer + .CHANNEL_OUT_GAIN[0].min + ) { + store.dispatch({ + type: SET_FADER_LEVEL, + channel: ch - 1, + level: node.contents.value, + }) + global.mainThreadHandler.updatePartialStore(ch - 1) + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + ch - 1, + node.contents.value + ) + } + } + }) + }) + .catch((error: any) => { + logger.error(error) + }) + } + + subscribeChannelName( + ch: number, + typeIndex: number, + channelTypeIndex: number + ) { + this.emberConnection + .getNodeByPath( + this.mixerProtocol.channelTypes[ + typeIndex + ].fromMixer.CHANNEL_NAME[0].mixerMessage.replace( + '{channel}', + String(channelTypeIndex + 1) + ) + ) + .then((node: any) => { + this.emberConnection.subscribe(node, () => { + store.dispatch({ + type: SET_CHANNEL_LABEL, + channel: ch - 1, + level: node.contents.value, + }) + }) + }) + } + + pingMixerCommand() { + //Ping Ember mixer if mixerProtocol needs it. + return + this.mixerProtocol.pingCommand.map((command) => { + this.sendOutMessage( + command.mixerMessage, + 0, + command.value, + command.type + ) + }) + } + + sendOutMessage( + mixerMessage: string, + channel: number, + value: string | number, + type: string + ) { + let channelString = this.mixerProtocol.leadingZeros + ? ('0' + channel).slice(-2) + : channel.toString() + + let message = mixerMessage.replace('{channel}', channelString) + + this.emberConnection + .getElementByPath(message) + .then((element: any) => { + logger.verbose('Sending out message : ' + message) + this.emberConnection.setValue( + this.emberNodeObject[channel - 1], + typeof value === 'number' ? value : parseFloat(value) + ) + }) + .catch((error: any) => { + console.log('Ember Error ', error) + }) + } + + sendOutLevelMessage(channel: number, value: number) { + logger.verbose( + 'Sending out Level: ' + + String(value) + + ' To Path : ' + + JSON.stringify(this.emberNodeObject[channel]) + ) + this.emberConnection + .setValueNoAck(this.emberNodeObject[channel - 1], value) + .catch((error: any) => { + console.log('Ember Error ', error) + }) + } + + sendOutRequest(mixerMessage: string, channel: number) { + let channelString = this.mixerProtocol.leadingZeros + ? ('0' + channel).slice(-2) + : channel.toString() + let message = mixerMessage.replace('{channel}', channelString) + if (message != 'none') { + /* + this.oscConnection.send({ + address: message + }); +*/ + } + } + + updateOutLevel(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let protocol = this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0] + let level = + (state.channels[0].channel[channelIndex].outputLevel - + protocol.min) * + (protocol.max - protocol.min) + this.sendOutLevelMessage(channelTypeIndex + 1, level) + } + + updateFadeIOLevel(channelIndex: number, outputLevel: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let protocol = this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0] + let level = (outputLevel - protocol.min) * (protocol.max - protocol.min) + + this.sendOutLevelMessage(channelTypeIndex + 1, level) + } + + updatePflState(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + + if (state.faders[0].fader[channelIndex].pflOn === true) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .mixerMessage, + channelTypeIndex + 1, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .type + ) + } else { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .mixerMessage, + channelTypeIndex + 1, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .type + ) + } + } + + updateMuteState(channelIndex: number, muteOn: boolean) { + return true + } + + updateNextAux(channelIndex: number, level: number) { + return true + } + + updateThreshold(channelIndex: number, level: number) { + return true + } + updateRatio(channelIndex: number, level: number) { + return true + } + updateDelayTime(channelIndex: number, level: number) { + return true + } + updateLow(channelIndex: number, level: number) { + return true + } + updateLoMid(channelIndex: number, level: number) { + return true + } + updateMid(channelIndex: number, level: number) { + return true + } + updateHigh(channelIndex: number, level: number) { + return true + } + updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { + return true + } + + updateChannelName(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let channelName = state.faders[0].fader[channelIndex].label + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0] + .mixerMessage, + channelTypeIndex + 1, + channelName, + 'string' + ) + } + + injectCommand(command: string[]) { + return true + } +} diff --git a/server/utils/mixerConnections/MidiMixerConnection.ts b/server/utils/mixerConnections/MidiMixerConnection.ts index 2a9e05ae..c51dd521 100644 --- a/server/utils/mixerConnections/MidiMixerConnection.ts +++ b/server/utils/mixerConnections/MidiMixerConnection.ts @@ -1,247 +1,279 @@ - -// *** Work around to run Web-midi on nodejs *** - - -// The `web-midi-api` module takes care of importing the `jazz-midi` module (which needs to be -// installed) and the WebMIDIAPI shim (which is already part of `web-midi-api`). -global.navigator = require('web-midi-api') -// WebMidi.js depends on the browser's performance.now() so we fake it with the `performance-now` -// Node module (which is installed as a dependency of `web-midi-api`). -if (!global.performance) global.performance = { now: require('performance-now') }; -//Node Modules: -const WebMidi = require('webmidi') - -import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' - - -//Utils: -import { MixerProtocolPresets } from '../../constants/MixerProtocolPresets'; -import { IMixerProtocol } from '../../constants/MixerProtocolInterface'; -import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' -import { - SET_VU_LEVEL, - SET_FADER_LEVEL, - SET_CHANNEL_LABEL, - TOGGLE_PGM -} from '../../reducers/faderActions' - - -export class MidiMixerConnection { - store: any; - mixerProtocol: any; - midiInput: any; - midiOutput:any; - - constructor(mixerProtocol: IMixerProtocol) { - this.sendOutMessage = this.sendOutMessage.bind(this); - this.pingMixerCommand = this.pingMixerCommand.bind(this); - - this.mixerProtocol = mixerProtocol || MixerProtocolPresets.genericMidi; - - WebMidi.enable((err: any) => { - - if (err) { - console.log("WebMidi could not be enabled.", err); - } - console.log("Connecting Mixer Midi input on port :", state.settings[0].mixerMidiInputPort); - console.log("Connecting Mixer Midi output on port :", state.settings[0].mixerMidiOutputPort); - this.midiInput = WebMidi.getInputByName(state.settings[0].mixerMidiInputPort); - this.midiOutput = WebMidi.getOutputByName(state.settings[0].mixerMidiOutputPort); - - this.setupMixerConnection(); - }); - } - - setupMixerConnection() { - this.midiInput.addListener('controlchange', 1, - (message: any) => { - console.log("Received 'controlchange' message (" + message.data + ")."); - if (message.data[1] >= parseInt(this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage) - && message.data[1] <= parseInt(this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage) + 24) { - let ch = 1 + message.data[1] - parseInt(this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage) - let faderChannel = 1 + state.channels[0].channel[ch - 1].assignedFader - store.dispatch({ - type: SET_FADER_LEVEL, - channel: faderChannel - 1, - level: message.data[2] - }); - if (!state.faders[0].fader[faderChannel - 1].pgmOn) { - store.dispatch({ - type: TOGGLE_PGM, - channel: state.channels[0].channel[ch - 1].assignedFader -1 - }); - } - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(faderChannel - 1, state.faders[0].fader[faderChannel - 1].faderLevel) - } - if (state.faders[0].fader[faderChannel - 1].pgmOn && this.mixerProtocol.mode === 'master') - { - state.channels[0].channel.map((channel: any, index: number) => { - if (channel.assignedFader === faderChannel - 1) { - this.updateOutLevel(index); - } - }) - } - } - } - ); - this.midiInput.addListener('noteon', "all", - (error: any) => { - console.log("Received 'noteon' message (" + error.note.name + error.note.octave + ")."); - } - ); -/* - if ( - this.checkOscCommand(message.address, this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_VU) - ) { - if (state.settings[0].mixerProtocol === 'behringer') { - behringerMeter(message.args); - } else { - let ch = message.address.split("/")[2]; - store.dispatch({ - type:SET_VU_LEVEL, - channel: ch - 1, - level: message.args[0] - }); - } - } - if ( - this.checkOscCommand(message.address, this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_NAME) - ) { - let ch = message.address.split("/")[2]; - store.dispatch({ - type: SET_CHANNEL_LABEL, - channel: ch - 1, - label: message.args[0] - }); - console.log("OSC message: ", message.address); - } -*/ -return true; - //Ping OSC mixer if mixerProtocol needs it. - if (this.mixerProtocol.pingTime > 0) { - let oscTimer = setInterval( - () => { - this.pingMixerCommand(); - }, - this.mixerProtocol.pingTime - ); - } - } - - pingMixerCommand() { - //Ping OSC mixer if mixerProtocol needs it. - this.mixerProtocol.pingCommand.map((command: any) => { - this.sendOutMessage( - command.mixerMessage, - 0, - command.value - ); - }); - } - - sendOutMessage(ctrlMessage: string, channel: number, value: string) { - if (ctrlMessage != "none" && 0 <= parseFloat(value) && parseFloat(value) <= 127) { - let ctrlMessageInt = (parseInt(ctrlMessage) + channel - 1) - this.midiOutput.sendControlChange(ctrlMessageInt, value, 1); - } - } - - updateOutLevel(channelIndex: number) { - let faderIndex = state.channels[0].channel[channelIndex].assignedFader; - if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch({ - type:SET_OUTPUT_LEVEL, - channel: channelIndex, - level: state.faders[0].fader[faderIndex].faderLevel - }); - } - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelIndex+1, - String(state.channels[0].channel[channelIndex].outputLevel) - ); - /* Client mode is disabled - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_FADER_LEVEL[0].mixerMessage, - channelIndex+1, - state.faders[0].fader[channelIndex].faderLevel - ); - */ - } - - updatePflState(channelIndex: number) { - - if (state.faders[0].fader[channelIndex].pflOn === true) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.PFL_ON[0].mixerMessage, - channelIndex+1, - this.mixerProtocol.channelTypes[0].toMixer.PFL_ON[0].value - ); - } else { - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.PFL_OFF[0].mixerMessage, - channelIndex+1, - this.mixerProtocol.channelTypes[0].toMixer.PFL_OFF[0].value - ); - } - } - - updateMuteState(channelIndex: number, muteOn: boolean) { - return true - } - - updateNextAux(channelIndex: number, level: number) { - return true - } - updateThreshold(channelIndex: number, level: number) { - return true - } - updateRatio(channelIndex: number, level: number) { - return true - - } - updateDelayTime(channelIndex: number, level: number) { - return true - } - updateLow(channelIndex: number, level: number) { - return true - } - updateLoMid(channelIndex: number, level: number) { - return true - } - updateMid(channelIndex: number, level: number) { - return true - } - updateHigh(channelIndex: number, level: number) { - return true - } - updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { - return true - } - - updateFadeIOLevel(channelIndex: number, outputLevel: number) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelIndex+1, - String(outputLevel) - ); - } - - - updateChannelName(channelIndex: number) { - let channelName = state.faders[0].fader[channelIndex].label; - this.sendOutMessage( - this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_NAME[0].mixerMessage, - channelIndex+1, - channelName - ); - } - - injectCommand(command: string[]) { - return true - } - -} - +// *** Work around to run Web-midi on nodejs *** + +// The `web-midi-api` module takes care of importing the `jazz-midi` module (which needs to be +// installed) and the WebMIDIAPI shim (which is already part of `web-midi-api`). +global.navigator = require('web-midi-api') +// WebMidi.js depends on the browser's performance.now() so we fake it with the `performance-now` +// Node module (which is installed as a dependency of `web-midi-api`). +if (!global.performance) + global.performance = { now: require('performance-now') } +//Node Modules: +const WebMidi = require('webmidi') + +import { store, state } from '../../reducers/store' +import { remoteConnections } from '../../mainClasses' + +//Utils: +import { MixerProtocolPresets } from '../../constants/MixerProtocolPresets' +import { IMixerProtocol } from '../../constants/MixerProtocolInterface' +import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' +import { + SET_VU_LEVEL, + SET_FADER_LEVEL, + SET_CHANNEL_LABEL, + TOGGLE_PGM, +} from '../../reducers/faderActions' + +export class MidiMixerConnection { + store: any + mixerProtocol: any + midiInput: any + midiOutput: any + + constructor(mixerProtocol: IMixerProtocol) { + this.sendOutMessage = this.sendOutMessage.bind(this) + this.pingMixerCommand = this.pingMixerCommand.bind(this) + + this.mixerProtocol = mixerProtocol || MixerProtocolPresets.genericMidi + + WebMidi.enable((err: any) => { + if (err) { + console.log('WebMidi could not be enabled.', err) + } + console.log( + 'Connecting Mixer Midi input on port :', + state.settings[0].mixerMidiInputPort + ) + console.log( + 'Connecting Mixer Midi output on port :', + state.settings[0].mixerMidiOutputPort + ) + this.midiInput = WebMidi.getInputByName( + state.settings[0].mixerMidiInputPort + ) + this.midiOutput = WebMidi.getOutputByName( + state.settings[0].mixerMidiOutputPort + ) + + this.setupMixerConnection() + }) + } + + setupMixerConnection() { + this.midiInput.addListener('controlchange', 1, (message: any) => { + console.log( + "Received 'controlchange' message (" + message.data + ').' + ) + if ( + message.data[1] >= + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) && + message.data[1] <= + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) + + 24 + ) { + let ch = + 1 + + message.data[1] - + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) + let faderChannel = + 1 + state.channels[0].channel[ch - 1].assignedFader + store.dispatch({ + type: SET_FADER_LEVEL, + channel: faderChannel - 1, + level: message.data[2], + }) + if (!state.faders[0].fader[faderChannel - 1].pgmOn) { + store.dispatch({ + type: TOGGLE_PGM, + channel: + state.channels[0].channel[ch - 1].assignedFader - 1, + }) + } + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + faderChannel - 1, + state.faders[0].fader[faderChannel - 1].faderLevel + ) + } + if ( + state.faders[0].fader[faderChannel - 1].pgmOn && + this.mixerProtocol.mode === 'master' + ) { + state.channels[0].channel.map( + (channel: any, index: number) => { + if (channel.assignedFader === faderChannel - 1) { + this.updateOutLevel(index) + } + } + ) + } + } + }) + this.midiInput.addListener('noteon', 'all', (error: any) => { + console.log( + "Received 'noteon' message (" + + error.note.name + + error.note.octave + + ').' + ) + }) + /* + if ( + this.checkOscCommand(message.address, this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_VU) + ) { + if (state.settings[0].mixerProtocol === 'behringer') { + behringerMeter(message.args); + } else { + let ch = message.address.split("/")[2]; + store.dispatch({ + type:SET_VU_LEVEL, + channel: ch - 1, + level: message.args[0] + }); + } + } + if ( + this.checkOscCommand(message.address, this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_NAME) + ) { + let ch = message.address.split("/")[2]; + store.dispatch({ + type: SET_CHANNEL_LABEL, + channel: ch - 1, + label: message.args[0] + }); + console.log("OSC message: ", message.address); + } +*/ + return true + //Ping OSC mixer if mixerProtocol needs it. + if (this.mixerProtocol.pingTime > 0) { + let oscTimer = setInterval(() => { + this.pingMixerCommand() + }, this.mixerProtocol.pingTime) + } + } + + pingMixerCommand() { + //Ping OSC mixer if mixerProtocol needs it. + this.mixerProtocol.pingCommand.map((command: any) => { + this.sendOutMessage(command.mixerMessage, 0, command.value) + }) + } + + sendOutMessage(ctrlMessage: string, channel: number, value: string) { + if ( + ctrlMessage != 'none' && + 0 <= parseFloat(value) && + parseFloat(value) <= 127 + ) { + let ctrlMessageInt = parseInt(ctrlMessage) + channel - 1 + this.midiOutput.sendControlChange(ctrlMessageInt, value, 1) + } + } + + updateOutLevel(channelIndex: number) { + let faderIndex = state.channels[0].channel[channelIndex].assignedFader + if (state.faders[0].fader[faderIndex].pgmOn) { + store.dispatch({ + type: SET_OUTPUT_LEVEL, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) + } + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_OUT_GAIN[0] + .mixerMessage, + channelIndex + 1, + String(state.channels[0].channel[channelIndex].outputLevel) + ) + /* Client mode is disabled + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_FADER_LEVEL[0].mixerMessage, + channelIndex+1, + state.faders[0].fader[channelIndex].faderLevel + ); + */ + } + + updatePflState(channelIndex: number) { + if (state.faders[0].fader[channelIndex].pflOn === true) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.PFL_ON[0] + .mixerMessage, + channelIndex + 1, + this.mixerProtocol.channelTypes[0].toMixer.PFL_ON[0].value + ) + } else { + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.PFL_OFF[0] + .mixerMessage, + channelIndex + 1, + this.mixerProtocol.channelTypes[0].toMixer.PFL_OFF[0].value + ) + } + } + + updateMuteState(channelIndex: number, muteOn: boolean) { + return true + } + + updateNextAux(channelIndex: number, level: number) { + return true + } + updateThreshold(channelIndex: number, level: number) { + return true + } + updateRatio(channelIndex: number, level: number) { + return true + } + updateDelayTime(channelIndex: number, level: number) { + return true + } + updateLow(channelIndex: number, level: number) { + return true + } + updateLoMid(channelIndex: number, level: number) { + return true + } + updateMid(channelIndex: number, level: number) { + return true + } + updateHigh(channelIndex: number, level: number) { + return true + } + updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { + return true + } + + updateFadeIOLevel(channelIndex: number, outputLevel: number) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_OUT_GAIN[0] + .mixerMessage, + channelIndex + 1, + String(outputLevel) + ) + } + + updateChannelName(channelIndex: number) { + let channelName = state.faders[0].fader[channelIndex].label + this.sendOutMessage( + this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_NAME[0] + .mixerMessage, + channelIndex + 1, + channelName + ) + } + + injectCommand(command: string[]) { + return true + } +} diff --git a/server/utils/mixerConnections/OscMixerConnection.ts b/server/utils/mixerConnections/OscMixerConnection.ts index e76b3608..b3134b81 100644 --- a/server/utils/mixerConnections/OscMixerConnection.ts +++ b/server/utils/mixerConnections/OscMixerConnection.ts @@ -1,7 +1,7 @@ //Node Modules: const osc = require('osc') import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' +import { remoteConnections } from '../../mainClasses' import { socketServer } from '../../expressHandler' //Utils: @@ -218,8 +218,8 @@ export class OscMixerConnection { assignedFaderIndex ) - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState( + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( assignedFaderIndex, message.args[0] ) diff --git a/server/utils/mixerConnections/SSLMixerConnection.ts b/server/utils/mixerConnections/SSLMixerConnection.ts index 0cfee381..53eed68d 100644 --- a/server/utils/mixerConnections/SSLMixerConnection.ts +++ b/server/utils/mixerConnections/SSLMixerConnection.ts @@ -1,423 +1,533 @@ -//Node Modules: -const net = require('net') -import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' - -//Utils: -import { IMixerProtocol } from '../../constants/MixerProtocolInterface' -import { IStore } from '../../reducers/indexReducer' -import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' -import { - SET_FADER_LEVEL, - TOGGLE_PGM, - SET_MUTE - } from '../../reducers/faderActions' -import { SET_MIXER_ONLINE } from '../../reducers/settingsActions'; -import { logger } from '../logger' - -export class SSLMixerConnection { - mixerProtocol: IMixerProtocol; - cmdChannelIndex: number; - SSLConnection: any; - mixerOnlineTimer: any; - - constructor(mixerProtocol: IMixerProtocol) { - this.sendOutLevelMessage = this.sendOutLevelMessage.bind(this); - - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: false - }); - - this.mixerProtocol = mixerProtocol; - - this.cmdChannelIndex = this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.split('/').findIndex(ch => ch === '{channel}'); - - this.SSLConnection = new net.Socket() - this.SSLConnection.connect(state.settings[0].devicePort, state.settings[0].deviceIp, () => { - logger.info('Connected to SSL', {}) - - } - ); - this.setupMixerConnection(); - } - - formatHexWithSpaces(str: string, item: string, every: number) { - for(let i = 0; i < str.length; i++){ - if(!(i % (every + 1))){ - str = str.substring(0, i) + item + str.substring(i); - } - } - return str.substring(1); - } - - setupMixerConnection() { - // Return command was an acknowledge: - let lastWasAck = false - - this.SSLConnection - .on("ready", () => { - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: true - }); - - logger.info("Receiving state of desk", {}) - this.mixerProtocol.initializeCommands.map((item) => { - if (item.mixerMessage.includes("{channel}")) { - state.channels[0].channel.map((channel: any, index: any) => { - this.sendOutRequest(item.mixerMessage, index); - }); - } else { - this.sendOutLevelMessage(item.mixerMessage, 0, item.value); - } - }); - global.mainThreadHandler.updateFullClientStore() - }) - .on('data', (data: any) => { - clearTimeout(this.mixerOnlineTimer) - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: true - }); - - let buffers = [] - let lastIndex = 0 - for (let index=1; index { - if (buffer[1] === 6 && buffer[2] === 255 && !lastWasAck) { - lastWasAck = false - // FADERLEVEL COMMAND: - try { - - - let commandHex = buffer.toString('hex') - let channel = buffer[6] - let value = buffer.readUInt16BE(7)/1024 - - let assignedFaderIndex = state.channels[0].channel[channel].assignedFader - if (!state.channels[0].channel[channel].fadeActive) { - if (value > this.mixerProtocol.fader.min + (this.mixerProtocol.fader.max * state.settings[0].autoResetLevel / 100)) { - store.dispatch({ - type: SET_FADER_LEVEL, - channel: assignedFaderIndex, - level: value - }); - if (!state.faders[0].fader[assignedFaderIndex].pgmOn) { - store.dispatch({ - type: TOGGLE_PGM, - channel: assignedFaderIndex - }); - } - - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(assignedFaderIndex, value); - } - if (state.faders[0].fader[assignedFaderIndex].pgmOn) { - state.channels[0].channel.map((channel: any, index: number) => { - if (channel.assignedFader === assignedFaderIndex) { - this.updateOutLevel(index); - } - }) - } - } else if (state.faders[0].fader[assignedFaderIndex].pgmOn - || state.faders[0].fader[assignedFaderIndex].voOn) - { - store.dispatch({ - type: SET_FADER_LEVEL, - channel: assignedFaderIndex, - level: value - }); - state.channels[0].channel.forEach((item, index) => { - if (item.assignedFader === assignedFaderIndex) { - store.dispatch({ - type: SET_OUTPUT_LEVEL, - channel: index, - level: value - }); - } - }) - } - global.mainThreadHandler.updatePartialStore(assignedFaderIndex) - } - } catch (error) { - logger.error('Error translating received message :' + String(error), {}) - } - - } else if (buffer[1] === 5 && buffer[2] === 255 && buffer[4] === 1 && !lastWasAck) { - lastWasAck = false - // MUTE ON/OFF COMMAND - let commandHex = buffer.toString('hex') - let channelIndex = buffer[6] - let value: boolean = buffer[7] === 0 ? true : false - logger.verbose('Receive Buffer Channel On/off: ' + this.formatHexWithSpaces(commandHex, ' ', 2), {}) - - let assignedFaderIndex = state.channels[0].channel[channelIndex].assignedFader - - store.dispatch({ - type: SET_MUTE, - channel: assignedFaderIndex, - muteOn: value - }); - - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(assignedFaderIndex, value ? 1 : 0); - } - state.channels[0].channel.forEach((channel: any, index: number) => { - if (channel.assignedFader === assignedFaderIndex && index !== channelIndex) { - this.updateMuteState(index, state.faders[0].fader[assignedFaderIndex].muteOn); - } - }) - global.mainThreadHandler.updatePartialStore(assignedFaderIndex) - } else { - let commandHex = buffer.toString('hex') - logger.verbose('Receieve Buffer Hex: ' + this.formatHexWithSpaces(commandHex, ' ', 2), {}) - } - if (buffer[0] === 4) { - lastWasAck = true - } else { - lastWasAck = false - } - }) - }) - .on('error', (error: any) => { - logger.error("Error : " + String(error), {}) - logger.info("Lost SCP connection", {}) - }); - - //Ping mixer to get mixerOnlineState - let oscTimer = setInterval( - () => { - this.pingMixerCommand(); - }, - this.mixerProtocol.pingTime - ); - } - - pingMixerCommand() { - //Ping OSC mixer if mixerProtocol needs it. - this.mixerProtocol.pingCommand.forEach((command) => { - this.sendOutPingRequest(); - }); - global.mainThreadHandler.updateFullClientStore() - this.mixerOnlineTimer = setTimeout(() => { - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: false - }); - }, this.mixerProtocol.pingTime) - } - - checkSSLCommand(message: string, command: string) { - if (!message) return false - if (message.slice(0, command.length) === command) return true; - return false; - } - - calculate_checksum8(hexValues: string) { - // convert input value to upper case - hexValues = hexValues.toUpperCase(); - - let strHex = new String("0123456789ABCDEF"); - let result = 0; - let fctr = 16; - - for (let i = 0; i < hexValues.length; i++) { - if (hexValues.charAt(i) == " ") - continue; - - let v = strHex.indexOf(hexValues.charAt(i)); - if (v < 0) { - result = -1; - break; - } - result += v * fctr; - - if (fctr == 16) - fctr = 1; - else - fctr = 16; - } - - // Calculate 2's complement - result = (~(result & 0xff) + 1) & 0xFF; - // Convert result to string - return strHex.charAt(Math.floor(result / 16)) + strHex.charAt(result % 16); - } - - - sendOutLevelMessage(sslMessage: string, channelIndex: number, value: string | number) { - let valueNumber: number - if (typeof value === 'string') { - value = parseFloat(value) - } - if (value < 0) { - value = 0 - } - valueNumber = value * 1024 - let valueByte = new Uint8Array([ - (valueNumber & 0x0000ff00) >> 8, - (valueNumber & 0x000000ff), - ]) - - let channelByte = new Uint8Array([ - (channelIndex & 0x0000ff00) >> 8, - (channelIndex & 0x000000ff), - ]) - - sslMessage = sslMessage.replace('{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + ' ' + ('0' + channelByte[1].toString(16)).slice(-2)) - sslMessage = sslMessage.replace('{level}', ('0' + valueByte[0].toString(16)).slice(-2) + ' ' + ('0' + valueByte[1].toString(16)).slice(-2) + ' ') - sslMessage = sslMessage + this.calculate_checksum8(sslMessage.slice(9)) - let a = sslMessage.split(' ') - let buf = new Buffer(a.map((val:string) => { return parseInt(val, 16) })) - - logger.verbose("Send HEX: " + sslMessage, {}) - this.SSLConnection.write(buf) - } - - sendOutRequest(sslMessage: string, channelIndex: number) { - //let sslMessage = 'f1 06 00 80 00 00 {channel} {level}' - let channelByte = new Uint8Array([ - (channelIndex & 0x0000ff00) >> 8, - (channelIndex & 0x000000ff), - ]) - sslMessage = sslMessage.replace('{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + ' ' + ('0' + channelByte[1].toString(16)).slice(-2)) - sslMessage = sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) - let a = sslMessage.split(' ') - let buf = new Buffer(a.map((val:string) => { return parseInt(val, 16) })) - - logger.verbose("Send HEX: " + sslMessage, {}) - this.SSLConnection.write(buf) - } - - sendOutPingRequest() { - let sslMessage = 'f1 02 00 07 00' - sslMessage = sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) - let a = sslMessage.split(' ') - let buf = new Buffer(a.map((val:string) => { return parseInt(val, 16) })) - - logger.verbose("Send HEX: " + sslMessage, {}) - this.SSLConnection.write(buf) - } - - updateOutLevel(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let faderIndex = state.channels[0].channel[channelIndex].assignedFader; - if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch({ - type:SET_OUTPUT_LEVEL, - channel: channelIndex, - level: state.faders[0].fader[faderIndex].faderLevel - }); - } - this.sendOutLevelMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelTypeIndex, - state.channels[0].channel[channelIndex].outputLevel - ); - } - - updatePflState(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - if (state.faders[0].fader[channelIndex].pflOn === true) { - this.sendOutRequest( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].mixerMessage, - channelTypeIndex - ); - } else { - this.sendOutRequest( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].mixerMessage, - channelTypeIndex - ); - } - } - - updateMuteState(channelIndex: number, muteOn: boolean) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - if (muteOn === true) { - this.sendOutRequest( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_MUTE_ON[0].mixerMessage, - channelTypeIndex - ); - } else { - this.sendOutRequest( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_MUTE_OFF[0].mixerMessage, - channelTypeIndex - ); - } - } - - updateFadeIOLevel(channelIndex: number, outputLevel: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - this.sendOutLevelMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelTypeIndex, - String(outputLevel) - ); - } - - updateNextAux(channelIndex: number, level: number) { - this.sendOutLevelMessage( - this.mixerProtocol.channelTypes[0].toMixer.NEXT_SEND[0].mixerMessage, - channelIndex + 128, - level - ); - } - updateThreshold(channelIndex: number, level: number) { - return true - } - updateRatio(channelIndex: number, level: number) { - return true - - } - updateDelayTime(channelIndex: number, level: number) { - return true - } - updateLow(channelIndex: number, level: number) { - return true - } - updateLoMid(channelIndex: number, level: number) { - return true - } - updateMid(channelIndex: number, level: number) { - return true - } - updateHigh(channelIndex: number, level: number) { - return true - } - updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { - return true - } - - updateChannelName(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let channelName = state.faders[0].fader[channelIndex].label; - /* - this.sendOutLevelMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0].mixerMessage, - channelTypeIndex, - channelName - ); - */ - } - - injectCommand(command: string[]) { - return true - } - -} - +//Node Modules: +const net = require('net') +import { store, state } from '../../reducers/store' +import { remoteConnections } from '../../mainClasses' + +//Utils: +import { IMixerProtocol } from '../../constants/MixerProtocolInterface' +import { IStore } from '../../reducers/indexReducer' +import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' +import { + SET_FADER_LEVEL, + TOGGLE_PGM, + SET_MUTE, +} from '../../reducers/faderActions' +import { SET_MIXER_ONLINE } from '../../reducers/settingsActions' +import { logger } from '../logger' + +export class SSLMixerConnection { + mixerProtocol: IMixerProtocol + cmdChannelIndex: number + SSLConnection: any + mixerOnlineTimer: any + + constructor(mixerProtocol: IMixerProtocol) { + this.sendOutLevelMessage = this.sendOutLevelMessage.bind(this) + + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: false, + }) + + this.mixerProtocol = mixerProtocol + + this.cmdChannelIndex = this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage + .split('/') + .findIndex((ch) => ch === '{channel}') + + this.SSLConnection = new net.Socket() + this.SSLConnection.connect( + state.settings[0].devicePort, + state.settings[0].deviceIp, + () => { + logger.info('Connected to SSL', {}) + } + ) + this.setupMixerConnection() + } + + formatHexWithSpaces(str: string, item: string, every: number) { + for (let i = 0; i < str.length; i++) { + if (!(i % (every + 1))) { + str = str.substring(0, i) + item + str.substring(i) + } + } + return str.substring(1) + } + + setupMixerConnection() { + // Return command was an acknowledge: + let lastWasAck = false + + this.SSLConnection.on('ready', () => { + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: true, + }) + + logger.info('Receiving state of desk', {}) + this.mixerProtocol.initializeCommands.map((item) => { + if (item.mixerMessage.includes('{channel}')) { + state.channels[0].channel.map( + (channel: any, index: any) => { + this.sendOutRequest(item.mixerMessage, index) + } + ) + } else { + this.sendOutLevelMessage(item.mixerMessage, 0, item.value) + } + }) + global.mainThreadHandler.updateFullClientStore() + }) + .on('data', (data: any) => { + clearTimeout(this.mixerOnlineTimer) + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: true, + }) + + let buffers = [] + let lastIndex = 0 + for (let index = 1; index < data.length; index++) { + if (data[index] === 241) { + buffers.push(data.slice(lastIndex, index - 1)) + lastIndex = index + } + } + if (buffers.length === 0) { + buffers.push(data) + } + + buffers.forEach((buffer) => { + if (buffer[1] === 6 && buffer[2] === 255 && !lastWasAck) { + lastWasAck = false + // FADERLEVEL COMMAND: + try { + let commandHex = buffer.toString('hex') + let channel = buffer[6] + let value = buffer.readUInt16BE(7) / 1024 + + let assignedFaderIndex = + state.channels[0].channel[channel].assignedFader + if ( + !state.channels[0].channel[channel].fadeActive + ) { + if ( + value > + this.mixerProtocol.fader.min + + (this.mixerProtocol.fader.max * + state.settings[0].autoResetLevel) / + 100 + ) { + store.dispatch({ + type: SET_FADER_LEVEL, + channel: assignedFaderIndex, + level: value, + }) + if ( + !state.faders[0].fader[ + assignedFaderIndex + ].pgmOn + ) { + store.dispatch({ + type: TOGGLE_PGM, + channel: assignedFaderIndex, + }) + } + + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + assignedFaderIndex, + value + ) + } + if ( + state.faders[0].fader[ + assignedFaderIndex + ].pgmOn + ) { + state.channels[0].channel.map( + (channel: any, index: number) => { + if ( + channel.assignedFader === + assignedFaderIndex + ) { + this.updateOutLevel(index) + } + } + ) + } + } else if ( + state.faders[0].fader[assignedFaderIndex] + .pgmOn || + state.faders[0].fader[assignedFaderIndex] + .voOn + ) { + store.dispatch({ + type: SET_FADER_LEVEL, + channel: assignedFaderIndex, + level: value, + }) + state.channels[0].channel.forEach( + (item, index) => { + if ( + item.assignedFader === + assignedFaderIndex + ) { + store.dispatch({ + type: SET_OUTPUT_LEVEL, + channel: index, + level: value, + }) + } + } + ) + } + global.mainThreadHandler.updatePartialStore( + assignedFaderIndex + ) + } + } catch (error) { + logger.error( + 'Error translating received message :' + + String(error), + {} + ) + } + } else if ( + buffer[1] === 5 && + buffer[2] === 255 && + buffer[4] === 1 && + !lastWasAck + ) { + lastWasAck = false + // MUTE ON/OFF COMMAND + let commandHex = buffer.toString('hex') + let channelIndex = buffer[6] + let value: boolean = buffer[7] === 0 ? true : false + logger.verbose( + 'Receive Buffer Channel On/off: ' + + this.formatHexWithSpaces(commandHex, ' ', 2), + {} + ) + + let assignedFaderIndex = + state.channels[0].channel[channelIndex] + .assignedFader + + store.dispatch({ + type: SET_MUTE, + channel: assignedFaderIndex, + muteOn: value, + }) + + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + assignedFaderIndex, + value ? 1 : 0 + ) + } + state.channels[0].channel.forEach( + (channel: any, index: number) => { + if ( + channel.assignedFader === + assignedFaderIndex && + index !== channelIndex + ) { + this.updateMuteState( + index, + state.faders[0].fader[ + assignedFaderIndex + ].muteOn + ) + } + } + ) + global.mainThreadHandler.updatePartialStore( + assignedFaderIndex + ) + } else { + let commandHex = buffer.toString('hex') + logger.verbose( + 'Receieve Buffer Hex: ' + + this.formatHexWithSpaces(commandHex, ' ', 2), + {} + ) + } + if (buffer[0] === 4) { + lastWasAck = true + } else { + lastWasAck = false + } + }) + }) + .on('error', (error: any) => { + logger.error('Error : ' + String(error), {}) + logger.info('Lost SCP connection', {}) + }) + + //Ping mixer to get mixerOnlineState + let oscTimer = setInterval(() => { + this.pingMixerCommand() + }, this.mixerProtocol.pingTime) + } + + pingMixerCommand() { + //Ping OSC mixer if mixerProtocol needs it. + this.mixerProtocol.pingCommand.forEach((command) => { + this.sendOutPingRequest() + }) + global.mainThreadHandler.updateFullClientStore() + this.mixerOnlineTimer = setTimeout(() => { + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: false, + }) + }, this.mixerProtocol.pingTime) + } + + checkSSLCommand(message: string, command: string) { + if (!message) return false + if (message.slice(0, command.length) === command) return true + return false + } + + calculate_checksum8(hexValues: string) { + // convert input value to upper case + hexValues = hexValues.toUpperCase() + + let strHex = new String('0123456789ABCDEF') + let result = 0 + let fctr = 16 + + for (let i = 0; i < hexValues.length; i++) { + if (hexValues.charAt(i) == ' ') continue + + let v = strHex.indexOf(hexValues.charAt(i)) + if (v < 0) { + result = -1 + break + } + result += v * fctr + + if (fctr == 16) fctr = 1 + else fctr = 16 + } + + // Calculate 2's complement + result = (~(result & 0xff) + 1) & 0xff + // Convert result to string + return ( + strHex.charAt(Math.floor(result / 16)) + strHex.charAt(result % 16) + ) + } + + sendOutLevelMessage( + sslMessage: string, + channelIndex: number, + value: string | number + ) { + let valueNumber: number + if (typeof value === 'string') { + value = parseFloat(value) + } + if (value < 0) { + value = 0 + } + valueNumber = value * 1024 + let valueByte = new Uint8Array([ + (valueNumber & 0x0000ff00) >> 8, + valueNumber & 0x000000ff, + ]) + + let channelByte = new Uint8Array([ + (channelIndex & 0x0000ff00) >> 8, + channelIndex & 0x000000ff, + ]) + + sslMessage = sslMessage.replace( + '{channel}', + ('0' + channelByte[0].toString(16)).slice(-2) + + ' ' + + ('0' + channelByte[1].toString(16)).slice(-2) + ) + sslMessage = sslMessage.replace( + '{level}', + ('0' + valueByte[0].toString(16)).slice(-2) + + ' ' + + ('0' + valueByte[1].toString(16)).slice(-2) + + ' ' + ) + sslMessage = sslMessage + this.calculate_checksum8(sslMessage.slice(9)) + let a = sslMessage.split(' ') + let buf = new Buffer( + a.map((val: string) => { + return parseInt(val, 16) + }) + ) + + logger.verbose('Send HEX: ' + sslMessage, {}) + this.SSLConnection.write(buf) + } + + sendOutRequest(sslMessage: string, channelIndex: number) { + //let sslMessage = 'f1 06 00 80 00 00 {channel} {level}' + let channelByte = new Uint8Array([ + (channelIndex & 0x0000ff00) >> 8, + channelIndex & 0x000000ff, + ]) + sslMessage = sslMessage.replace( + '{channel}', + ('0' + channelByte[0].toString(16)).slice(-2) + + ' ' + + ('0' + channelByte[1].toString(16)).slice(-2) + ) + sslMessage = + sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) + let a = sslMessage.split(' ') + let buf = new Buffer( + a.map((val: string) => { + return parseInt(val, 16) + }) + ) + + logger.verbose('Send HEX: ' + sslMessage, {}) + this.SSLConnection.write(buf) + } + + sendOutPingRequest() { + let sslMessage = 'f1 02 00 07 00' + sslMessage = + sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) + let a = sslMessage.split(' ') + let buf = new Buffer( + a.map((val: string) => { + return parseInt(val, 16) + }) + ) + + logger.verbose('Send HEX: ' + sslMessage, {}) + this.SSLConnection.write(buf) + } + + updateOutLevel(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let faderIndex = state.channels[0].channel[channelIndex].assignedFader + if (state.faders[0].fader[faderIndex].pgmOn) { + store.dispatch({ + type: SET_OUTPUT_LEVEL, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) + } + this.sendOutLevelMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0].mixerMessage, + channelTypeIndex, + state.channels[0].channel[channelIndex].outputLevel + ) + } + + updatePflState(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + if (state.faders[0].fader[channelIndex].pflOn === true) { + this.sendOutRequest( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .mixerMessage, + channelTypeIndex + ) + } else { + this.sendOutRequest( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .mixerMessage, + channelTypeIndex + ) + } + } + + updateMuteState(channelIndex: number, muteOn: boolean) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + if (muteOn === true) { + this.sendOutRequest( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_MUTE_ON[0].mixerMessage, + channelTypeIndex + ) + } else { + this.sendOutRequest( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_MUTE_OFF[0].mixerMessage, + channelTypeIndex + ) + } + } + + updateFadeIOLevel(channelIndex: number, outputLevel: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + this.sendOutLevelMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0].mixerMessage, + channelTypeIndex, + String(outputLevel) + ) + } + + updateNextAux(channelIndex: number, level: number) { + this.sendOutLevelMessage( + this.mixerProtocol.channelTypes[0].toMixer.NEXT_SEND[0] + .mixerMessage, + channelIndex + 128, + level + ) + } + updateThreshold(channelIndex: number, level: number) { + return true + } + updateRatio(channelIndex: number, level: number) { + return true + } + updateDelayTime(channelIndex: number, level: number) { + return true + } + updateLow(channelIndex: number, level: number) { + return true + } + updateLoMid(channelIndex: number, level: number) { + return true + } + updateMid(channelIndex: number, level: number) { + return true + } + updateHigh(channelIndex: number, level: number) { + return true + } + updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { + return true + } + + updateChannelName(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let channelName = state.faders[0].fader[channelIndex].label + /* + this.sendOutLevelMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0].mixerMessage, + channelTypeIndex, + channelName + ); + */ + } + + injectCommand(command: string[]) { + return true + } +} diff --git a/server/utils/mixerConnections/StuderMixerConnection.ts b/server/utils/mixerConnections/StuderMixerConnection.ts index 9be411db..7f193fa5 100644 --- a/server/utils/mixerConnections/StuderMixerConnection.ts +++ b/server/utils/mixerConnections/StuderMixerConnection.ts @@ -1,320 +1,362 @@ -//@ts-ignore -import { EmberClient } from 'node-emberplus' -import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' - -//Utils: -import { IMixerProtocol } from '../../constants/MixerProtocolInterface'; -import { - SET_FADER_LEVEL, - SET_CHANNEL_LABEL -} from '../../reducers/faderActions' -import { logger } from '../logger'; - - -export class StuderMixerConnection { - mixerProtocol: IMixerProtocol - emberConnection: EmberClient - deviceRoot: any; - emberNodeObject: Array; - - - constructor(mixerProtocol: IMixerProtocol) { - this.sendOutMessage = this.sendOutMessage.bind(this); - this.pingMixerCommand = this.pingMixerCommand.bind(this); - - this.emberNodeObject = new Array(200); - this.mixerProtocol = mixerProtocol; - - logger.info("Setting up Ember connection") - this.emberConnection = new EmberClient( - state.settings[0].deviceIp, - state.settings[0].devicePort - ); - - this.emberConnection.on('error', (error: any) => { - if ( - (error.message + '').match(/econnrefused/i) || - (error.message + '').match(/disconnected/i) - ) { - logger.error('Ember connection not establised') - } else { - logger.error('Ember connection unknown error' + error.message) - } - }) - this.emberConnection.on('disconnected', () => { - logger.error('Lost Ember connection') - }) - logger.info('Connecting to Ember') - let deviceRoot: any; - this.emberConnection.connect() - .then(() => { - this.setupMixerConnection(); - }) - .catch((e: any) => { - console.log(e.stack); - }); - } - - setupMixerConnection() { - logger.info('Ember connection established - setting up subscription of channels') - - let ch: number = 1; - state.settings[0].numberOfChannelsInType.forEach((numberOfChannels, typeIndex) => { - for (let channelTypeIndex=0; channelTypeIndex < numberOfChannels ; channelTypeIndex++) { - this.subscribeFaderLevel(ch, typeIndex, channelTypeIndex); - ch++; - } - }) -/* - .CHANNEL_VU)){ - store.dispatch({ - type:SET_VU_LEVEL, - channel: ch - 1, - level: message.args[0] - }); - */ - - - //Ping OSC mixer if mixerProtocol needs it. - if (this.mixerProtocol.pingTime > 0) { - let emberTimer = setInterval( - () => { - this.pingMixerCommand(); - }, - this.mixerProtocol.pingTime - ); - } - } - - subscribeFaderLevel(ch: number, typeIndex: number, channelTypeIndex: number) { - let command = this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.replace("{channel}", String(channelTypeIndex+1)) - this.emberConnection.getElementByPath(command) - .then((node: any) => { - logger.info('Subscription of channel : ' + command) - this.emberNodeObject[ch-1] = node; - this.emberConnection.subscribe(node, (() => { - logger.verbose('Receiving Level from Ch ' + String(ch)) - if (!state.channels[0].channel[ch-1].fadeActive - && !state.channels[0].channel[ch - 1].fadeActive - && node.contents.value > this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_OUT_GAIN[0].min) { - store.dispatch({ - type: SET_FADER_LEVEL, - channel: ch-1, - level: node.contents.value - }); - global.mainThreadHandler.updatePartialStore(ch-1) - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(ch-1, node.contents.value); - } - } - - }) - ) - }) - .catch((error: any) => { - logger.error(error) - }) - - } - - subscribeChannelName(ch: number, typeIndex: number, channelTypeIndex: number) { - this.emberConnection.getNodeByPath(this.mixerProtocol.channelTypes[typeIndex].fromMixer.CHANNEL_NAME[0].mixerMessage.replace("{channel}", String(channelTypeIndex+1))) - .then((node: any) => { - this.emberConnection.subscribe(node, (() => { - store.dispatch({ - type: SET_CHANNEL_LABEL, - channel: ch-1, - level: node.contents.value - }); - }) - ) - }) - } - - pingMixerCommand() { - //Ping Ember mixer if mixerProtocol needs it. - return; - this.mixerProtocol.pingCommand.map((command) => { - this.sendOutMessage( - command.mixerMessage, - 0, - command.value, - command.type - ); - }); - } - - sendOutMessage(mixerMessage: string, channel: number, value: string | number, type: string) { - let channelString = this.mixerProtocol.leadingZeros ? ("0"+channel).slice(-2) : channel.toString(); - - let message = mixerMessage.replace( - "{channel}", - channelString - ) - -/* - this.emberConnection.getElementByPath(message) - .then((element: any) => { - logger.verbose('Sending out message : ' + message) - this.emberConnection.setValue( - this.emberNodeObject[channel-1], - typeof value === 'number' ? value : parseFloat(value) - ) - }) - .catch((error: any) => { - console.log("Ember Error ", error) - }) - */ - } - - sendOutLevelMessage(channel: number, value: number) { - let levelMessage: string - let channelVal: number - let channelType = state.channels[0].channel[channel - 1].channelType; - let channelTypeIndex = state.channels[0].channel[channel - 1].channelTypeIndex; - - if (channel<25) { - levelMessage = this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage - channelVal = 160 + channelTypeIndex + 1 - } else { - levelMessage = this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[1].mixerMessage - channelVal = channelTypeIndex + 1 - } - - let valueNumber = value - let valueByte = new Uint8Array([ - (valueNumber & 0x0000ff00) >> 8, - (valueNumber & 0x000000ff), - ]) - let channelByte = new Uint8Array([ - (channelVal & 0x000000ff), - ]) - - levelMessage = levelMessage.replace('{channel}', ('0' + channelByte[0].toString(16)).slice(-2)) - levelMessage = levelMessage.replace('{level}', ('0' + valueByte[0].toString(16)).slice(-2) + ' ' + ('0' + valueByte[1].toString(16)).slice(-2)) - - let hexArray = levelMessage.split(' ') - let buf = new Buffer(hexArray.map((val:string) => { return parseInt(val, 16) })) - this.emberConnection._client.socket.write(buf) - logger.verbose("Send HEX: " + levelMessage) - } - - sendOutRequest(mixerMessage: string, channel: number) { - let channelString = this.mixerProtocol.leadingZeros ? ("0"+channel).slice(-2) : channel.toString(); - let message = mixerMessage.replace( - "{channel}", - channelString - ); - if (message != 'none') { -/* - this.oscConnection.send({ - address: message - }); -*/ - } - } - - updateOutLevel(channelIndex: number) { - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let outputlevel = state.channels[0].channel[channelIndex].outputLevel - let level = 20 * Math.log((1.3*outputlevel)/0.775) - if (level < -90) { - level = -90 - } - // console.log('Log level :', level) - - this.sendOutLevelMessage( - channelTypeIndex+1, - level, - ); - } - - updateFadeIOLevel(channelIndex: number, outputLevel: number) { - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let level = 20 * Math.log((1.3*outputLevel)/0.775) - if (level < -90) { - level = -90 - } - // console.log('Log level :', level) - - this.sendOutLevelMessage( - channelTypeIndex+1, - level - ) - } - - updatePflState(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - - if (state.faders[0].fader[channelIndex].pflOn === true) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].mixerMessage, - channelTypeIndex+1, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].type - ); - } else { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].mixerMessage, - channelTypeIndex+1, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].type - ); - } - } - - updateMuteState(channelIndex: number, muteOn: boolean) { - return true - } - - updateNextAux(channelIndex: number, level: number) { - return true - } - - - updateThreshold(channelIndex: number, level: number) { - return true - } - updateRatio(channelIndex: number, level: number) { - return true - - } - updateDelayTime(channelIndex: number, level: number) { - return true - } - updateLow(channelIndex: number, level: number) { - return true - } - updateLoMid(channelIndex: number, level: number) { - return true - } - updateMid(channelIndex: number, level: number) { - return true - } - updateHigh(channelIndex: number, level: number) { - return true - } - updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { - return true - } - - updateChannelName(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let channelName = state.faders[0].fader[channelIndex].label; - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0].mixerMessage, - channelTypeIndex+1, - channelName, - "string" - ); - } - - injectCommand(command: string[]) { - return true - } - -} - +//@ts-ignore +import { EmberClient } from 'node-emberplus' +import { store, state } from '../../reducers/store' +import { remoteConnections } from '../../mainClasses' + +//Utils: +import { IMixerProtocol } from '../../constants/MixerProtocolInterface' +import { SET_FADER_LEVEL, SET_CHANNEL_LABEL } from '../../reducers/faderActions' +import { logger } from '../logger' + +export class StuderMixerConnection { + mixerProtocol: IMixerProtocol + emberConnection: EmberClient + deviceRoot: any + emberNodeObject: Array + + constructor(mixerProtocol: IMixerProtocol) { + this.sendOutMessage = this.sendOutMessage.bind(this) + this.pingMixerCommand = this.pingMixerCommand.bind(this) + + this.emberNodeObject = new Array(200) + this.mixerProtocol = mixerProtocol + + logger.info('Setting up Ember connection') + this.emberConnection = new EmberClient( + state.settings[0].deviceIp, + state.settings[0].devicePort + ) + + this.emberConnection.on('error', (error: any) => { + if ( + (error.message + '').match(/econnrefused/i) || + (error.message + '').match(/disconnected/i) + ) { + logger.error('Ember connection not establised') + } else { + logger.error('Ember connection unknown error' + error.message) + } + }) + this.emberConnection.on('disconnected', () => { + logger.error('Lost Ember connection') + }) + logger.info('Connecting to Ember') + let deviceRoot: any + this.emberConnection + .connect() + .then(() => { + this.setupMixerConnection() + }) + .catch((e: any) => { + console.log(e.stack) + }) + } + + setupMixerConnection() { + logger.info( + 'Ember connection established - setting up subscription of channels' + ) + + let ch: number = 1 + state.settings[0].numberOfChannelsInType.forEach( + (numberOfChannels, typeIndex) => { + for ( + let channelTypeIndex = 0; + channelTypeIndex < numberOfChannels; + channelTypeIndex++ + ) { + this.subscribeFaderLevel(ch, typeIndex, channelTypeIndex) + ch++ + } + } + ) + /* + .CHANNEL_VU)){ + store.dispatch({ + type:SET_VU_LEVEL, + channel: ch - 1, + level: message.args[0] + }); + */ + + //Ping OSC mixer if mixerProtocol needs it. + if (this.mixerProtocol.pingTime > 0) { + let emberTimer = setInterval(() => { + this.pingMixerCommand() + }, this.mixerProtocol.pingTime) + } + } + + subscribeFaderLevel( + ch: number, + typeIndex: number, + channelTypeIndex: number + ) { + let command = this.mixerProtocol.channelTypes[ + typeIndex + ].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.replace( + '{channel}', + String(channelTypeIndex + 1) + ) + this.emberConnection + .getElementByPath(command) + .then((node: any) => { + logger.info('Subscription of channel : ' + command) + this.emberNodeObject[ch - 1] = node + this.emberConnection.subscribe(node, () => { + logger.verbose('Receiving Level from Ch ' + String(ch)) + if ( + !state.channels[0].channel[ch - 1].fadeActive && + !state.channels[0].channel[ch - 1].fadeActive && + node.contents.value > + this.mixerProtocol.channelTypes[typeIndex].fromMixer + .CHANNEL_OUT_GAIN[0].min + ) { + store.dispatch({ + type: SET_FADER_LEVEL, + channel: ch - 1, + level: node.contents.value, + }) + global.mainThreadHandler.updatePartialStore(ch - 1) + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + ch - 1, + node.contents.value + ) + } + } + }) + }) + .catch((error: any) => { + logger.error(error) + }) + } + + subscribeChannelName( + ch: number, + typeIndex: number, + channelTypeIndex: number + ) { + this.emberConnection + .getNodeByPath( + this.mixerProtocol.channelTypes[ + typeIndex + ].fromMixer.CHANNEL_NAME[0].mixerMessage.replace( + '{channel}', + String(channelTypeIndex + 1) + ) + ) + .then((node: any) => { + this.emberConnection.subscribe(node, () => { + store.dispatch({ + type: SET_CHANNEL_LABEL, + channel: ch - 1, + level: node.contents.value, + }) + }) + }) + } + + pingMixerCommand() { + //Ping Ember mixer if mixerProtocol needs it. + return + this.mixerProtocol.pingCommand.map((command) => { + this.sendOutMessage( + command.mixerMessage, + 0, + command.value, + command.type + ) + }) + } + + sendOutMessage( + mixerMessage: string, + channel: number, + value: string | number, + type: string + ) { + let channelString = this.mixerProtocol.leadingZeros + ? ('0' + channel).slice(-2) + : channel.toString() + + let message = mixerMessage.replace('{channel}', channelString) + + /* + this.emberConnection.getElementByPath(message) + .then((element: any) => { + logger.verbose('Sending out message : ' + message) + this.emberConnection.setValue( + this.emberNodeObject[channel-1], + typeof value === 'number' ? value : parseFloat(value) + ) + }) + .catch((error: any) => { + console.log("Ember Error ", error) + }) + */ + } + + sendOutLevelMessage(channel: number, value: number) { + let levelMessage: string + let channelVal: number + let channelType = state.channels[0].channel[channel - 1].channelType + let channelTypeIndex = + state.channels[0].channel[channel - 1].channelTypeIndex + + if (channel < 25) { + levelMessage = this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + channelVal = 160 + channelTypeIndex + 1 + } else { + levelMessage = this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[1].mixerMessage + channelVal = channelTypeIndex + 1 + } + + let valueNumber = value + let valueByte = new Uint8Array([ + (valueNumber & 0x0000ff00) >> 8, + valueNumber & 0x000000ff, + ]) + let channelByte = new Uint8Array([channelVal & 0x000000ff]) + + levelMessage = levelMessage.replace( + '{channel}', + ('0' + channelByte[0].toString(16)).slice(-2) + ) + levelMessage = levelMessage.replace( + '{level}', + ('0' + valueByte[0].toString(16)).slice(-2) + + ' ' + + ('0' + valueByte[1].toString(16)).slice(-2) + ) + + let hexArray = levelMessage.split(' ') + let buf = new Buffer( + hexArray.map((val: string) => { + return parseInt(val, 16) + }) + ) + this.emberConnection._client.socket.write(buf) + logger.verbose('Send HEX: ' + levelMessage) + } + + sendOutRequest(mixerMessage: string, channel: number) { + let channelString = this.mixerProtocol.leadingZeros + ? ('0' + channel).slice(-2) + : channel.toString() + let message = mixerMessage.replace('{channel}', channelString) + if (message != 'none') { + /* + this.oscConnection.send({ + address: message + }); +*/ + } + } + + updateOutLevel(channelIndex: number) { + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let outputlevel = state.channels[0].channel[channelIndex].outputLevel + let level = 20 * Math.log((1.3 * outputlevel) / 0.775) + if (level < -90) { + level = -90 + } + // console.log('Log level :', level) + + this.sendOutLevelMessage(channelTypeIndex + 1, level) + } + + updateFadeIOLevel(channelIndex: number, outputLevel: number) { + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let level = 20 * Math.log((1.3 * outputLevel) / 0.775) + if (level < -90) { + level = -90 + } + // console.log('Log level :', level) + + this.sendOutLevelMessage(channelTypeIndex + 1, level) + } + + updatePflState(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + + if (state.faders[0].fader[channelIndex].pflOn === true) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .mixerMessage, + channelTypeIndex + 1, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .type + ) + } else { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .mixerMessage, + channelTypeIndex + 1, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .type + ) + } + } + + updateMuteState(channelIndex: number, muteOn: boolean) { + return true + } + + updateNextAux(channelIndex: number, level: number) { + return true + } + + updateThreshold(channelIndex: number, level: number) { + return true + } + updateRatio(channelIndex: number, level: number) { + return true + } + updateDelayTime(channelIndex: number, level: number) { + return true + } + updateLow(channelIndex: number, level: number) { + return true + } + updateLoMid(channelIndex: number, level: number) { + return true + } + updateMid(channelIndex: number, level: number) { + return true + } + updateHigh(channelIndex: number, level: number) { + return true + } + updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { + return true + } + + updateChannelName(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let channelName = state.faders[0].fader[channelIndex].label + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0] + .mixerMessage, + channelTypeIndex + 1, + channelName, + 'string' + ) + } + + injectCommand(command: string[]) { + return true + } +} diff --git a/server/utils/mixerConnections/YamahaQlClConnection.ts b/server/utils/mixerConnections/YamahaQlClConnection.ts index 43fd71f7..d4f74043 100644 --- a/server/utils/mixerConnections/YamahaQlClConnection.ts +++ b/server/utils/mixerConnections/YamahaQlClConnection.ts @@ -1,344 +1,436 @@ -//Node Modules: -const net = require('net') -import { store, state } from '../../reducers/store' -import { huiRemoteConnection } from '../../mainClasses' - - -//Utils: -import { IMixerProtocol } from '../../constants/MixerProtocolInterface' -import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' -import { - SET_VU_LEVEL, - SET_FADER_LEVEL, - SET_CHANNEL_LABEL, - TOGGLE_PGM, - SET_MUTE -} from '../../reducers/faderActions' -import { logger } from '../logger' -import { SET_MIXER_ONLINE } from '../../reducers/settingsActions' - - - -export class QlClMixerConnection { - mixerProtocol: IMixerProtocol - cmdChannelIndex: number - midiConnection: any - mixerOnlineTimer: any - - - constructor(mixerProtocol: IMixerProtocol) { - this.sendOutMessage = this.sendOutMessage.bind(this); - this.pingMixerCommand = this.pingMixerCommand.bind(this); - - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: false - }); - - this.mixerProtocol = mixerProtocol; - - this.cmdChannelIndex = this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage.split('/').findIndex(ch => ch === '{channel}'); - - this.midiConnection = new net.Socket() - this.midiConnection.connect(50000, state.settings[0].deviceIp, () => { - logger.info('Connected to Yamaha mixer', {}) - - } - ); - this.setupMixerConnection(); - } - - setupMixerConnection() { - this.midiConnection - .on("ready", () => { - logger.info("Receiving state of desk", {}) - this.mixerProtocol.initializeCommands.map((item) => { - if (item.mixerMessage.includes("{channel}")) { - state.channels[0].channel.map((channel: any, index: any) => { - this.sendOutMessage(item.mixerMessage, (index + 1), 0, '') - }) - } else { - this.sendOutMessage(item.mixerMessage, 0, item.value, item.type) - } - }) - global.mainThreadHandler.updateFullClientStore() - }) - .on('data', (data: any) => { - clearTimeout(this.mixerOnlineTimer) - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: true - }); - - let buffers = [] - let lastIndex = 0 - for (let index=1; index { - logger.verbose("Received Midi Message : " + message.toString('hex')) - if (this.checkMidiCommand(message, this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_VU[0].mixerMessage)) { - let mixerValues: string[] = message.split(' ') - let ch = parseInt(mixerValues[3]) - let assignedFader = 1 + state.channels[0].channel[ch - 1].assignedFader - let mixerValue = parseInt(mixerValues[6]) - store.dispatch({ - type: SET_VU_LEVEL, - channel: assignedFader, - level: mixerValue - } - ) - } else if (this.checkMidiCommand(message, this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_OUT_GAIN[0].mixerMessage)) { - let ch = 1 + (message[11] | message[10] << 8) - let assignedFader = 1 + state.channels[0].channel[ch - 1].assignedFader - let mixerLevel: number = message[16] | message[15] << 8 // parseFloat(message[16]) - let faderLevel = Math.pow(2, (mixerLevel) / 1920) - 1 - //let faderLevel = Math.log10((mixerLevel + 32768) / (1000 + 32768)) - if (!state.channels[0].channel[ch - 1].fadeActive - && faderLevel > this.mixerProtocol.fader.min) { - store.dispatch({ - type: SET_FADER_LEVEL, - channel: assignedFader - 1, - level: faderLevel - }); - if (!state.faders[0].fader[assignedFader - 1].pgmOn) { - store.dispatch({ - type: TOGGLE_PGM, - channel: assignedFader - 1 - }); - } - - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(assignedFader - 1, faderLevel); - } - if (state.faders[0].fader[assignedFader - 1].pgmOn) { - state.channels[0].channel.map((channel: any, index: number) => { - if (channel.assignedFader === assignedFader - 1) { - this.updateOutLevel(index); - } - }) - } - - } - global.mainThreadHandler.updatePartialStore(assignedFader - 1) - - } else if (this.checkMidiCommand(message, this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_MUTE_ON[0].mixerMessage)) { - // MUTE ON/OFF COMMAND - let channelIndex = (message[11] | message[10] << 8) - - let value: boolean = message[16] === 0 ? true : false - logger.verbose('Receive Buffer Channel On/off - Channel ' + String(channelIndex + 1) + ' Val :' + String(message[16]) ) - - let assignedFaderIndex = state.channels[0].channel[channelIndex].assignedFader - - store.dispatch({ - type: SET_MUTE, - channel: assignedFaderIndex, - muteOn: value - }); - - if (huiRemoteConnection) { - huiRemoteConnection.updateRemoteFaderState(assignedFaderIndex, value ? 1 : 0); - } - state.channels[0].channel.forEach((channel: any, index: number) => { - if (channel.assignedFader === assignedFaderIndex && index !== channelIndex) { - this.updateMuteState(index, state.faders[0].fader[assignedFaderIndex].muteOn); - } - }) - global.mainThreadHandler.updatePartialStore(assignedFaderIndex) - } - }) - }) - .on('error', (error: any) => { - logger.error("Error : " + String(error), {}) - logger.info("Lost QlCl connection", {}) - }); - - //Ping OSC mixer if mixerProtocol needs it. - if (this.mixerProtocol.pingTime > 0) { - let oscTimer = setInterval( - () => { - this.pingMixerCommand(); - }, - this.mixerProtocol.pingTime - ); - } - } - - pingMixerCommand() { - this.mixerOnlineTimer = setTimeout(() => { - store.dispatch({ - type: SET_MIXER_ONLINE, - mixerOnline: false - }); - }, this.mixerProtocol.pingTime) - } - - checkMidiCommand(midiMessage: number[], command: string) { - if (!midiMessage) return false - let commandArray = command.split(' ') - let valid = true - for (let i=0; i <= 8; i++) { - if (i < midiMessage.length) { - if (("0" + midiMessage[i].toString(16)).substr(-2) !== commandArray[i]) { - valid = false - } - } else { - valid = false - } - } - return valid - } - - sendOutMessage(message: string, channel: number, value: string | number, type: string) { - let valueNumber: number - if (typeof value === 'string') { - value = parseFloat(value) - } - - valueNumber = value * 2048 - let valueByte = new Uint8Array([ - (valueNumber & 0xff00) >> 8, - (valueNumber & 0x00ff), - ]) - - let channelByte = new Uint8Array([ - (channel & 0xff00) >> 8, - (channel & 0x00ff), - ]) - - let command = message.replace('{channel}', channelByte[0].toString(16) + ' ' + channelByte[1].toString(16)) - command = command.replace('{level}', valueByte[0].toString(16) + ' ' + valueByte[1].toString(16)) - let a = command.split(' ') - let buf = new Buffer(a.map((val:string) => { return parseInt(val, 16) })) - logger.verbose("Sending Command :" + command) - this.midiConnection.write(buf) - } - - updateOutLevel(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let faderIndex = state.channels[0].channel[channelIndex].assignedFader; - if (state.faders[0].fader[faderIndex].pgmOn) { - store.dispatch({ - type:SET_OUTPUT_LEVEL, - channel: channelIndex, - level: state.faders[0].fader[faderIndex].faderLevel - }); - } - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelTypeIndex, - state.channels[0].channel[channelIndex].outputLevel, - "f" - ); - } - - updatePflState(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - if (state.faders[0].fader[channelIndex].pflOn === true) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].mixerMessage, - channelTypeIndex, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0].type - ); - } else { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].mixerMessage, - channelTypeIndex, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].value, - this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0].type - ); - } - } - - updateMuteState(channelIndex: number, muteOn: boolean) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - if (muteOn === true) { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_MUTE_ON[0].mixerMessage, - channelTypeIndex, - '', - '' - ); - } else { - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_MUTE_OFF[0].mixerMessage, - channelTypeIndex, - '', - '' - ); - } - } - - updateNextAux(channelIndex: number, level: number) { - return true - } - updateThreshold(channelIndex: number, level: number) { - return true - } - updateRatio(channelIndex: number, level: number) { - return true - - } - updateDelayTime(channelIndex: number, level: number) { - return true - } - updateLow(channelIndex: number, level: number) { - return true - } - updateLoMid(channelIndex: number, level: number) { - return true - } - updateMid(channelIndex: number, level: number) { - return true - } - updateHigh(channelIndex: number, level: number) { - return true - } - updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { - return true - } - - updateFadeIOLevel(channelIndex: number, outputLevel: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_OUT_GAIN[0].mixerMessage, - channelTypeIndex, - String(outputLevel), - "f" - ); - } - - updateChannelName(channelIndex: number) { - let channelType = state.channels[0].channel[channelIndex].channelType; - let channelTypeIndex = state.channels[0].channel[channelIndex].channelTypeIndex; - let channelName = state.faders[0].fader[channelIndex].label; - this.sendOutMessage( - this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0].mixerMessage, - channelTypeIndex, - channelName, - "s" - ); - } - - injectCommand(command: string[]) { - return true - } - -} - +//Node Modules: +const net = require('net') +import { store, state } from '../../reducers/store' +import { remoteConnections } from '../../mainClasses' + +//Utils: +import { IMixerProtocol } from '../../constants/MixerProtocolInterface' +import { SET_OUTPUT_LEVEL } from '../../reducers/channelActions' +import { + SET_VU_LEVEL, + SET_FADER_LEVEL, + SET_CHANNEL_LABEL, + TOGGLE_PGM, + SET_MUTE, +} from '../../reducers/faderActions' +import { logger } from '../logger' +import { SET_MIXER_ONLINE } from '../../reducers/settingsActions' + +export class QlClMixerConnection { + mixerProtocol: IMixerProtocol + cmdChannelIndex: number + midiConnection: any + mixerOnlineTimer: any + + constructor(mixerProtocol: IMixerProtocol) { + this.sendOutMessage = this.sendOutMessage.bind(this) + this.pingMixerCommand = this.pingMixerCommand.bind(this) + + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: false, + }) + + this.mixerProtocol = mixerProtocol + + this.cmdChannelIndex = this.mixerProtocol.channelTypes[0].fromMixer.CHANNEL_OUT_GAIN[0].mixerMessage + .split('/') + .findIndex((ch) => ch === '{channel}') + + this.midiConnection = new net.Socket() + this.midiConnection.connect(50000, state.settings[0].deviceIp, () => { + logger.info('Connected to Yamaha mixer', {}) + }) + this.setupMixerConnection() + } + + setupMixerConnection() { + this.midiConnection + .on('ready', () => { + logger.info('Receiving state of desk', {}) + this.mixerProtocol.initializeCommands.map((item) => { + if (item.mixerMessage.includes('{channel}')) { + state.channels[0].channel.map( + (channel: any, index: any) => { + this.sendOutMessage( + item.mixerMessage, + index + 1, + 0, + '' + ) + } + ) + } else { + this.sendOutMessage( + item.mixerMessage, + 0, + item.value, + item.type + ) + } + }) + global.mainThreadHandler.updateFullClientStore() + }) + .on('data', (data: any) => { + clearTimeout(this.mixerOnlineTimer) + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: true, + }) + + let buffers = [] + let lastIndex = 0 + for (let index = 1; index < data.length; index++) { + if (data[index] === 240) { + buffers.push(data.slice(lastIndex, index)) + lastIndex = index + } + } + if (buffers.length === 0) { + buffers.push(data) + } + + buffers.forEach((message) => { + logger.verbose( + 'Received Midi Message : ' + message.toString('hex') + ) + if ( + this.checkMidiCommand( + message, + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_VU[0].mixerMessage + ) + ) { + let mixerValues: string[] = message.split(' ') + let ch = parseInt(mixerValues[3]) + let assignedFader = + 1 + state.channels[0].channel[ch - 1].assignedFader + let mixerValue = parseInt(mixerValues[6]) + store.dispatch({ + type: SET_VU_LEVEL, + channel: assignedFader, + level: mixerValue, + }) + } else if ( + this.checkMidiCommand( + message, + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) + ) { + let ch = 1 + (message[11] | (message[10] << 8)) + let assignedFader = + 1 + state.channels[0].channel[ch - 1].assignedFader + let mixerLevel: number = + message[16] | (message[15] << 8) // parseFloat(message[16]) + let faderLevel = Math.pow(2, mixerLevel / 1920) - 1 + //let faderLevel = Math.log10((mixerLevel + 32768) / (1000 + 32768)) + if ( + !state.channels[0].channel[ch - 1].fadeActive && + faderLevel > this.mixerProtocol.fader.min + ) { + store.dispatch({ + type: SET_FADER_LEVEL, + channel: assignedFader - 1, + level: faderLevel, + }) + if ( + !state.faders[0].fader[assignedFader - 1].pgmOn + ) { + store.dispatch({ + type: TOGGLE_PGM, + channel: assignedFader - 1, + }) + } + + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + assignedFader - 1, + faderLevel + ) + } + if ( + state.faders[0].fader[assignedFader - 1].pgmOn + ) { + state.channels[0].channel.map( + (channel: any, index: number) => { + if ( + channel.assignedFader === + assignedFader - 1 + ) { + this.updateOutLevel(index) + } + } + ) + } + } + global.mainThreadHandler.updatePartialStore( + assignedFader - 1 + ) + } else if ( + this.checkMidiCommand( + message, + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_MUTE_ON[0].mixerMessage + ) + ) { + // MUTE ON/OFF COMMAND + let channelIndex = message[11] | (message[10] << 8) + + let value: boolean = message[16] === 0 ? true : false + logger.verbose( + 'Receive Buffer Channel On/off - Channel ' + + String(channelIndex + 1) + + ' Val :' + + String(message[16]) + ) + + let assignedFaderIndex = + state.channels[0].channel[channelIndex] + .assignedFader + + store.dispatch({ + type: SET_MUTE, + channel: assignedFaderIndex, + muteOn: value, + }) + + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + assignedFaderIndex, + value ? 1 : 0 + ) + } + state.channels[0].channel.forEach( + (channel: any, index: number) => { + if ( + channel.assignedFader === + assignedFaderIndex && + index !== channelIndex + ) { + this.updateMuteState( + index, + state.faders[0].fader[ + assignedFaderIndex + ].muteOn + ) + } + } + ) + global.mainThreadHandler.updatePartialStore( + assignedFaderIndex + ) + } + }) + }) + .on('error', (error: any) => { + logger.error('Error : ' + String(error), {}) + logger.info('Lost QlCl connection', {}) + }) + + //Ping OSC mixer if mixerProtocol needs it. + if (this.mixerProtocol.pingTime > 0) { + let oscTimer = setInterval(() => { + this.pingMixerCommand() + }, this.mixerProtocol.pingTime) + } + } + + pingMixerCommand() { + this.mixerOnlineTimer = setTimeout(() => { + store.dispatch({ + type: SET_MIXER_ONLINE, + mixerOnline: false, + }) + }, this.mixerProtocol.pingTime) + } + + checkMidiCommand(midiMessage: number[], command: string) { + if (!midiMessage) return false + let commandArray = command.split(' ') + let valid = true + for (let i = 0; i <= 8; i++) { + if (i < midiMessage.length) { + if ( + ('0' + midiMessage[i].toString(16)).substr(-2) !== + commandArray[i] + ) { + valid = false + } + } else { + valid = false + } + } + return valid + } + + sendOutMessage( + message: string, + channel: number, + value: string | number, + type: string + ) { + let valueNumber: number + if (typeof value === 'string') { + value = parseFloat(value) + } + + valueNumber = value * 2048 + let valueByte = new Uint8Array([ + (valueNumber & 0xff00) >> 8, + valueNumber & 0x00ff, + ]) + + let channelByte = new Uint8Array([ + (channel & 0xff00) >> 8, + channel & 0x00ff, + ]) + + let command = message.replace( + '{channel}', + channelByte[0].toString(16) + ' ' + channelByte[1].toString(16) + ) + command = command.replace( + '{level}', + valueByte[0].toString(16) + ' ' + valueByte[1].toString(16) + ) + let a = command.split(' ') + let buf = new Buffer( + a.map((val: string) => { + return parseInt(val, 16) + }) + ) + logger.verbose('Sending Command :' + command) + this.midiConnection.write(buf) + } + + updateOutLevel(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let faderIndex = state.channels[0].channel[channelIndex].assignedFader + if (state.faders[0].fader[faderIndex].pgmOn) { + store.dispatch({ + type: SET_OUTPUT_LEVEL, + channel: channelIndex, + level: state.faders[0].fader[faderIndex].faderLevel, + }) + } + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0].mixerMessage, + channelTypeIndex, + state.channels[0].channel[channelIndex].outputLevel, + 'f' + ) + } + + updatePflState(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + if (state.faders[0].fader[channelIndex].pflOn === true) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .mixerMessage, + channelTypeIndex, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] + .type + ) + } else { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .mixerMessage, + channelTypeIndex, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .value, + this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] + .type + ) + } + } + + updateMuteState(channelIndex: number, muteOn: boolean) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + if (muteOn === true) { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_MUTE_ON[0].mixerMessage, + channelTypeIndex, + '', + '' + ) + } else { + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_MUTE_OFF[0].mixerMessage, + channelTypeIndex, + '', + '' + ) + } + } + + updateNextAux(channelIndex: number, level: number) { + return true + } + updateThreshold(channelIndex: number, level: number) { + return true + } + updateRatio(channelIndex: number, level: number) { + return true + } + updateDelayTime(channelIndex: number, level: number) { + return true + } + updateLow(channelIndex: number, level: number) { + return true + } + updateLoMid(channelIndex: number, level: number) { + return true + } + updateMid(channelIndex: number, level: number) { + return true + } + updateHigh(channelIndex: number, level: number) { + return true + } + updateAuxLevel(channelIndex: number, auxSendIndex: number, level: number) { + return true + } + + updateFadeIOLevel(channelIndex: number, outputLevel: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer + .CHANNEL_OUT_GAIN[0].mixerMessage, + channelTypeIndex, + String(outputLevel), + 'f' + ) + } + + updateChannelName(channelIndex: number) { + let channelType = state.channels[0].channel[channelIndex].channelType + let channelTypeIndex = + state.channels[0].channel[channelIndex].channelTypeIndex + let channelName = state.faders[0].fader[channelIndex].label + this.sendOutMessage( + this.mixerProtocol.channelTypes[channelType].toMixer.CHANNEL_NAME[0] + .mixerMessage, + channelTypeIndex, + channelName, + 's' + ) + } + + injectCommand(command: string[]) { + return true + } +}