diff --git a/client/assets/css/ChanStripFull.css b/client/assets/css/ChanStripFull.css new file mode 100644 index 00000000..3956a272 --- /dev/null +++ b/client/assets/css/ChanStripFull.css @@ -0,0 +1,257 @@ +.chan-strip-full-body { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 1200px; + overflow: auto; + max-height: 90vh; + background-color: rgb(31, 31, 31); + border-color: rgb(124, 124, 124); + border-style: solid; + border-width: 4px; + text-align: left; + z-index: 2; + + color: #fff; +} + +.chan-strip-full-body > .header { + margin-left: 40px; + margin-top: 10px; + margin-right: 80px; + /* width: 420px; */ + font-size: 240%; + color: #fff; + white-space: nowrap; +} + +.chan-strip-full-body > .parameters { + top: 5px; + left: 2px; + height: 900px; + overflow: auto; + text-align: center; + color: #fff; +} + +.chan-strip-full-body .parameters .horizontal { + display: flex; + justify-content: space-evenly; +} +.chan-strip-full-body .parameters .horizontal .item { +} +.chan-strip-full-body .parameters .horizontal .item .content { + display: flex; +} + +.parameters > .inp-comp-del-group { + display: flex; + top: 5px; + left: 2px; + margin-left: 5px; + overflow: auto; + text-align: center; + color: #fff; +} + +.inp-comp-del-group > .horizontal-space { + width: 40px; + height: 50px; +} + +.parameters > .eq-group, +.content > .eq-group { + display: flex; + top: 5px; + left: 2px; + margin-left: 90px; + overflow: auto; + text-align: center; + font-size: 14px; + color: #fff; +} +.content > .eq-group { + margin-left: 0; +} + +.eq-group > .horizontal-space { + width: 150px; + height: 50px; +} + +.eq > .group-text { + text-align: center; + line-height: 20px; + font-size: 110%; +} + +.zero-eq { + width: 63px; + height: 2px; + margin-left: -68px; + margin-right: 30px; + margin-top: 111px; +} + +.zero-comp { + width: 63px; + height: 2px; + margin-left: -68px; + margin-right: 30px; + margin-top: 81px; +} + +.zero-monitor { + width: 2px; + height: 20px; + margin-left: 10px; + margin-top: -150px; +} + +.parameters > .parameter-text, +.content > .parameter-text { + list-style-type: none; + text-align: center; + margin-top: 15px; + line-height: 10px; + font-size: 14px; +} + +.parameter-text > .parameter-mini-text, +.content > .parameter-mini-text { + list-style-type: none; + text-align: center; + margin-top: 5px; + line-height: 10px; + font-size: 80%; +} + +.inp-comp-del-group > .delayButtons { + width: 30px; + margin-top: 24px; + margin-left: 50px; +} +.content > .delayButtons { + width: 30px; + margin-top: 24px; + margin-left: 50px; +} + +.delayButtons > .delayTime { + outline: none; + -moz-outline: none; + color: white; + height: 45px; + width: 70px; + border-color: rgb(71, 71, 71); + background-color: rgb(53, 53, 53); + margin-left: -50px; + margin-top: 5px; + border-radius: 7px; +} + +.inp-comp-del-group > .input-buttons { + width: 30px; + margin-top: 24px; + margin-left: 50px; +} +.inp-comp-del-group .input-buttons.disabled { + visibility: hidden; +} +.content > .input-buttons { + width: 30px; + margin-top: 24px; + margin-left: 50px; +} +.content > .input-buttons.disabled { + visibility: hidden; +} + +.input-buttons > .input-select { + outline: none; + -moz-outline: none; + color: white; + height: 62px; + width: 70px; + border-color: rgb(71, 71, 71); + background-color: rgb(53, 53, 53); + margin-left: -50px; + margin-top: 5px; + border-radius: 7px; +} +.input-buttons > .input-select.active { + background-color: #2f475b; +} + +.parameters > .monitor-sends, +.content > .monitor-sends { + list-style-type: none; + display: flex; + text-align: center; + margin-top: 15px; + margin-left: 1px; + padding: 0px; + line-height: 10px; + font-size: 95%; +} + +.header > .close { + position: absolute; + outline: none; + border-color: rgb(99, 99, 99); + background-color: rgb(27, 27, 27); + border-radius: 20px; + color: #fff; + width: 50px; + height: 50px; + font-size: 30px; + /* margin-top: 5px; */ + right: 10px; +} + +.header > .button { + outline: none; + border-color: rgb(99, 99, 99); + background-color: rgb(27, 27, 27); + border-radius: 7px; + margin-left: 10px; + width: 80px; + height: 50px; + font-size: 12px; + line-height: 30px; + color: #fff; +} + +.chan-strip-fader { + width: 10px; + height: 190px; + margin-left: 35px; + margin-right: 30px; + margin-top: 10px; + border-width: 0px; + border-style: solid; + border-radius: 8px; + background-color: rgb(17, 17, 17); +} + +.chan-strip-thumb { + margin-left: -20px; + color: #3a3a3a; + font-size: 90%; + line-height: 50px; + width: 45px; + height: 49px; + border: 1px solid #c5c2c2; + border-radius: 8px; + background: linear-gradient( + to top, + #3a3a3a 0%, + #c2c2c2 20%, + hsl(0, 0%, 57%) 50%, + #00a 1px, + #919191 52%, + #c2c2c2 80%, + #3a3a3a 100% + ); +} diff --git a/client/components/ChanStrip.tsx b/client/components/ChanStrip.tsx index 12e203c9..2e901085 100644 --- a/client/components/ChanStrip.tsx +++ b/client/components/ChanStrip.tsx @@ -620,31 +620,11 @@ class ChanStrip extends React.PureComponent< > X - {window.location.search.includes( - 'settings=0' - ) ? null : ( - - )} - {window.location.search.includes( - 'settings=0' - ) ? null : ( - - )}
diff --git a/client/components/ChanStripFull.tsx b/client/components/ChanStripFull.tsx new file mode 100644 index 00000000..99d16103 --- /dev/null +++ b/client/components/ChanStripFull.tsx @@ -0,0 +1,718 @@ +import React from 'react' +import ReactSlider from 'react-slider' + +import '../assets/css/ChanStripFull.css' +import { Store } from 'redux' +import { connect } from 'react-redux' +import { + storeShowOptions, + storeShowMonitorOptions, + storeShowChanStripFull, +} from '../../server/reducers/settingsActions' +import { IFader } from '../../server/reducers/fadersReducer' +import { + SOCKET_SET_THRESHOLD, + SOCKET_SET_RATIO, + SOCKET_SET_DELAY_TIME, + SOCKET_SET_FX, + SOCKET_SET_AUX_LEVEL, + SOCKET_SET_INPUT_GAIN, + SOCKET_SET_INPUT_SELECTOR, +} from '../../server/constants/SOCKET_IO_DISPATCHERS' +import CcgChannelInputSettings from './CcgChannelSettings' +import ReductionMeter from './ReductionMeter' +import ClassNames from 'classnames' +import { fxParamsList } from '../../server/constants/MixerProtocolInterface' + +interface IChanStripFullInjectProps { + label: string + selectedProtocol: string + numberOfChannelsInType: Array + channel: Array + fader: Array + auxSendIndex: number + offtubeMode: boolean +} + +interface IChanStripFullProps { + faderIndex: number +} + +class ChanStripFull extends React.PureComponent< + IChanStripFullProps & IChanStripFullInjectProps & Store +> { + constructor(props: any) { + super(props) + } + + shouldComponentUpdate( + nextProps: IChanStripFullInjectProps & IChanStripFullProps + ) { + if (nextProps.faderIndex > -1) { + return true + } else { + return false + } + } + + handleShowRoutingOptions() { + this.props.dispatch(storeShowOptions(this.props.faderIndex)) + this.props.dispatch(storeShowChanStripFull(-1)) + } + + handleShowMonitorOptions() { + this.props.dispatch(storeShowMonitorOptions(this.props.faderIndex)) + this.props.dispatch(storeShowChanStripFull(-1)) + } + + handleClose = () => { + this.props.dispatch(storeShowChanStripFull(-1)) + } + handleInputSelect(selected: number) { + window.socketIoClient.emit(SOCKET_SET_INPUT_SELECTOR, { + faderIndex: this.props.faderIndex, + selected: selected, + }) + } + handleInputGain(event: any) { + window.socketIoClient.emit(SOCKET_SET_INPUT_GAIN, { + faderIndex: this.props.faderIndex, + level: parseFloat(event), + }) + } + handleThreshold(event: any) { + window.socketIoClient.emit(SOCKET_SET_THRESHOLD, { + channel: this.props.faderIndex, + level: parseFloat(event), + }) + } + handleRatio(event: any) { + window.socketIoClient.emit(SOCKET_SET_RATIO, { + channel: this.props.faderIndex, + level: parseFloat(event), + }) + } + + handleDelay(event: any) { + window.socketIoClient.emit(SOCKET_SET_DELAY_TIME, { + channel: this.props.faderIndex, + delayTime: parseFloat(event), + }) + } + + changeDelay(currentValue: number, addValue: number) { + window.socketIoClient.emit(SOCKET_SET_DELAY_TIME, { + channel: this.props.faderIndex, + delayTime: currentValue + addValue, + }) + } + + handleFx(fxParam: fxParamsList, event: any) { + window.socketIoClient.emit(SOCKET_SET_FX, { + fxParam: fxParam, + channel: this.props.faderIndex, + level: parseFloat(event), + }) + } + + handleMonitorLevel(event: any, channelIndex: number) { + window.socketIoClient.emit(SOCKET_SET_AUX_LEVEL, { + channel: channelIndex, + auxIndex: this.props.auxSendIndex, + level: parseFloat(event), + }) + } + + inputSelectorButton(index: number) { + const isActive = + this.props.fader[this.props.faderIndex].inputSelector === index + 1 + return ( + + ) + } + + inputSelector() { + return ( +
+ {window.mixerProtocol.channelTypes[0].toMixer + .CHANNEL_INPUT_SELECTOR ? ( + + {window.mixerProtocol.channelTypes[0].toMixer.CHANNEL_INPUT_SELECTOR.map( + (none: any, index: number) => { + return this.inputSelectorButton(index) + } + )} + + ) : null} +
+ ) + } + + inputGain() { + let maxLabel: number = + window.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_INPUT_GAIN?.[0].maxLabel ?? 1 + let minLabel = + window.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_INPUT_GAIN?.[0].minLabel ?? 0 + return ( +
+ Gain +
{maxLabel + ' dB'}
+ {window.mixerProtocol.channelTypes[0].toMixer + .CHANNEL_INPUT_GAIN ? ( + + { + this.handleInputGain(event) + }} + /> + + ) : null} +
{minLabel + ' dB'}
+
+ ) + } + + threshold() { + let maxLabel: number = + window.mixerProtocol.channelTypes[0].fromMixer.THRESHOLD?.[0] + .maxLabel ?? 1 + let minLabel = + window.mixerProtocol.channelTypes[0].fromMixer.THRESHOLD?.[0] + .minLabel ?? 0 + return ( +
+ Threshold +
{maxLabel + ' dB'}
+ ( +
+ {Math.round( + (maxLabel - minLabel) * + parseFloat(state.valueNow) + + minLabel + )} + dB +
+ )} + onChange={(event: any) => { + this.handleThreshold(event) + }} + /> +
{minLabel + ' dB'}
+
+ ) + } + + ratio() { + let maxLabel: number = + window.mixerProtocol.channelTypes[0].fromMixer.RATIO?.[0] + .maxLabel ?? 1 + let minLabel = + window.mixerProtocol.channelTypes[0].fromMixer.RATIO?.[0] + .minLabel ?? 0 + return ( +
+ Ratio +
{maxLabel + ':1'}
+ ( +
+ {Math.round( + (maxLabel - minLabel) * + parseFloat(state.valueNow) + + minLabel + ) + ':1'} +
+ )} + onChange={(event: any) => { + this.handleRatio(event) + }} + /> +
{minLabel + ':1'}
+
+ ) + } + + gainReduction() { + return ( +
+ Redution + +
+ ) + } + delay() { + let maxLabel: number = + window.mixerProtocol.channelTypes[0].fromMixer.DELAY_TIME?.[0] + .maxLabel ?? 1 + let minLabel = + window.mixerProtocol.channelTypes[0].fromMixer.DELAY_TIME?.[0] + .minLabel ?? 0 + return ( + +
+ Time +
+ {maxLabel + ' ms'} +
+ ( +
+ {Math.round( + (maxLabel - minLabel) * + parseFloat(state.valueNow) + + minLabel + )} + ms +
+ )} + onChange={(event: any) => { + this.handleDelay(event) + }} + /> +
+ {minLabel + ' ms'} +
+
+
+ + + + +
+
+ ) + } + + eqGain(fxParam: fxParamsList) { + let maxLabel: number = + window.mixerProtocol.channelTypes[0].fromMixer.FX_PARAMS?.[fxParam] + .params[0].maxLabel ?? 1 + let minLabel = + window.mixerProtocol.channelTypes[0].fromMixer.FX_PARAMS?.[fxParam] + .params[0].minLabel ?? 0 + return ( +
+ {window.mixerProtocol.channelTypes[0].fromMixer.FX_PARAMS?.[ + fxParam + ].params[0].label ?? 'ERR'} +
{maxLabel + ' dB'}
+ ( +
+ {Math.round( + (maxLabel - minLabel) * + parseFloat(state.valueNow) + + minLabel + )} + dB +
+ )} + onChange={(event: any) => { + this.handleFx(fxParam, event) + }} + /> +
{minLabel + ' dB'}
+
+ ) + } + + monitor(channelIndex: number) { + let faderIndex = this.props.channel[channelIndex].assignedFader + if (faderIndex === -1) return null + let monitorName = this.props.fader[faderIndex] + ? this.props.fader[faderIndex].label + : '' + if (monitorName === '') { + monitorName = + 'Fader ' + + String(this.props.channel[channelIndex].assignedFader + 1) + } + return ( +
  • + {monitorName} + { + this.handleMonitorLevel(event, channelIndex) + }} + /> +

    _______

    +
  • + ) + } + parameters() { + if (this.props.offtubeMode) { + const hasInput = + window.mixerProtocol.channelTypes[0].toMixer + .CHANNEL_INPUT_GAIN || + window.mixerProtocol.channelTypes[0].toMixer + .CHANNEL_INPUT_SELECTOR + const hasComp = + window.mixerProtocol.channelTypes[0].toMixer.THRESHOLD || + window.mixerProtocol.channelTypes[0].toMixer.DELAY_TIME + const hasDelay = + window.mixerProtocol.channelTypes[0].toMixer.DELAY_TIME + const hasEq = + window.mixerProtocol.channelTypes[0].toMixer.FX_PARAMS?.[ + fxParamsList.EqLowGain + ] || + window.mixerProtocol.channelTypes[0].toMixer.FX_PARAMS?.[ + fxParamsList.EqLowMidGain + ] || + window.mixerProtocol.channelTypes[0].toMixer.FX_PARAMS?.[ + fxParamsList.EqMidGain + ] || + window.mixerProtocol.channelTypes[0].toMixer.FX_PARAMS?.[ + fxParamsList.EqHighGain + ] + const hasMonitorSends = this.props.channel.find( + (ch: any) => ch.auxLevel[this.props.auxSendIndex] >= 0 + ) + return ( +
    +
    + {hasInput && ( + +
    +
    INPUT
    +
    + {this.inputSelector()} + {this.inputGain()} +
    +
    +
    + )} + {hasComp && ( + +
    +
    COMPRESSOR
    +
    + {this.threshold()} +

    ______

    + {this.ratio()} +

    ______

    + {this.gainReduction()} +
    +
    +
    + )} + {hasDelay && ( + +
    +
    DELAY
    +
    + {this.delay()} +
    +
    +
    + )} +
    + + {hasEq && ( + +
    +
    +
    +
    EQUALIZER
    +
    +
    + {window.mixerProtocol + .channelTypes[0].toMixer + .FX_PARAMS?.[ + fxParamsList.EqLowGain + ] ? ( + + {this.eqGain( + fxParamsList.EqLowGain + )} +

    + _______ +

    +
    + ) : null} + {window.mixerProtocol + .channelTypes[0].toMixer + .FX_PARAMS?.[ + fxParamsList.EqLowMidGain + ] ? ( + + {this.eqGain( + fxParamsList.EqLowMidGain + )} +

    + _______ +

    +
    + ) : null} + {window.mixerProtocol + .channelTypes[0].toMixer + .FX_PARAMS?.[ + fxParamsList.EqMidGain + ] ? ( + + {this.eqGain( + fxParamsList.EqMidGain + )} +

    + _______ +

    +
    + ) : null} + {window.mixerProtocol + .channelTypes[0].toMixer + .FX_PARAMS?.[ + fxParamsList.EqHighGain + ] ? ( + + {this.eqGain( + fxParamsList.EqHighGain + )} +

    + _______ +

    +
    + ) : null} +
    +
    +
    +
    +
    + )} + + {hasMonitorSends && ( + +
    +
    + {this.props.label || + 'FADER ' + (this.props.faderIndex + 1)} + {' - MONITOR MIX MINUS'} +
    +
      + {this.props.channel.map( + (ch: any, index: number) => { + if ( + ch.auxLevel[ + this.props.auxSendIndex + ] >= 0 + ) { + return this.monitor(index) + } + } + )} +
    +
    + )} +
    + ) + } else { + return null + } + } + + render() { + if (this.props.faderIndex >= 0) { + return ( +
    +
    + {this.props.label || + 'FADER ' + (this.props.faderIndex + 1)} + + {window.location.search.includes( + 'settings=0' + ) ? null : ( + + )} + {window.location.search.includes( + 'settings=0' + ) ? null : ( + + )} +
    +
    + {this.props.selectedProtocol.includes('caspar') ? ( + + ) : ( + this.parameters() + )} +
    + ) + } else { + return
    + } + } +} + +const mapStateToProps = (state: any, props: any): IChanStripFullInjectProps => { + let inject: IChanStripFullInjectProps = { + label: '', + selectedProtocol: state.settings[0].mixers[0].mixerProtocol, + numberOfChannelsInType: + state.settings[0].mixers[0].numberOfChannelsInType, + channel: state.channels[0].chConnection[0].channel, + fader: state.faders[0].fader, + auxSendIndex: -1, + offtubeMode: state.settings[0].offtubeMode, + } + if (props.faderIndex >= 0) { + inject = { + label: state.faders[0].fader[props.faderIndex].label, + selectedProtocol: state.settings[0].mixers[0].mixerProtocol, + numberOfChannelsInType: + state.settings[0].mixers[0].numberOfChannelsInType, + channel: state.channels[0].chConnection[0].channel, + fader: state.faders[0].fader, + auxSendIndex: state.faders[0].fader[props.faderIndex].monitor - 1, + offtubeMode: state.settings[0].offtubeMode, + } + } + return inject +} + +export default connect(mapStateToProps)( + ChanStripFull +) as any