diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 55e7abd3..512d66bf 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -4,7 +4,7 @@ runs: using: "composite" steps: - name: Cache dependencies - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.node-version }} cache: ${{ env.node-package-manager }} \ No newline at end of file diff --git a/.github/workflows/node-ci.dev.yml b/.github/workflows/node-ci.dev.yml index 7a34f1ed..d2526a80 100644 --- a/.github/workflows/node-ci.dev.yml +++ b/.github/workflows/node-ci.dev.yml @@ -1,7 +1,7 @@ name: Dev Node CI env: - node-version: 16 + node-version: 18 node-package-manager: yarn # on: @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./.github/actions/cache - name: Install dependencies run: yarn install --frozen-lockfile @@ -41,7 +41,7 @@ jobs: - validate-dependencies steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./.github/actions/cache - name: Install dependencies @@ -51,13 +51,13 @@ jobs: run: yarn build - name: Upload client build artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}-client-develop path: client/dist - name: Upload server build artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}-server-develop path: server/dist @@ -69,7 +69,7 @@ jobs: defined: ${{ steps.username.outputs.defined == 'true' && steps.password.outputs.defined == 'true' }} steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check if has username id: username @@ -90,34 +90,34 @@ jobs: - check-docker-credentials steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}-client-develop path: client/dist - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}-server-develop path: server/dist - name: Docker meta id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: 'tv2media/${{ github.event.repository.name }}' tags: | type=ref,event=branch - name: Log in to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . push: true diff --git a/.github/workflows/node-ci.prod.yml b/.github/workflows/node-ci.prod.yml index 31642791..a5bb7faa 100644 --- a/.github/workflows/node-ci.prod.yml +++ b/.github/workflows/node-ci.prod.yml @@ -20,7 +20,7 @@ name: Prod Node CI env: - node-version: 16 + node-version: 18 node-package-manager: yarn # on: @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./.github/actions/cache - name: Install dependencies run: yarn install --frozen-lockfile @@ -44,7 +44,7 @@ jobs: needs: cache-dependencies steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./.github/actions/cache - name: Install dependencies run: yarn install --frozen-lockfile @@ -56,7 +56,7 @@ jobs: needs: cache-dependencies steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: ./.github/actions/test @@ -81,20 +81,20 @@ jobs: commit_sha: ${{ steps.commit_sha.outputs.commit_sha }} steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure committer run: | git config user.name "${{ github.event.pusher.name }}" git config user.email "${{ github.event.pusher.email }}" - name: Bump version and push tag id: tag_version - uses: mathieudutour/github-tag-action@v5.6 + uses: mathieudutour/github-tag-action@v6.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} default_bump: false - name: Update package.json if: steps.tag_version.outputs.new_tag != '' - uses: jossef/action-set-json-field@v1 + uses: jossef/action-set-json-field@v2.1 with: file: package.json field: version @@ -110,7 +110,7 @@ jobs: - name: Commit and push changes to package.json and CHANGELOG.md id: commit_sha if: steps.tag_version.outputs.new_tag != '' - uses: EndBug/add-and-commit@v7 + uses: EndBug/add-and-commit@v9 with: add: "['package.json', 'CHANGELOG.md']" @@ -121,7 +121,7 @@ jobs: - bump-version steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Pull request to develop id: develop continue-on-error: true @@ -142,7 +142,7 @@ jobs: - bump-version steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: ${{ needs.bump-version.outputs.commit_sha }} - name: Ensure commits from bump-version @@ -153,12 +153,12 @@ jobs: - name: Build run: yarn build - name: Upload client build artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}-client path: client/dist - name: Upload server build artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}-server path: server/dist @@ -170,17 +170,17 @@ jobs: - build steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: ${{ needs.bump-version.outputs.commit_sha }} - name: Ensure commits from bump-version run: git pull - uses: ./.github/actions/cache - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}-client path: client/dist - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}-server path: server/dist @@ -189,7 +189,7 @@ jobs: - name: Build desktop run: yarn build:desktop - name: Upload desktop build artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ github.event.repository.name }}-desktop path: desktop/dist @@ -201,7 +201,7 @@ jobs: defined: ${{ steps.release.outputs.defined == 'true' }} steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check if is set to release id: release uses: ./.github/actions/check-secret @@ -216,12 +216,12 @@ jobs: - check-github-release steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: ${{ needs.bump-version.outputs.commit_sha }} - name: Ensure commits from bump-version run: git pull - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }}-desktop path: desktop/dist @@ -247,7 +247,7 @@ jobs: defined: ${{ steps.token.outputs.defined == 'true' }} steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check if has username id: token uses: ./.github/actions/check-secret @@ -262,19 +262,19 @@ jobs: - check-npm-token steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure publisher run: | git config user.name "${{ github.event.pusher.name }}" git config user.email "${{ github.event.pusher.email }}" - name: Download artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: ${{ github.event.repository.name }} path: dist - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: '16.x' + node-version: '18.x' registry-url: 'https://registry.npmjs.org' - name: Publish package run: yarn publish --access=public --tag latest --new-version "${{ needs.bump-version.outputs.version }}" @@ -288,7 +288,7 @@ jobs: defined: ${{ steps.username.outputs.defined == 'true' && steps.password.outputs.defined == 'true' }} steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check if has username id: username uses: ./.github/actions/check-secret @@ -308,7 +308,7 @@ jobs: - check-docker-credentials steps: - name: Access repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Extract version for tags id: version @@ -317,13 +317,13 @@ jobs: version: ${{ needs.bump-version.outputs.version }} - name: Log in to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . push: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ac90202..f11800b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,65 @@ +## [4.19.0](https://github.com/tv2/sisyfos-audio-controller/compare/v4.18.1...v4.19.0) (2023-09-08) + + +### Features + +* Atem Fairlight Ch-Fader relation ([5bc654e](https://github.com/tv2/sisyfos-audio-controller/commit/5bc654e73cf565240be6c30b7d564f4c5b960533)) +* Ember Ch-Fader relation ([71b69c1](https://github.com/tv2/sisyfos-audio-controller/commit/71b69c11d9f1ab6f049d759685a392287ab9f9a2)) +* Midas channel-fader relation ([6a495d6](https://github.com/tv2/sisyfos-audio-controller/commit/6a495d6c9898f38d99f8fb3d95164afeda563eb9)) +* MidiMixer Channel-Fader relation ([4417b2f](https://github.com/tv2/sisyfos-audio-controller/commit/4417b2fe42ab1ab813b68f1818c6fb185883c2be)) +* Optionally allow the fade time to be specified with the fader level ([edf95b0](https://github.com/tv2/sisyfos-audio-controller/commit/edf95b0f2bc64f61707309529393e946bb1676f2)) +* OSC mixer remove last .assignedFader reference ([a72497a](https://github.com/tv2/sisyfos-audio-controller/commit/a72497a73f62811b97c339bf43657a3c7359a3d8)) +* rename channel to fader ([db40d02](https://github.com/tv2/sisyfos-audio-controller/commit/db40d02feefd4f2b50b423bfe8dfc8fe4c2f8d28)) +* rename channel to faderIndex & use fader ref in channelroutesettings ([454e3a2](https://github.com/tv2/sisyfos-audio-controller/commit/454e3a2c1f318334f64a80f720f4c2238b33fef7)) +* rename handle1to1Routing to handleOneToOneRouting ([6aba807](https://github.com/tv2/sisyfos-audio-controller/commit/6aba8076a07a9fa300c240583e6e6c4f33fe3640)) +* SSL ch-fader relation ([db25280](https://github.com/tv2/sisyfos-audio-controller/commit/db252800fddc38acad1f567a3ce5f70d2b9f717d)) +* VMix channel-fader realtion ([8240673](https://github.com/tv2/sisyfos-audio-controller/commit/8240673d6def0a426559554b98c9e593e2042898)) +* YamahaQl Channel-Fader relation ([6361e39](https://github.com/tv2/sisyfos-audio-controller/commit/6361e39e0e75b58890c5696f123b726f5e6df41f)) + + +### Bug Fixes + +* cleanup fader assignments when number of mixers are changed ([2741f1c](https://github.com/tv2/sisyfos-audio-controller/commit/2741f1c9c1b37c3a8df2779e9d6451277a4f72fb)) +* clear old assignment prior to recalculate them ([ca5373e](https://github.com/tv2/sisyfos-audio-controller/commit/ca5373e2854487e0e1e5091637931be7fae22cba)) +* Don't fade if the start and end levels are the same ([80a2cdf](https://github.com/tv2/sisyfos-audio-controller/commit/80a2cdfdd044b09f0b8062c5e3179c3562c85b03)) +* don't run auxLevel request loop if channel is not assigned to any fader ([ee29125](https://github.com/tv2/sisyfos-audio-controller/commit/ee29125229f30a71e65f10d09c2ff66194f4800f)) +* fader Ch assigment ([2232442](https://github.com/tv2/sisyfos-audio-controller/commit/2232442266815ddffed8101b989c83940b6718e2)) +* false false return gave true ([8890e06](https://github.com/tv2/sisyfos-audio-controller/commit/8890e0619ffcc4d0d4e939c95d140ba3e3c78196)) +* global store war updated everytime a ping was sent ([a2597d9](https://github.com/tv2/sisyfos-audio-controller/commit/a2597d9f558d9e0222dedd68330491a8a1df2ded)) +* if size of mixer changed, SET_ASSIGNED_FADER gave an error ([9371ae1](https://github.com/tv2/sisyfos-audio-controller/commit/9371ae134bb78255500225418ffc5bdadf4cf826)) +* index in iteration was unsused ([61a3b3a](https://github.com/tv2/sisyfos-audio-controller/commit/61a3b3a1306dbd2983b417cbb29336caab16ff8a)) +* Midas OSC messages gave an error when an Fxparameter was on a channel that was not assigned to a fader. ([ab9d7ff](https://github.com/tv2/sisyfos-audio-controller/commit/ab9d7ff0553bd70d2a2e94567f9625978caedcec)) +* more optionals when no channels are assigned to a fader ([991128a](https://github.com/tv2/sisyfos-audio-controller/commit/991128a3e7dd006d31fa9c382ef355e8a0d7bad7)) +* optional if no channels are assigned to a fader ([92b6091](https://github.com/tv2/sisyfos-audio-controller/commit/92b6091042ffde9671349d8cbbef7199f0785157)) +* optional if no cvhannels are assigned to a fader ([81b5beb](https://github.com/tv2/sisyfos-audio-controller/commit/81b5bebb9374e1bb09c2d72d6e386596f0e831df)) +* rename to handleClearAllRouting ([036cc89](https://github.com/tv2/sisyfos-audio-controller/commit/036cc8908c305a7087baa75809ffda5d9d2835ad)) +* return assignedfader instead of faderindex ([686b9de](https://github.com/tv2/sisyfos-audio-controller/commit/686b9de3700c0ab6846506e4cb8be2f03179a19e)) +* revert Midas metering back to code from last release. As metering comes in "all channels at once", so reference to Channel is way more performant. ([546367b](https://github.com/tv2/sisyfos-audio-controller/commit/546367bd1d0c42a93ee4d166418a108679a3df87)) +* spelling error in isAssinged. renamed to assignedFaderIndex ([f25d537](https://github.com/tv2/sisyfos-audio-controller/commit/f25d537166f0d03d90c69ed5126b7f3bb64ef550)) +* SSLmixer remove last references to channel.assignedFader ([fef38ed](https://github.com/tv2/sisyfos-audio-controller/commit/fef38ede5c2b52acbd0e07c79e02a13069c5daf2)) +* status of monitorrouting should be boolean ([3d5bd24](https://github.com/tv2/sisyfos-audio-controller/commit/3d5bd247c08bf83607c5326dc5841238e281511d)) +* throw error if OSC protocol ports are already in use ([42c2c8a](https://github.com/tv2/sisyfos-audio-controller/commit/42c2c8a518bfa3ec06024230ff9fd6510bd7a19b)) +* unbind channel prior to binding it to new channel ([99dc4a0](https://github.com/tv2/sisyfos-audio-controller/commit/99dc4a0556472f618252efb6f21af237bda46a72)) +* update fullClientStore after clearing all ch - fader assignments ([e147a6d](https://github.com/tv2/sisyfos-audio-controller/commit/e147a6d384a38de16364673fd2bc86bbcb005b9d)) +* update gui when assignments to a fader changes ([ee56778](https://github.com/tv2/sisyfos-audio-controller/commit/ee567786052267d5c9dcfae113bc98edf572cf59)) +* use .some instead of includes on objects ([055c82c](https://github.com/tv2/sisyfos-audio-controller/commit/055c82cb0e082c5d53aded9616de67f20dbe29b3)) +* use .some() instead of includes for objects. ([bff1425](https://github.com/tv2/sisyfos-audio-controller/commit/bff14251d6da815a76f0157e6ed97495d8bcdb4c)) +* use optional on .assignedChannels ([487d15c](https://github.com/tv2/sisyfos-audio-controller/commit/487d15c451e84ed6486567173432a7f5464f8765)) + + +### Documentation + +* Document fadeTime arg for faderLevel ([e69b7b1](https://github.com/tv2/sisyfos-audio-controller/commit/e69b7b11e382e341ef76af6299117299dcec3db2)) + + +### [4.18.1](https://github.com/tv2/sisyfos-audio-controller/compare/v4.18.0...v4.18.1) (2023-06-22) + + +### Bug Fixes + +* Corrected package version to 4.18.0. ([94a605c](https://github.com/tv2/sisyfos-audio-controller/commit/94a605cae9f49cfdcb29cf1dcdd7f6980b12b21f)) + + ### [4.17.1](https://github.com/tv2/sisyfos-audio-controller/compare/v4.17.0...v4.17.1) (2022-03-11) diff --git a/Dockerfile b/Dockerfile index 3055802f..e23bcb2a 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # BUILD IMAGE -FROM node:16.14-alpine +FROM node:18.16-alpine RUN apk add --no-cache git WORKDIR /opt/sisyfos-audio-controller COPY . . @@ -9,7 +9,7 @@ RUN yarn --check-files --frozen-lockfile --production --force RUN yarn cache clean # DEPLOY IMAGE -FROM node:16.14-alpine +FROM node:18.16-alpine WORKDIR /opt/sisyfos-audio-controller COPY --from=0 /opt/sisyfos-audio-controller . EXPOSE 1176/tcp diff --git a/README.md b/README.md index 29f95c85..644fec4d 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,9 @@ To set the state send these OSC commands from you Automation to ProducersAudioMi #### Set channel faderlevel: -/ch/1/mix/faderlevel - float {between 0 and 1} +(the first defines the fader level) +(if second is missing it will take default fade value) +/ch/1/mix/faderlevel - float {between 0 and 1} - float { fadetime in ms } #### Set channel label: diff --git a/client/package.json b/client/package.json index e2131e1e..5f9d97a8 100644 --- a/client/package.json +++ b/client/package.json @@ -12,7 +12,7 @@ "@types/node": "^18.16.0", "@types/react-dom": "^18.2.4", "@types/react-test-renderer": "^18.0.0", - "@babel/core": "^7.21.8", + "@babel/core": "^7.22.10", "css-loader": "^6.7.3", "html-webpack-plugin": "^5.5.1", "react-test-renderer": "^18.2.0", diff --git a/client/src/components/ChanStrip.tsx b/client/src/components/ChanStrip.tsx index ccdbff58..13b376d6 100644 --- a/client/src/components/ChanStrip.tsx +++ b/client/src/components/ChanStrip.tsx @@ -85,7 +85,7 @@ class ChanStrip extends React.PureComponent< changeDelay(currentValue: number, addValue: number) { window.socketIoClient.emit(SOCKET_SET_FX, { fxParam: fxParamsList.DelayTime, - channel: this.props.faderIndex, + faderIndex: this.props.faderIndex, level: currentValue + addValue, }) } @@ -93,7 +93,7 @@ class ChanStrip extends React.PureComponent< handleFx(fxParam: fxParamsList, event: any) { window.socketIoClient.emit(SOCKET_SET_FX, { fxParam: fxParam, - channel: this.props.faderIndex, + faderIndex: this.props.faderIndex, level: parseFloat(event), }) } diff --git a/client/src/components/ChanStripEq.tsx b/client/src/components/ChanStripEq.tsx index 24a32985..1f43f0df 100644 --- a/client/src/components/ChanStripEq.tsx +++ b/client/src/components/ChanStripEq.tsx @@ -112,7 +112,7 @@ class ChanStripEq extends React.PureComponent< // window.storeRedux.dispatch(storeFaderFx(fxParam, this.props.faderIndex, parseFloat(level))) window.socketIoClient.emit(SOCKET_SET_FX, { fxParam: fxParam, - channel: this.props.faderIndex, + faderIndex: this.props.faderIndex, level: parseFloat(level), }) } diff --git a/client/src/components/ChanStripFull.tsx b/client/src/components/ChanStripFull.tsx index 03504a82..3396ae84 100644 --- a/client/src/components/ChanStripFull.tsx +++ b/client/src/components/ChanStripFull.tsx @@ -88,7 +88,7 @@ class ChanStripFull extends React.PureComponent< changeDelay(currentValue: number, addValue: number) { window.socketIoClient.emit(SOCKET_SET_FX, { fxParam: fxParamsList.DelayTime, - channel: this.props.faderIndex, + faderIndex: this.props.faderIndex, level: currentValue + addValue, }) } @@ -103,7 +103,7 @@ class ChanStripFull extends React.PureComponent< // window.storeRedux.dispatch(storeFaderFx(fxParam, this.props.faderIndex, parseFloat(level))) window.socketIoClient.emit(SOCKET_SET_FX, { fxParam: fxParam, - channel: this.props.faderIndex, + faderIndex: this.props.faderIndex, level: parseFloat(level), }) } diff --git a/client/src/components/Channel.tsx b/client/src/components/Channel.tsx index a27e5ab0..0834b28e 100644 --- a/client/src/components/Channel.tsx +++ b/client/src/components/Channel.tsx @@ -66,6 +66,7 @@ class Channel extends React.Component< nextProps.settings.showChanStrip != this.props.settings.showChanStrip || nextProps.fader.amixOn != this.props.fader.amixOn || + nextProps.fader.assignedChannels != this.props.fader.assignedChannels || XOR(nextProps.fader.capabilities, this.props.fader.capabilities) || XOR( nextProps.fader.capabilities?.hasAMix, diff --git a/client/src/components/ChannelMonitorOptions.tsx b/client/src/components/ChannelMonitorOptions.tsx index a9af7284..75254f40 100644 --- a/client/src/components/ChannelMonitorOptions.tsx +++ b/client/src/components/ChannelMonitorOptions.tsx @@ -64,7 +64,7 @@ class ChannelMonitorOptions extends React.PureComponent< if ( window.confirm( 'This will remove all monitor assignments to Aux :' + - String(this.props.fader[this.faderIndex].monitor) + String(this.props.fader[this.faderIndex].monitor) ) ) { this.props.channel.forEach((channel: any, index: number) => { @@ -81,7 +81,7 @@ class ChannelMonitorOptions extends React.PureComponent< if ( window.confirm( 'Send all channels to Aux: ' + - String(this.props.fader[this.faderIndex].monitor) + String(this.props.fader[this.faderIndex].monitor) ) ) { this.props.channel.forEach((channel: any, index: number) => { @@ -154,10 +154,11 @@ class ChannelMonitorOptions extends React.PureComponent< />
{this.props.channel.map((channel: any, index: number) => { - let isSelected: boolean = - this.props.channel[index].auxLevel[ + let isSelected: boolean = ( + channel.auxLevel[ this.props.fader[this.faderIndex].monitor - 1 - ] + ] >= 0 + ) return (
{ + if (fader.assignedChannels.some((assignedChan) => { + return assignedChan.mixerIndex === mixerIndex && assignedChan.channelIndex === channelIndex + })) { + window.socketIoClient.emit(SOCKET_ASSIGN_CH_TO_FADER, { + mixerIndex: mixerIndex, + channel: channelIndex, + faderIndex: index, + assigned: false + }) + } }) } + + + window.socketIoClient.emit(SOCKET_ASSIGN_CH_TO_FADER, { + mixerIndex: mixerIndex, + channel: channelIndex, + faderIndex: this.faderIndex, + assigned: event.target.checked + }) } } - handleClearRouting() { + handleClearAllRouting() { if (window.confirm('REMOVE ALL FADER ASSIGNMENTS????')) { - this.props.chMixerConnections.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: any, index: number) => { - window.socketIoClient.emit( - SOCKET_SET_ASSIGNED_FADER, - { - mixerIndex: mixerIndex, - channel: index, - faderAssign: -1, - } - ) - } - ) - } - ) + window.socketIoClient.emit(SOCKET_REMOVE_ALL_CH_ASSIGNMENTS) } } - handle11Routing() { + handleOneToOneRouting() { if (window.confirm('Reassign all Faders 1:1 to Channels????')) { + window.socketIoClient.emit(SOCKET_REMOVE_ALL_CH_ASSIGNMENTS) this.props.fader.forEach((fader: any, index: number) => { if (this.props.chMixerConnections[0].channel.length > index) { - window.socketIoClient.emit(SOCKET_SET_ASSIGNED_FADER, { + window.socketIoClient.emit(SOCKET_ASSIGN_CH_TO_FADER, { mixerIndex: 0, channel: index, - faderAssign: index, + faderIndex: index, + assigned: true }) } }) @@ -110,6 +94,19 @@ class ChannelRouteSettings extends React.PureComponent< this.props.dispatch(storeShowOptions(this.faderIndex)) } + getAssignedToFaderIndex = (channel: IChannelReference): number => { + let assignedFaderIndex = -1 + this.props.fader.forEach((fader: any, index: number) => { + + if (fader.assignedChannels.some((assignedChan: IChannelReference) => { + return assignedChan.channelIndex === channel.channelIndex && assignedChan.mixerIndex === channel.mixerIndex + })) + assignedFaderIndex = index + }) + return assignedFaderIndex + } + + renderMixer(chMixerConnection: IchMixerConnection, mixerIndex: number) { return (
@@ -118,19 +115,20 @@ class ChannelRouteSettings extends React.PureComponent< {'MIXER ' + (mixerIndex + 1)}

{chMixerConnection.channel.map((channel: any, index: number) => { + const assignedFaderIndex = this.getAssignedToFaderIndex({ mixerIndex: mixerIndex, channelIndex: index }) return (
{' Channel ' + (index + 1) + ' : '} this.handleAssignChannel( @@ -140,10 +138,10 @@ class ChannelRouteSettings extends React.PureComponent< ) } /> - {channel.assignedFader >= 0 + {assignedFaderIndex >= 0 ? ' (Fader ' + - (channel.assignedFader + 1) + - ')' + (assignedFaderIndex + 1) + + ')' : ' (not assigned)'}
) @@ -161,13 +159,13 @@ class ChannelRouteSettings extends React.PureComponent< diff --git a/package.json b/package.json index bf3db231..ce535b26 100644 --- a/package.json +++ b/package.json @@ -1,86 +1,86 @@ -{ - "name": "sisyfos-audio-controller", - "version": "4.17.1", - "description": "Audio mixer build with the logic from a video mixer", - "license": "MIT", - "author": { - "name": "Kasper Olsson Hans (TV2 Denmark)", - "email": "github@olzzon.dk" - }, - "contributors": [ - { - "name": "Balte de Wit", - "email": "balte@superfly.tv", - "url": "https://superfly.tv" - }, - { - "name": "Jan Starzak", - "email": "jan@superfly.tv", - "url": "https://superfly.tv" - }, - { - "name": "Anders Frederik Jørgensen", - "email": "afjo@tv2.dk" - } - ], - "keywords": [ - "app", - "audio", - "open-source" - ], - "engines": { - "node": ">=14.17.6", - "yarn": ">=1.0.0" - }, - "private": true, - "workspaces": [ - "client", - "server", - "shared", - "desktop" - ], - "scripts": { - "start": "cross-env NODE_ENV=production node server/dist/server", - "start:dev": "cross-env NODE_ENV=development node --inspect server/dist/server", - "start:local": "cross-env NODE_ENV=local node --inspect server/dist/server", - "build": "yarn build:client && yarn build:server", - "build:client": "yarn --cwd ./client build", - "build:server": "yarn --cwd ./server build", - "build:desktop": "yarn --cwd ./desktop build", - "watch": "concurrently --kill-others \"yarn watch:server\" \"yarn watch:client\"", - "watch:client": "yarn --cwd ./client watch", - "watch:server": "yarn --cwd ./server watch", - "test": "yarn test:client && yarn test:server", - "test:client": "yarn --cwd ./client test", - "test:server": "yarn --cwd ./server test", - "test:watch": "concurrently --kill-others \"yarn --cwd ./client test:watch\" \"yarn --cwd ./server test:watch\"", - "lint": "prettier --write", - "validate": "yarn validate:dependencies && yarn validate:license", - "validate:dependencies": "yarn audit --groups dependencies", - "validate:license": "node-license-validator -p -d --allow-licenses MIT MIT/X11 BSD 0BSD BSD-3-Clause BSD-2-Clause ISC Apache Apache-2.0 WTFPL CC-BY-3.0 CC-BY-4.0 CC0-1.0 GPL Python-2.0 Unlicense --allow-packages cycle", - "clean": "rimraf **/dist **/release", - "reset": "yarn clean && rimraf **/node_modules node_modules" - }, - "simple-git-hooks": { - "pre-commit": "yarn lint-staged" - }, - "lint-staged": { - "*.{js,ts,css,json,md}": [ - "prettier --write" - ] - }, - "dependencies": { - "cross-env": "^7.0.3" - }, - "devDependencies": { - "concurrently": "^8.0.1", - "lint-staged": "^13.2.2", - "node-license-validator": "^1.3.2", - "prettier": "^2.8.8", - "rimraf": "^5.0.0" - }, - "resolutions": { - "xml2js": "^0.5.0", - "socket.io-parser": "^4.2.3" - } -} +{ + "name": "sisyfos-audio-controller", + "version": "4.19.0", + "description": "Audio mixer build with the logic from a video mixer", + "license": "MIT", + "author": { + "name": "Kasper Olsson Hans (TV2 Denmark)", + "email": "github@olzzon.dk" + }, + "contributors": [ + { + "name": "Balte de Wit", + "email": "balte@superfly.tv", + "url": "https://superfly.tv" + }, + { + "name": "Jan Starzak", + "email": "jan@superfly.tv", + "url": "https://superfly.tv" + }, + { + "name": "Anders Frederik Jørgensen", + "email": "afjo@tv2.dk" + } + ], + "keywords": [ + "app", + "audio", + "open-source" + ], + "engines": { + "node": ">=18.15.0", + "yarn": ">=1.22.0" + }, + "private": true, + "workspaces": [ + "client", + "server", + "shared", + "desktop" + ], + "scripts": { + "start": "cross-env NODE_ENV=production node server/dist/server", + "start:dev": "cross-env NODE_ENV=development node --inspect server/dist/server", + "start:local": "cross-env NODE_ENV=local node --inspect server/dist/server", + "build": "yarn build:client && yarn build:server", + "build:client": "yarn --cwd ./client build", + "build:server": "yarn --cwd ./server build", + "build:desktop": "yarn --cwd ./desktop build", + "watch": "concurrently --kill-others \"yarn watch:server\" \"yarn watch:client\"", + "watch:client": "yarn --cwd ./client watch", + "watch:server": "yarn --cwd ./server watch", + "test": "yarn test:client && yarn test:server", + "test:client": "yarn --cwd ./client test", + "test:server": "yarn --cwd ./server test", + "test:watch": "concurrently --kill-others \"yarn --cwd ./client test:watch\" \"yarn --cwd ./server test:watch\"", + "lint": "prettier --write", + "validate": "yarn validate:dependencies && yarn validate:license", + "validate:dependencies": "yarn audit --groups dependencies", + "validate:license": "node-license-validator -p -d --allow-licenses MIT MIT/X11 BSD 0BSD BSD-3-Clause BSD-2-Clause ISC Apache Apache-2.0 WTFPL CC-BY-3.0 CC-BY-4.0 CC0-1.0 GPL Python-2.0 Unlicense --allow-packages cycle", + "clean": "rimraf **/dist **/release", + "reset": "yarn clean && rimraf **/node_modules node_modules" + }, + "simple-git-hooks": { + "pre-commit": "yarn lint-staged" + }, + "lint-staged": { + "*.{js,ts,css,json,md}": [ + "prettier --write" + ] + }, + "dependencies": { + "cross-env": "^7.0.3" + }, + "devDependencies": { + "concurrently": "^8.0.1", + "lint-staged": "^13.2.2", + "node-license-validator": "^1.3.2", + "prettier": "^2.8.8", + "rimraf": "^5.0.0" + }, + "resolutions": { + "xml2js": "^0.5.0", + "socket.io-parser": "^4.2.3" + } +} \ No newline at end of file diff --git a/server/package.json b/server/package.json index 561dafdd..0eeb6739 100644 --- a/server/package.json +++ b/server/package.json @@ -18,17 +18,17 @@ "typescript": "^5.0.4" }, "dependencies": { - "@babel/core": "^7.21.8", + "@babel/core": "^7.22.10", "@tv2media/logger": "^2.0.1", "atem-connection": "^3.2.0", "casparcg-connection": "^5.1.0", - "emberplus-connection": "^0.1.2", + "emberplus-connection": "^0.2.1", "express": "^4.18.2", "node-emberplus": "^3.0.5", "node-vmix": "^1.6.1", "osc": "^2.4.4", "performance-now": "^2.1.0", - "redux": "^4.1.2", + "redux": "^4.2.1", "socket.io": "^4.6.2", "tslib": "^2.5.0", "vmix-js-utils": "^4.0.16", @@ -36,4 +36,4 @@ "webmidi": "^2.5.1", "shared": "file:../shared" } -} +} \ No newline at end of file diff --git a/server/src/MainThreadHandler.ts b/server/src/MainThreadHandler.ts index 0673ecc3..a0a20153 100644 --- a/server/src/MainThreadHandler.ts +++ b/server/src/MainThreadHandler.ts @@ -11,6 +11,7 @@ import { socketServer } from './expressHandler' import { storeUpdateSettings } from '../../shared/src/actions/settingsActions' import * as IO from '../../shared/src/constants/SOCKET_IO_DISPATCHERS' import * as FADER_ACTIONS from '../../shared/src/actions/faderActions' +import * as CHANNEL_ACTIONS from '../../shared/src/actions/channelActions' import { loadSettings, @@ -26,7 +27,6 @@ import { import { storeFlushChLabels, - storeSetAssignedFader, storeSetAuxLevel, } from '../../shared/src/actions/channelActions' import { logger } from './utils/logger' @@ -34,6 +34,7 @@ import { ICustomPages } from '../../shared/src/reducers/settingsReducer' import { fxParamsList } from '../../shared/src/constants/MixerProtocolInterface' import path from 'path' import { IChannel } from '../../shared/src/reducers/channelsReducer' +import { IChannelReference } from '../../shared/src/reducers/fadersReducer' export class MainThreadHandlers { snapshotHandler: SnapshotHandler @@ -43,10 +44,11 @@ export class MainThreadHandlers { this.snapshotHandler = new SnapshotHandler() store.dispatch(storeUpdateSettings(loadSettings(state))) + this.cleanUpAssignedChannelsOnFaders() + this.reIndexAssignedChannelsRelation() } updateFullClientStore() { - this.recalcAssignedChannels() socketServer.emit(IO.SOCKET_SET_FULL_STORE, state) } @@ -55,18 +57,16 @@ export class MainThreadHandlers { faderIndex: faderIndex, state: state.faders[0].fader[faderIndex], }) - state.channels[0].chMixerConnection.forEach((chMixerConnection) => { - chMixerConnection.channel.forEach( - (channel: IChannel, index: number) => { - if (channel.assignedFader === faderIndex) { - socketServer.emit(IO.SOCKET_SET_STORE_CHANNEL, { - channelIndex: index, - state: channel, - }) - } - } - ) - }) + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (channel: IChannelReference) => { + socketServer.emit(IO.SOCKET_SET_STORE_CHANNEL, { + channelIndex: channel.channelIndex, + state: state.channels[0].chMixerConnection[channel.mixerIndex] + .channel[channel.channelIndex], + }) + } + ) + } updateMixerOnline(mixerIndex: number, onLineState?: boolean) { @@ -77,22 +77,35 @@ export class MainThreadHandlers { }) } - // Assigned channel to faders are right now based on Channel.assignedFader - // Plan is to change it so fader.assignedChannel will be the master (a lot of change in code is needed) - recalcAssignedChannels() { - store.dispatch(FADER_ACTIONS.removeAllAssignedChannels()) - state.channels[0].chMixerConnection.forEach((mixer, mixerIndex) => { - mixer.channel.forEach((channel: IChannel, channelIndex) => { - if ( - channel.assignedFader >= 0 && - state.faders[0].fader[channel.assignedFader] - ) { + reIndexAssignedChannelsRelation() { + state.channels[0].chMixerConnection.forEach((mixer: any) => { + mixer.channel.forEach((channel: IChannel) => { + channel.assignedFader = -1 + }) + }) + state.faders[0].fader.forEach((fader, faderIndex) => { + fader.assignedChannels?.forEach((channel: IChannelReference) => { + store.dispatch( + CHANNEL_ACTIONS.storeSetAssignedFader( + channel.mixerIndex, + channel.channelIndex, + faderIndex + ) + ) + }) + }) + } + + cleanUpAssignedChannelsOnFaders() { + state.faders[0].fader.forEach((fader, faderIndex) => { + fader.assignedChannels?.forEach((channel: IChannelReference) => { + if (state.settings[0].numberOfMixers < channel.mixerIndex + 1) { store.dispatch( FADER_ACTIONS.storeSetAssignedChannel( - channel.assignedFader, - mixerIndex, - channelIndex, - true + faderIndex, + channel.mixerIndex, + channel.channelIndex, + false ) ) } @@ -100,14 +113,15 @@ export class MainThreadHandlers { }) } + + socketServerHandlers(socket: any) { logger.info('Setting up socket IO main handlers.') - // get-store get-settings and get-mixerprotocol will be replaces with - // serverside Redux middleware emitter when moved to Socket IO: socket .on('get-store', () => { logger.info(`Setting initial store on: ${socket.client.id}`) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() }) .on('get-settings', () => { @@ -117,7 +131,7 @@ export class MainThreadHandlers { socketServer.emit('set-mixerprotocol', { mixerProtocol: mixerProtocolPresets[ - state.settings[0].mixers[0].mixerProtocol + state.settings[0].mixers[0].mixerProtocol ], mixerProtocolPresets: mixerProtocolPresets, mixerProtocolList: mixerProtocolList, @@ -136,6 +150,7 @@ export class MainThreadHandlers { path.join(STORAGE_FOLDER, payload), true ) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() }) .on(IO.SOCKET_SAVE_SNAPSHOT, (payload: string) => { @@ -168,11 +183,13 @@ export class MainThreadHandlers { .on(IO.SOCKET_SAVE_CCG_FILE, (payload: any) => { logger.info(`Set default CCG File: ${payload}`) setCcgDefault(payload) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() }) .on(IO.SOCKET_LOAD_MIXER_PRESET, (payload: any) => { logger.info(`Set Mixer Preset: ${payload}`) mixerGenericConnection.loadMixerPreset(payload) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() }) .on(IO.SOCKET_GET_PAGES_LIST, () => { @@ -212,6 +229,7 @@ export class MainThreadHandlers { .on(IO.SOCKET_SAVE_SETTINGS, (payload: any) => { logger.data(payload).info('Save settings:') saveSettings(payload) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() /** Delay restart to ensure the async saveSettings is done before restarting*/ setTimeout(() => { @@ -221,22 +239,30 @@ export class MainThreadHandlers { .on(IO.SOCKET_RESTART_SERVER, () => { process.exit(0) }) - .on(IO.SOCKET_SET_ASSIGNED_FADER, (payload: any) => { + .on(IO.SOCKET_ASSIGN_CH_TO_FADER, (payload: any) => { logger.trace( - `Set assigned fader.\n Mixer: ${ - payload.mixerIndex + 1 - }\n Channel: ${payload.channel}\n Fader: ${ - payload.faderAssign + `Set assigned fader.\n Mixer: ${payload.mixerIndex + 1 + }\n Channel: ${payload.channel}\n Fader: ${payload.faderAssign }` ) store.dispatch( - storeSetAssignedFader( + FADER_ACTIONS.storeSetAssignedChannel( + payload.faderIndex, payload.mixerIndex, payload.channel, - payload.faderAssign + payload.assigned ) ) - + this.reIndexAssignedChannelsRelation() + this.updateFullClientStore() + }) + .on(IO.SOCKET_REMOVE_ALL_CH_ASSIGNMENTS, () => { + logger.trace( + `Remove all channel assignments.\n`) + store.dispatch( + FADER_ACTIONS.removeAllAssignedChannels() + ) + this.reIndexAssignedChannelsRelation() this.updateFullClientStore() }) .on(IO.SOCKET_SET_FADER_MONITOR, (payload: any) => { @@ -290,15 +316,15 @@ export class MainThreadHandlers { store.dispatch( FADER_ACTIONS.storeFaderFx( payload.fxParam, - payload.channel, + payload.faderIndex, payload.level ) ) mixerGenericConnection.updateFx( payload.fxParam, - payload.channel + payload.faderIndex ) - this.updatePartialStore(payload.channel) + this.updatePartialStore(payload.faderIndex) }) .on(IO.SOCKET_NEXT_MIX, () => { store.dispatch(FADER_ACTIONS.storeNextMix()) @@ -354,8 +380,7 @@ export class MainThreadHandlers { }) .on(IO.SOCKET_SET_FADERLEVEL, (payload: any) => { logger.trace( - `Set fader level\n Channel: ${ - payload.faderIndex + 1 + `Set fader level\n Channel: ${payload.faderIndex + 1 }\n Level: ${payload.level}` ) store.dispatch( @@ -370,8 +395,7 @@ export class MainThreadHandlers { }) .on(IO.SOCKET_SET_INPUT_GAIN, (payload: any) => { logger.trace( - `Set fInput\n Gain Channel: ${ - payload.faderIndex + 1 + `Set fInput\n Gain Channel: ${payload.faderIndex + 1 }\n Level: ${payload.level}` ) store.dispatch( @@ -385,8 +409,7 @@ export class MainThreadHandlers { }) .on(IO.SOCKET_SET_INPUT_SELECTOR, (payload: any) => { logger.trace( - `Set Input selector: ${ - payload.faderIndex + 1 + `Set Input selector: ${payload.faderIndex + 1 }\n Selected: ${payload.selected}` ) logger.debug(payload) diff --git a/server/src/utils/AutomationConnection.ts b/server/src/utils/AutomationConnection.ts index c10dd44f..03d47c8b 100644 --- a/server/src/utils/AutomationConnection.ts +++ b/server/src/utils/AutomationConnection.ts @@ -147,7 +147,14 @@ export class AutomationConnection { } else if (check('CHANNEL_FADER_LEVEL')) { wrapChannelCommand((ch: any) => { store.dispatch(storeFaderLevel(ch - 1, message.args[0])) - mixerGenericConnection.updateOutLevel(ch - 1, -1) + if (message.args.length > 1) { + mixerGenericConnection.updateOutLevel( + ch - 1, + parseFloat(message.args[1]) + ) + } else { + mixerGenericConnection.updateOutLevel(ch - 1, -1) + } global.mainThreadHandler.updatePartialStore(ch - 1) }) } else if (check('INJECT_COMMAND')) { diff --git a/server/src/utils/MixerConnection.ts b/server/src/utils/MixerConnection.ts index d369306e..82f8b32a 100644 --- a/server/src/utils/MixerConnection.ts +++ b/server/src/utils/MixerConnection.ts @@ -21,7 +21,6 @@ import { StuderMixerConnection } from './mixerConnections/StuderMixerConnection' import { StuderVistaMixerConnection } from './mixerConnections/StuderVistaMixerConnection' import { CasparCGConnection } from './mixerConnections/CasparCGConnection' import { - IChannel, IchMixerConnection, } from '../../../shared/src/reducers/channelsReducer' import { @@ -30,6 +29,7 @@ import { } from '../../../shared/src/actions/channelActions' import { storeFaderLevel } from '../../../shared/src/actions/faderActions' import { AtemMixerConnection } from './mixerConnections/AtemConnection' +import { IChannelReference } from '../../../shared/src/reducers/fadersReducer' export class MixerGenericConnection { store: any @@ -47,7 +47,7 @@ export class MixerGenericConnection { state.settings[0].mixers.forEach((none: any, index: number) => { this.mixerProtocol.push( MixerProtocolPresets[ - state.settings[0].mixers[index].mixerProtocol + state.settings[0].mixers[index].mixerProtocol ] || MixerProtocolPresets.sslSystemT ) this.mixerConnection.push({}) @@ -201,19 +201,15 @@ export class MixerGenericConnection { } } - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - if (mixerIndex !== mixerIndexToSkip) { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.fadeInOut( - mixerIndex, - channelIndex, - fadeTime - ) - } - } + + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + if (assignedChannel.mixerIndex !== mixerIndexToSkip) { + this.fadeInOut( + assignedChannel.mixerIndex, + assignedChannel.channelIndex, + faderIndex, + fadeTime, ) } } @@ -229,17 +225,11 @@ export class MixerGenericConnection { updateInputGain = (faderIndex: number) => { let level = state.faders[0].fader[faderIndex].inputGain - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[mixerIndex].updateInputGain( - channelIndex, - level - ) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + this.mixerConnection[assignedChannel.mixerIndex].updateInputGain( + assignedChannel.channelIndex, + level, ) } ) @@ -248,16 +238,11 @@ export class MixerGenericConnection { updateInputSelector = (faderIndex: number) => { let inputSelected = state.faders[0].fader[faderIndex].inputSelector logger.trace(`${faderIndex} ${inputSelected}`) - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[ - mixerIndex - ].updateInputSelector(channelIndex, inputSelected) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + this.mixerConnection[assignedChannel.mixerIndex].updateInputSelector( + assignedChannel.channelIndex, + inputSelected, ) } ) @@ -268,20 +253,12 @@ export class MixerGenericConnection { } updateMuteState = (faderIndex: number, mixerIndexToSkip: number = -1) => { - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - if (mixerIndex !== mixerIndexToSkip) { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[ - mixerIndex - ].updateMuteState( - channelIndex, - state.faders[0].fader[faderIndex].muteOn - ) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + if (assignedChannel.mixerIndex !== mixerIndexToSkip) { + this.mixerConnection[assignedChannel.mixerIndex].updateMuteState( + assignedChannel.channelIndex, + state.faders[0].fader[faderIndex].muteOn, ) } } @@ -289,17 +266,11 @@ export class MixerGenericConnection { } updateAMixState = (faderIndex: number) => { - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[mixerIndex].updateAMixState( - channelIndex, - state.faders[0].fader[faderIndex].amixOn - ) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + this.mixerConnection[assignedChannel.mixerIndex].updateAMixState( + assignedChannel.channelIndex, + state.faders[0].fader[faderIndex].amixOn, ) } ) @@ -315,17 +286,11 @@ export class MixerGenericConnection { (100 - state.settings[0].voLevel)) / 100 } - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[mixerIndex].updateNextAux( - channelIndex, - level - ) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + this.mixerConnection[assignedChannel.mixerIndex].updateNextAux( + assignedChannel.channelIndex, + level, ) } ) @@ -333,22 +298,17 @@ export class MixerGenericConnection { updateFx = (fxParam: fxParamsList, faderIndex: number) => { let level: number = state.faders[0].fader[faderIndex][fxParam][0] - state.channels[0].chMixerConnection.forEach( - (chMixerConnection: IchMixerConnection, mixerIndex: number) => { - chMixerConnection.channel.forEach( - (channel: IChannel, channelIndex: number) => { - if (faderIndex === channel.assignedFader) { - this.mixerConnection[mixerIndex].updateFx( - fxParam, - channelIndex, - level - ) - } - } + state.faders[0].fader[faderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + this.mixerConnection[assignedChannel.mixerIndex].updateFx( + fxParam, + assignedChannel.channelIndex, + level, ) } ) } + updateAuxLevel = (channelIndex: number, auxSendIndex: number) => { let channel = state.channels[0].chMixerConnection[0].channel[channelIndex] @@ -386,12 +346,9 @@ export class MixerGenericConnection { fadeInOut = ( mixerIndex: number, channelIndex: number, + faderIndex: number, fadeTime: number ) => { - let faderIndex = - state.channels[0].chMixerConnection[mixerIndex].channel[ - channelIndex - ].assignedFader if ( !state.faders[0].fader[faderIndex].pgmOn && !state.faders[0].fader[faderIndex].voOn && @@ -495,7 +452,7 @@ export class MixerGenericConnection { const currentTimeMS = Date.now() const elapsedTimeMS = currentTimeMS - startTimeAsMs - if (elapsedTimeMS >= fadeTime) { + if (elapsedTimeMS >= fadeTime || endLevel === startLevel) { this.mixerConnection[mixerIndex].updateFadeIOLevel( channelIndex, endLevel @@ -511,7 +468,7 @@ export class MixerGenericConnection { const currentOutputLevel = startLevel + (endLevel - startLevel) * - Math.max(0, Math.min(1, elapsedTimeMS / fadeTime)) + Math.max(0, Math.min(1, elapsedTimeMS / fadeTime)) this.mixerConnection[mixerIndex].updateFadeIOLevel( channelIndex, diff --git a/server/src/utils/mixerConnections/AtemConnection.ts b/server/src/utils/mixerConnections/AtemConnection.ts index 88231df2..ffc78a7e 100644 --- a/server/src/utils/mixerConnections/AtemConnection.ts +++ b/server/src/utils/mixerConnections/AtemConnection.ts @@ -7,7 +7,7 @@ import { } from '../../../../shared/src/constants/MixerProtocolInterface' import { logger } from '../logger' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' -import { IFader } from '../../../../shared/src/reducers/fadersReducer' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' import { IChannel } from '../../../../shared/src/reducers/channelsReducer' import { dbToFloat, floatToDB } from './LawoRubyConnection' import { @@ -64,7 +64,7 @@ export class AtemMixerConnection { .data(error) .error( 'Failed to connect to atem ' + - state.settings[0].mixers[this.mixerIndex].deviceIp + state.settings[0].mixers[this.mixerIndex].deviceIp ) }) } @@ -104,17 +104,17 @@ export class AtemMixerConnection { if ( channelIndex === undefined || !state.fairlight.inputs[input].sources[ - this._sourceTracks[channelIndex] + this._sourceTracks[channelIndex] ] ) { continue } const channel = this.getChannel(channelIndex) - const fader = this.getFaderFromChannelIndex(channelIndex) + const fader = this.getAssignedFader(channelIndex) const source = state.fairlight.inputs[input].sources[ - this._sourceTracks[channelIndex] + this._sourceTracks[channelIndex] ] this.setPropsFromChannel(channelIndex, channel, fader, source) @@ -194,10 +194,10 @@ export class AtemMixerConnection { updateInputSelector(channelIndex: number, inputSelected: number) { const { channelTypeIndex } = this.getChannel(channelIndex) - const { pgmOn, pflOn } = this.getFaderFromChannelIndex(channelIndex) + const { pgmOn, pflOn } = this.getAssignedFader(channelIndex) const tracks = this.mixerProtocol.channelTypes[0].toMixer.CHANNEL_INPUT_SELECTOR?.[ - inputSelected - 1 + inputSelected - 1 ] if (!tracks) return @@ -276,8 +276,8 @@ export class AtemMixerConnection { updateFadeIOLevel(channelIndex: number, level: number): void { const channel = this.getChannel(channelIndex) - const fader = this.getFaderFromChannelIndex(channelIndex) - const { muteOn } = this.getFaderFromChannelIndex(channelIndex) + const fader = this.getAssignedFader(channelIndex) + const { muteOn } = this.getAssignedFader(channelIndex) const sourceNo = this._chNoToSource[channel.channelTypeIndex] if (level > 0 && !muteOn) { @@ -311,14 +311,20 @@ export class AtemMixerConnection { } } - private getFaderFromChannelIndex(channelIndex: number): IFader { - const faderIndex = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelIndex - ].assignedFader - - return state.faders[0].fader[faderIndex] + private getAssignedFader(channelIndex: number): IFader { + return (state.faders[0].fader.find((fader: IFader) => { + return ( + fader.assignedChannels?.some((assignedChannel: IChannelReference) => { + return ( + assignedChannel.mixerIndex === this.mixerIndex && + assignedChannel.channelIndex === channelIndex + ) + }) + ) + } + )) } + private getChannel(channelIndex: number): IChannel { return state.channels[0].chMixerConnection[this.mixerIndex].channel[ channelIndex diff --git a/server/src/utils/mixerConnections/EmberMixerConnection.ts b/server/src/utils/mixerConnections/EmberMixerConnection.ts index f87a3733..aea87d8c 100644 --- a/server/src/utils/mixerConnections/EmberMixerConnection.ts +++ b/server/src/utils/mixerConnections/EmberMixerConnection.ts @@ -27,6 +27,11 @@ import { storeSetChLabel, } from '../../../../shared/src/actions/channelActions' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' +import { + IChannelReference, + IFader, +} from '../../../../shared/src/reducers/fadersReducer' +import { EmberElement, NumberedTreeNode } from 'emberplus-connection/dist/model' export class EmberMixerConnection { mixerProtocol: IMixerProtocol @@ -47,6 +52,17 @@ export class EmberMixerConnection { this.setupEmberSocket() } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex((fader: IFader) => + fader.assignedChannels?.some((assigned: IChannelReference) => { + return ( + assigned.mixerIndex === this.mixerIndex && + assigned.channelIndex === channelIndex + ) + }) + ) + } + setupEmberSocket() { logger.info('Setting up new Ember connection') this.emberConnection = new EmberClient( @@ -187,6 +203,7 @@ export class EmberMixerConnection { const mixerMessage = 'Channels.Inputs.${channel}.Fader' const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) await this.subscribeToEmberNode( channelTypeIndex, @@ -202,25 +219,20 @@ export class EmberMixerConnection { channelTypeIndex ) } - store.dispatch( - storeShowChannel(channel.assignedFader, true) - ) + store.dispatch(storeShowChannel(assignedFaderIndex, true)) global.mainThreadHandler.updatePartialStore( - channel.assignedFader + assignedFaderIndex ) } else { logger.info(`Channel ${ch} offline`) - store.dispatch( - storeShowChannel(channel.assignedFader, false) - ) + store.dispatch(storeShowChannel(assignedFaderIndex, false)) global.mainThreadHandler.updatePartialStore( - channel.assignedFader + assignedFaderIndex ) } } ) } - async subscribeToEmberNode( channelTypeIndex: number, mixerMessage: string, @@ -240,7 +252,10 @@ export class EmberMixerConnection { ) if (!node) return - await this.emberConnection.subscribe(node, cb) + await this.emberConnection.subscribe( + node as NumberedTreeNode, + cb + ) cb(node) } catch (e) { @@ -269,34 +284,31 @@ export class EmberMixerConnection { const channel = state.channels[0].chMixerConnection[this.mixerIndex] .channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) logger.trace( `Receiving Level from Ch "${ch}", val: ${val}, level: ${level}` ) if (!channel.fadeActive && level >= 0 && level <= 1) { - store.dispatch( - storeFaderLevel(channel.assignedFader, level) - ) + store.dispatch(storeFaderLevel(assignedFaderIndex, level)) store.dispatch({ type: SET_OUTPUT_LEVEL, - channel: channel.assignedFader, + channel: assignedFaderIndex, mixerIndex: this.mixerIndex, level, }) // toggle pgm based on level logger.trace(`Set Channel ${ch} pgmOn ${level > 0}`) - store.dispatch( - storeSetPgm(channel.assignedFader, level > 0) - ) + store.dispatch(storeSetPgm(assignedFaderIndex, level > 0)) global.mainThreadHandler.updatePartialStore( - channel.assignedFader + assignedFaderIndex ) if (remoteConnections) { remoteConnections.updateRemoteFaderState( - channel.assignedFader, + assignedFaderIndex, level ) } @@ -317,6 +329,7 @@ export class EmberMixerConnection { .mixerMessage const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) await this.subscribeToEmberNode( channelTypeIndex, mixerMessage, @@ -346,9 +359,7 @@ export class EmberMixerConnection { ) ) } - global.mainThreadHandler.updatePartialStore( - channel.assignedFader - ) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } ) } @@ -363,7 +374,7 @@ export class EmberMixerConnection { .mixerMessage const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] - + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) await this.subscribeToEmberNode( channelTypeIndex, mixerMessage, @@ -375,13 +386,11 @@ export class EmberMixerConnection { ) store.dispatch( storeSetPfl( - channel.assignedFader, + assignedFaderIndex, (node.contents as Model.Parameter).value as boolean ) ) - global.mainThreadHandler.updatePartialStore( - channel.assignedFader - ) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } ) } @@ -396,7 +405,7 @@ export class EmberMixerConnection { .CHANNEL_INPUT_GAIN[0].mixerMessage const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] - + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) await this.subscribeToEmberNode( channelTypeIndex, mixerMessage, @@ -417,10 +426,8 @@ export class EmberMixerConnection { // assume it is in db now level = this._faderLevelToFloat(Number(level), 0) - store.dispatch(storeInputGain(channel.assignedFader, level)) - global.mainThreadHandler.updatePartialStore( - channel.assignedFader - ) + store.dispatch(storeInputGain(assignedFaderIndex, level)) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } ) } @@ -432,6 +439,7 @@ export class EmberMixerConnection { ) { const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) for (const i in this.mixerProtocol.channelTypes[typeIndex].fromMixer .CHANNEL_INPUT_SELECTOR) { const proto = @@ -459,13 +467,13 @@ export class EmberMixerConnection { ) store.dispatch( storeInputSelector( - channel.assignedFader, + assignedFaderIndex, Number(i) + 1 ) ) } global.mainThreadHandler.updatePartialStore( - channel.assignedFader + assignedFaderIndex ) } ) @@ -481,6 +489,7 @@ export class EmberMixerConnection { const mixerMessage = 'Channels.Inputs.${channel}.Channel States.Stereo' const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) await this.subscribeToEmberNode( channelTypeIndex, mixerMessage, @@ -492,14 +501,12 @@ export class EmberMixerConnection { ) store.dispatch( storeCapability( - channel.assignedFader, + assignedFaderIndex, 'hasInputSelector', (node.contents as Model.Parameter).value as boolean ) ) - global.mainThreadHandler.updatePartialStore( - channel.assignedFader - ) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } ) // subscribe to input selectors @@ -509,15 +516,15 @@ export class EmberMixerConnection { const updateState = () => { if (llState && !rrState) { logger.trace(`Input selector state: ll`) - store.dispatch(storeInputSelector(channel.assignedFader, 2)) + store.dispatch(storeInputSelector(assignedFaderIndex, 2)) } else if (rrState && !llState) { logger.trace(`Input selector state: rr`) - store.dispatch(storeInputSelector(channel.assignedFader, 3)) + store.dispatch(storeInputSelector(assignedFaderIndex, 3)) } else { logger.trace(`Input selector state: lr`) - store.dispatch(storeInputSelector(channel.assignedFader, 1)) + store.dispatch(storeInputSelector(assignedFaderIndex, 1)) } - global.mainThreadHandler.updatePartialStore(channel.assignedFader) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } const llMixerMessage = @@ -562,6 +569,7 @@ export class EmberMixerConnection { ) { const channel = state.channels[0].chMixerConnection[this.mixerIndex].channel[ch - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) if (this.mixerProtocol.label === LawoMC2.label) { // subscription for enabling amix button const mixerMessage = @@ -577,7 +585,7 @@ export class EmberMixerConnection { ) store.dispatch( storeCapability( - channel.assignedFader, + assignedFaderIndex, 'hasAMix', (node.contents as Model.Parameter).value !== ((node.contents as Model.Parameter).maximum || @@ -585,7 +593,7 @@ export class EmberMixerConnection { ) ) global.mainThreadHandler.updatePartialStore( - channel.assignedFader + assignedFaderIndex ) } ) @@ -605,13 +613,11 @@ export class EmberMixerConnection { ) store.dispatch( storeSetAMix( - channel.assignedFader, + assignedFaderIndex, (node.contents as Model.Parameter).value as boolean ) ) - global.mainThreadHandler.updatePartialStore( - channel.assignedFader - ) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) } ) } diff --git a/server/src/utils/mixerConnections/LawoRubyConnection.ts b/server/src/utils/mixerConnections/LawoRubyConnection.ts index 61574a43..12ac9ff8 100644 --- a/server/src/utils/mixerConnections/LawoRubyConnection.ts +++ b/server/src/utils/mixerConnections/LawoRubyConnection.ts @@ -15,10 +15,12 @@ import { storeSetAMix, storeCapability, storeShowChannel, + storeSetPgm, } from '../../../../shared/src/actions/faderActions' import { logger } from '../logger' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' import { storeSetChLabel } from '../../../../shared/src/actions/channelActions' +import { EmberElement, NumberedTreeNode } from 'emberplus-connection/dist/model' // TODO - should these be util functions? export function floatToDB(f: number): number { @@ -122,7 +124,9 @@ export class LawoRubyMixerConnection { 'Ruby.Sources' ) // get the sources - const req = await this.emberConnection.getDirectory(sourceNode) + const req = await this.emberConnection.getDirectory( + sourceNode as NumberedTreeNode + ) const sources = await req.response // map sourceNames to their fader number @@ -251,36 +255,40 @@ export class LawoRubyMixerConnection { if (node.contents.type !== Model.ElementType.Parameter) return logger.debug(`Subscription of channel level: ${command}`) - this.emberConnection.subscribe(node, () => { - logger.trace(`Receiving Level from Ch ${ch}`) - if ( - !state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].fadeActive && - ((node.contents as Model.Parameter).value as number) > - this.mixerProtocol.channelTypes[typeIndex].fromMixer - .CHANNEL_OUT_GAIN[0].min - ) { - store.dispatch( - storeFaderLevel( - ch - 1, - dbToFloat( - (node.contents as Model.Parameter) - .value as number - ) - ) + this.emberConnection.subscribe( + node as NumberedTreeNode, + () => { + const levelInDecibel: number = ( + node.contents as Model.Parameter + ).value as number + logger.trace( + `Receiving Level from Ch ${ch}: ${levelInDecibel}` ) - global.mainThreadHandler.updatePartialStore(ch - 1) - if (remoteConnections) { - remoteConnections.updateRemoteFaderState( - ch - 1, - dbToFloat( - (node.contents as Model.Parameter) - .value as number + if ( + !state.channels[0].chMixerConnection[this.mixerIndex] + .channel[ch - 1].fadeActive && + levelInDecibel >= + this.mixerProtocol.channelTypes[typeIndex].fromMixer + .CHANNEL_OUT_GAIN[0].min + ) { + // update the fader + const level = dbToFloat(levelInDecibel) + store.dispatch(storeFaderLevel(ch - 1, level)) + + // toggle pgm based on level + logger.trace(`Set Channel ${ch} pgmOn ${level > 0}`) + store.dispatch(storeSetPgm(ch - 1, level > 0)) + + global.mainThreadHandler.updatePartialStore(ch - 1) + if (remoteConnections) { + remoteConnections.updateRemoteFaderState( + ch - 1, + level ) - ) + } } } - }) + ) } catch (e) { logger.data(e).debug('error when subscribing to fader level') } @@ -303,18 +311,22 @@ export class LawoRubyMixerConnection { if (node.contents.type !== Model.ElementType.Parameter) return logger.debug(`Subscription of channel gain: ${command}`) - this.emberConnection.subscribe(node, () => { - logger.trace(`Receiving Gain from Ch ${ch}`) - const value = (node.contents as Model.Parameter).value as number - const level = (value - proto.min) / (proto.max - proto.min) - if ( - ((node.contents as Model.Parameter).value as number) > - proto.min - ) { - store.dispatch(storeInputGain(ch - 1, level)) - global.mainThreadHandler.updatePartialStore(ch - 1) + this.emberConnection.subscribe( + node as NumberedTreeNode, + () => { + logger.trace(`Receiving Gain from Ch ${ch}`) + const value = (node.contents as Model.Parameter) + .value as number + const level = (value - proto.min) / (proto.max - proto.min) + if ( + ((node.contents as Model.Parameter).value as number) > + proto.min + ) { + store.dispatch(storeInputGain(ch - 1, level)) + global.mainThreadHandler.updatePartialStore(ch - 1) + } } - }) + ) } catch (e) { logger.data(e).debug('Error when subscribing to gain level') } @@ -343,24 +355,31 @@ export class LawoRubyMixerConnection { } logger.debug(`Subscription of channel input selector: ${command}`) - this.emberConnection.subscribe(node, () => { - logger.trace(`Receiving InpSelector from Ch ${ch}`) - this.mixerProtocol.channelTypes[ - typeIndex - ].fromMixer.CHANNEL_INPUT_SELECTOR.forEach((selector, i) => { - if ( - selector.value === - (node.contents as Model.Parameter).value - ) { - store.dispatch({ - type: SET_INPUT_SELECTOR, - channel: ch - 1, - selected: i + 1, - }) - global.mainThreadHandler.updatePartialStore(ch - 1) - } - }) - }) + this.emberConnection.subscribe( + node as NumberedTreeNode, + () => { + logger.trace(`Receiving InpSelector from Ch ${ch}`) + this.mixerProtocol.channelTypes[ + typeIndex + ].fromMixer.CHANNEL_INPUT_SELECTOR.forEach( + (selector, i) => { + if ( + selector.value === + (node.contents as Model.Parameter).value + ) { + store.dispatch({ + type: SET_INPUT_SELECTOR, + channel: ch - 1, + selected: i + 1, + }) + global.mainThreadHandler.updatePartialStore( + ch - 1 + ) + } + } + ) + } + ) } catch (e) { if (e.message.match(/could not find node/i)) { logger.debug(`set_cap ${ch} hasInputSel false`) @@ -395,16 +414,19 @@ export class LawoRubyMixerConnection { } logger.debug(`Subscription of AMix state: ${command}`) - this.emberConnection.subscribe(node, () => { - logger.trace(`Receiving AMix state from Ch ${ch}`) - store.dispatch( - storeSetAMix( - ch - 1, - (node.contents as Model.Parameter).value === 1 + this.emberConnection.subscribe( + node as NumberedTreeNode, + () => { + logger.trace(`Receiving AMix state from Ch ${ch}`) + store.dispatch( + storeSetAMix( + ch - 1, + (node.contents as Model.Parameter).value === true + ) ) - ) - global.mainThreadHandler.updatePartialStore(ch - 1) - }) + global.mainThreadHandler.updatePartialStore(ch - 1) + } + ) } catch (e) { if (e.message.match(/could not find node/i)) { logger.debug(`set_cap ${ch - 1} hasAMix false`) diff --git a/server/src/utils/mixerConnections/MidiMixerConnection.ts b/server/src/utils/mixerConnections/MidiMixerConnection.ts index d6e896c7..4627cb3d 100644 --- a/server/src/utils/mixerConnections/MidiMixerConnection.ts +++ b/server/src/utils/mixerConnections/MidiMixerConnection.ts @@ -14,6 +14,7 @@ import { import { storeSetOutputLevel } from '../../../../shared/src/actions/channelActions' import { storeFaderLevel, storeTogglePgm } from '../../../../shared/src/actions/faderActions' import { logger } from '../logger' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' export class MidiMixerConnection { store: any @@ -34,14 +35,12 @@ export class MidiMixerConnection { logger.data(err).error('WebMidi could not be enabled.') } logger.info( - `Connecting Mixer Midi input on port: ${ - state.settings[0].mixers[this.mixerIndex].mixerMidiInputPort + `Connecting Mixer Midi input on port: ${state.settings[0].mixers[this.mixerIndex].mixerMidiInputPort }` ) logger.info( - `Connecting Mixer Midi output on port: ${ - state.settings[0].mixers[this.mixerIndex] - .mixerMidiOutputPort + `Connecting Mixer Midi output on port: ${state.settings[0].mixers[this.mixerIndex] + .mixerMidiOutputPort }` ) this.midiInput = WebMidi.getInputByName( @@ -55,21 +54,29 @@ export class MidiMixerConnection { }) } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + setupMixerConnection() { this.midiInput.addListener('controlchange', 1, (message: any) => { logger.debug(`Received 'controlchange' message (${message.data}).`) if ( message.data[1] >= - parseInt( - this.mixerProtocol.channelTypes[0].fromMixer - .CHANNEL_OUT_GAIN[0].mixerMessage - ) && + 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 + parseInt( + this.mixerProtocol.channelTypes[0].fromMixer + .CHANNEL_OUT_GAIN[0].mixerMessage + ) + + 24 ) { let ch = 1 + @@ -78,18 +85,14 @@ export class MidiMixerConnection { this.mixerProtocol.channelTypes[0].fromMixer .CHANNEL_OUT_GAIN[0].mixerMessage ) - let faderChannel = - 1 + - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + let faderChannel = this.getAssignedFaderIndex(ch - 1) + 1 store.dispatch( storeFaderLevel(faderChannel - 1, message.data[2]) ) if (!state.faders[0].fader[faderChannel - 1].pgmOn) { store.dispatch( storeTogglePgm( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader - 1 + faderChannel - 1, ) ) } @@ -100,13 +103,13 @@ export class MidiMixerConnection { ) } if (state.faders[0].fader[faderChannel - 1].pgmOn) { - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach((channel: any, index: number) => { - if (channel.assignedFader === faderChannel - 1) { - this.updateOutLevel(index) + state.faders[0].fader[faderChannel - 1].assignedChannels?.forEach( + (channel: IChannelReference) => { + if (channel.mixerIndex === this.mixerIndex) { + this.updateOutLevel(channel.channelIndex, faderChannel - 1) + } } - }) + ) } } }) @@ -137,11 +140,7 @@ export class MidiMixerConnection { } } - updateOutLevel(channelIndex: number) { - let faderIndex = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelIndex - ].assignedFader + updateOutLevel(channelIndex: number, faderIndex: number) { if (state.faders[0].fader[faderIndex].pgmOn) { store.dispatch( storeSetOutputLevel( @@ -229,7 +228,7 @@ export class MidiMixerConnection { ) } - loadMixerPreset(presetName: string) {} + loadMixerPreset(presetName: string) { } injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/OscMixerConnection.ts b/server/src/utils/mixerConnections/OscMixerConnection.ts index b6613fb6..c87ea7e0 100644 --- a/server/src/utils/mixerConnections/OscMixerConnection.ts +++ b/server/src/utils/mixerConnections/OscMixerConnection.ts @@ -28,6 +28,8 @@ import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActi import { logger } from '../logger' import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' +import { IChannel } from '../../../../shared/src/reducers/channelsReducer' interface IOscCommand { address: string @@ -63,16 +65,27 @@ export class OscMixerConnection { .split('/') .findIndex((ch) => ch === '{channel}') - this.oscConnection = new osc.UDPPort({ - localAddress: state.settings[0].mixers[this.mixerIndex].localIp, - localPort: parseInt( - state.settings[0].mixers[this.mixerIndex].localOscPort + '' - ), - remoteAddress: state.settings[0].mixers[this.mixerIndex].deviceIp, - remotePort: parseInt( - state.settings[0].mixers[this.mixerIndex].devicePort + '' - ), - }) + try { + + this.oscConnection = new osc.UDPPort({ + localAddress: state.settings[0].mixers[this.mixerIndex].localIp, + localPort: parseInt( + state.settings[0].mixers[this.mixerIndex].localOscPort + '' + ), + remoteAddress: state.settings[0].mixers[this.mixerIndex].deviceIp, + remotePort: parseInt( + state.settings[0].mixers[this.mixerIndex].devicePort + '' + ), + }) + } + catch (error) { + logger.error( + `Error creating OSC connection to ${state.settings[0].mixers[this.mixerIndex].deviceIp}:${state.settings[0].mixers[this.mixerIndex].devicePort}` + ) + logger.error(error) + return + } + this.setupMixerConnection() } @@ -81,6 +94,14 @@ export class OscMixerConnection { global.mainThreadHandler.updateMixerOnline(this.mixerIndex, onLineState) } + private getAssignedFaderIndex(channelIndex: number): number { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + setupMixerConnection() { this.oscConnection .on('ready', () => { @@ -121,11 +142,11 @@ export class OscMixerConnection { this.resetMixerTimeout() midasMeter(this.mixerIndex, message.args) } else { + const assignedFaderIndex = this.getAssignedFaderIndex(message.address.split('/')[this.cmdChannelIndex]) let ch = message.address.split('/')[this.cmdChannelIndex] sendVuLevel( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, + assignedFaderIndex, VuType.Channel, 0, message.args[0] @@ -138,10 +159,10 @@ export class OscMixerConnection { .CHANNEL_VU_REDUCTION?.[0].mixerMessage ) ) { - let ch = message.address.split('/')[this.cmdChannelIndex] + const assignedFaderIndex = this.getAssignedFaderIndex(message.address.split('/')[this.cmdChannelIndex]) + sendVuLevel( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, + assignedFaderIndex, VuType.Reduction, 0, message.args[0] @@ -154,9 +175,7 @@ export class OscMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] - let assignedFaderIndex = - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) if ( assignedFaderIndex >= 0 && @@ -166,7 +185,7 @@ export class OscMixerConnection { if ( message.args[0] > this.mixerProtocol.fader.min || message.args[0] > - state.settings[0].autoResetLevel / 100 + state.settings[0].autoResetLevel / 100 ) { store.dispatch( storeFaderLevel( @@ -174,21 +193,13 @@ export class OscMixerConnection { message.args[0] ) ) - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach( - ( - item: { assignedFader: any }, - index: number - ) => { - if ( - item.assignedFader === - assignedFaderIndex - ) { + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + if (assignedChannel.mixerIndex === this.mixerIndex) { store.dispatch( storeSetOutputLevel( this.mixerIndex, - index, + assignedChannel.channelIndex, message.args[0] ) ) @@ -200,7 +211,7 @@ export class OscMixerConnection { ) { if ( message.args[0] > - this.mixerProtocol.fader.min || + this.mixerProtocol.fader.min || 0 ) { store.dispatch( @@ -218,21 +229,13 @@ export class OscMixerConnection { message.args[0] ) ) - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach( - ( - item: { assignedFader: any }, - index: number - ) => { - if ( - item.assignedFader === - assignedFaderIndex - ) { + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + if (assignedChannel.mixerIndex === this.mixerIndex) { store.dispatch( storeSetOutputLevel( this.mixerIndex, - index, + assignedChannel.channelIndex, message.args[0] ) ) @@ -315,8 +318,7 @@ export class OscMixerConnection { ) ) global.mainThreadHandler.updatePartialStore( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + this.getAssignedFaderIndex(ch - 1) ) } else if ( this.checkOscCommand( @@ -326,21 +328,19 @@ export class OscMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) store.dispatch( storeSetMute( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, + assignedFaderIndex, message.args[0] === 0 ) ) mixerGenericConnection.updateMuteState( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, + assignedFaderIndex, this.mixerIndex ) global.mainThreadHandler.updatePartialStore( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + assignedFaderIndex ) } else { this.checkFxCommands(message) @@ -358,8 +358,7 @@ export class OscMixerConnection { this.oscConnection.open() logger.info( - `OSC listening on port ${ - state.settings[0].mixers[this.mixerIndex].localOscPort + `OSC listening on port ${state.settings[0].mixers[this.mixerIndex].localOscPort }` ) @@ -388,29 +387,23 @@ export class OscMixerConnection { if (item.type !== undefined && item.type === 'aux') { state.channels[0].chMixerConnection[ this.mixerIndex - ].channel.forEach((channel: any) => { - channel.auxLevel.forEach( - (auxLevel: any, auxIndex: number) => { - if (channel.assignedFader >= 0) { - if ( - state.faders[0].fader[ - channel.assignedFader - ] - ) { - setTimeout(() => { - this.sendOutRequestAux( - item.mixerMessage, - auxIndex + 1, - state.faders[0].fader[ - channel - .assignedFader - ].monitor - ) - }, state.faders[0].fader[channel.assignedFader].monitor * 10 + auxIndex * 100) - } + ].channel.forEach((channel: IChannel, index: number) => { + const assignedFaderIndex = this.getAssignedFaderIndex(index) + if (assignedFaderIndex >= 0) { + channel.auxLevel.forEach( + (auxLevel: any, auxIndex: number) => { + setTimeout(() => { + this.sendOutRequestAux( + item.mixerMessage, + auxIndex + 1, + state.faders[0].fader[ + assignedFaderIndex + ].monitor + ) + }, state.faders[0].fader[assignedFaderIndex].monitor * 10 + auxIndex * 100) } - } - ) + ) + } }) } else { state.channels[0].chMixerConnection[ @@ -467,24 +460,24 @@ export class OscMixerConnection { let fxKey = keyName as keyof typeof fxParamsList let fxMessage = this.mixerProtocol.channelTypes[0].fromMixer[ - fxParamsList[fxKey] + fxParamsList[fxKey] ][0] let range: number = fxMessage.max - fxMessage.min || 1 if (this.checkOscCommand(message.address, fxMessage.mixerMessage)) { - let ch = message.address.split('/')[this.cmdChannelIndex] - - store.dispatch( - storeFaderFx( - fxParamsList[fxKey], - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, - message.args[0] / range + const ch = message.address.split('/')[this.cmdChannelIndex] + const assignedFaderIndex = this.getAssignedFaderIndex(ch - 1) + if (assignedFaderIndex >= 0) { + store.dispatch( + storeFaderFx( + fxParamsList[fxKey], + assignedFaderIndex, + message.args[0] / range + ) ) - ) - global.mainThreadHandler.updatePartialStore( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader - ) + global.mainThreadHandler.updatePartialStore( + assignedFaderIndex + ) + } } logger.trace(fxKey) @@ -598,7 +591,7 @@ export class OscMixerConnection { state.channels[0].chMixerConnection[this.mixerIndex].channel[ channelIndex ].channelTypeIndex - if (state.faders[0].fader[channelIndex].pflOn === true) { + if (state.faders[0].fader[channelIndex].pflOn === true && this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON) { this.sendOutMessage( this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] .mixerMessage, @@ -608,7 +601,7 @@ export class OscMixerConnection { this.mixerProtocol.channelTypes[channelType].toMixer.PFL_ON[0] .type ) - } else { + } else if (state.faders[0].fader[channelIndex].pflOn === false && this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF) { this.sendOutMessage( this.mixerProtocol.channelTypes[channelType].toMixer.PFL_OFF[0] .mixerMessage, diff --git a/server/src/utils/mixerConnections/SSLMixerConnection.ts b/server/src/utils/mixerConnections/SSLMixerConnection.ts index eeb1de6d..fd86b375 100644 --- a/server/src/utils/mixerConnections/SSLMixerConnection.ts +++ b/server/src/utils/mixerConnections/SSLMixerConnection.ts @@ -16,6 +16,7 @@ import { } from '../../../../shared/src/actions/faderActions' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' import { logger } from '../logger' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' export class SSLMixerConnection { mixerProtocol: IMixerProtocol @@ -57,61 +58,70 @@ export class SSLMixerConnection { return str.substring(1) } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + handleReceivedFaderLevelCommand = (buffer: any) => { try { let channelIndex = buffer[6] let value = buffer.readUInt16BE(7) / 1024 - const ch = state.channels[0].chMixerConnection[this.mixerIndex].channel + const thisMixerChannels = state.channels[0].chMixerConnection[this.mixerIndex].channel + const assignedFaderIndex = this.getAssignedFaderIndex(channelIndex) if ( - !ch[channelIndex].fadeActive + !thisMixerChannels[channelIndex].fadeActive ) { if ( value > this.mixerProtocol.fader.min + - (this.mixerProtocol.fader.max * - state.settings[0].autoResetLevel) / - 100 + (this.mixerProtocol.fader.max * + state.settings[0].autoResetLevel) / + 100 ) { if ( - ch[channelIndex].outputLevel !== value + thisMixerChannels[channelIndex].outputLevel !== value + ) { store.dispatch( - storeFaderLevel(ch[channelIndex].assignedFader, value) + storeFaderLevel(assignedFaderIndex, value) ) - if (!state.faders[0].fader[ch[channelIndex].assignedFader].pgmOn) { - store.dispatch(storeTogglePgm(ch[channelIndex].assignedFader)) + if (!state.faders[0].fader[assignedFaderIndex].pgmOn) { + store.dispatch(storeTogglePgm(assignedFaderIndex)) } if (remoteConnections) { remoteConnections.updateRemoteFaderState( - ch[channelIndex].assignedFader, + assignedFaderIndex, value ) } - if (state.faders[0].fader[ch[channelIndex].assignedFader].pgmOn) { - ch.forEach((channel: any, index: number) => { - if ( - channel.assignedFader === ch[channelIndex].assignedFader - ) { - this.updateOutLevel(index) - + if (state.faders[0].fader[assignedFaderIndex].pgmOn) { + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (item: IChannelReference) => { + if (item.mixerIndex === this.mixerIndex) { + this.updateOutLevel(item.channelIndex) + } } - }) + ) } } } else if ( - state.faders[0].fader[ch[channelIndex].assignedFader].pgmOn || - state.faders[0].fader[ch[channelIndex].assignedFader].voOn + state.faders[0].fader[assignedFaderIndex].pgmOn || + state.faders[0].fader[assignedFaderIndex].voOn ) { - store.dispatch(storeFaderLevel(ch[channelIndex].assignedFader, value)) - ch.forEach( - (item: { assignedFader: any }, index: number) => { - if (item.assignedFader === ch[channelIndex].assignedFader) { + store.dispatch(storeFaderLevel(assignedFaderIndex, value)) + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (item: IChannelReference) => { + if (item.mixerIndex === this.mixerIndex) { store.dispatch( storeSetOutputLevel( this.mixerIndex, - index, + item.channelIndex, value ) ) @@ -119,8 +129,8 @@ export class SSLMixerConnection { } ) } - global.mainThreadHandler.updatePartialStore(ch[channelIndex].assignedFader) - mixerGenericConnection.updateOutLevel(ch[channelIndex].assignedFader, 0, this.mixerIndex) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) + mixerGenericConnection.updateOutLevel(assignedFaderIndex, 0, this.mixerIndex) } } catch (error) { logger.error( @@ -134,6 +144,7 @@ export class SSLMixerConnection { // MUTE ON/OFF COMMAND let commandHex = buffer.toString('hex') let channelIndex = buffer[6] + const assignedFaderIndex = this.getAssignedFaderIndex(channelIndex) let value: boolean = buffer[7] === 0 ? true : false logger.trace( `Receive Buffer Channel On/off: ${this.formatHexWithSpaces( @@ -143,11 +154,6 @@ export class SSLMixerConnection { )}` ) - let assignedFaderIndex = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelIndex - ].assignedFader - store.dispatch(storeSetMute(assignedFaderIndex, value)) if (remoteConnections) { @@ -156,16 +162,11 @@ export class SSLMixerConnection { value ? 1 : 0 ) } - state.channels[0].chMixerConnection[this.mixerIndex].channel.forEach( - (channel: any, index: number) => { - if ( - channel.assignedFader === assignedFaderIndex && - index !== channelIndex - ) { - this.updateMuteState( - index, - state.faders[0].fader[assignedFaderIndex].muteOn - ) + + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (item: IChannelReference) => { + if (item.mixerIndex === this.mixerIndex && item.channelIndex !== channelIndex) { + this.updateMuteState(item.channelIndex, value) } } ) @@ -258,7 +259,6 @@ export class SSLMixerConnection { this.mixerProtocol.pingCommand.forEach((command) => { this.sendOutPingRequest() }) - global.mainThreadHandler.updateFullClientStore() this.mixerOnlineTimer = setTimeout(() => { store.dispatch(storeSetMixerOnline(this.mixerIndex, false)) }, this.mixerProtocol.pingTime) @@ -326,15 +326,15 @@ export class SSLMixerConnection { sslMessage = sslMessage.replace( '{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + - ' ' + - ('0' + channelByte[1].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) + - ' ' + ' ' + + ('0' + valueByte[1].toString(16)).slice(-2) + + ' ' ) sslMessage = sslMessage + this.calculate_checksum8(sslMessage.slice(9)) let a = sslMessage.split(' ') @@ -357,8 +357,8 @@ export class SSLMixerConnection { sslMessage = sslMessage.replace( '{channel}', ('0' + channelByte[0].toString(16)).slice(-2) + - ' ' + - ('0' + channelByte[1].toString(16)).slice(-2) + ' ' + + ('0' + channelByte[1].toString(16)).slice(-2) ) sslMessage = sslMessage + ' ' + this.calculate_checksum8(sslMessage.slice(9)) @@ -397,10 +397,8 @@ export class SSLMixerConnection { state.channels[0].chMixerConnection[this.mixerIndex].channel[ channelIndex ].channelTypeIndex - let faderIndex = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelIndex - ].assignedFader + const faderIndex = this.getAssignedFaderIndex(channelIndex) + if (state.faders[0].fader[faderIndex].pgmOn) { store.dispatch( storeSetOutputLevel( @@ -511,7 +509,7 @@ export class SSLMixerConnection { return true } - loadMixerPreset(presetName: string) {} + loadMixerPreset(presetName: string) { } injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts b/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts index 7c98544e..ce7a1795 100644 --- a/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts +++ b/server/src/utils/mixerConnections/StuderVistaMixerConnection.ts @@ -20,7 +20,7 @@ import { storeSetOutputLevel, } from '../../../../shared/src/actions/channelActions' import { remoteConnections } from '../../mainClasses' -import { IFader } from '../../../../shared/src/reducers/fadersReducer' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' import { IChannel } from '../../../../shared/src/reducers/channelsReducer' export class StuderVistaMixerConnection { @@ -50,7 +50,7 @@ export class StuderVistaMixerConnection { host: state.settings[0].mixers[this.mixerIndex].deviceIp, timeout: 1000, }, - () => {} + () => { } ) this.mixerConnection @@ -138,6 +138,14 @@ export class StuderVistaMixerConnection { return channelArrayIndex } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + checkEmberCommand(message: string, protocolMessage: string): boolean { let messageArray = message.split('31 ') if (messageArray.length > 2) { @@ -182,10 +190,7 @@ export class StuderVistaMixerConnection { channelType, channelTypeIndex ) - let assignedFader = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelArrayIndex - ].assignedFader + let assignedFaderIndex = this.getAssignedFaderIndex(channelArrayIndex) if ( state.channels[0].chMixerConnection[this.mixerIndex].channel[ @@ -197,26 +202,30 @@ export class StuderVistaMixerConnection { if ( value > state.settings[0].autoResetLevel / 100 || - state.faders[0].fader[assignedFader].pgmOn || - state.faders[0].fader[assignedFader].voOn + state.faders[0].fader[assignedFaderIndex].pgmOn || + state.faders[0].fader[assignedFaderIndex].voOn ) { - store.dispatch(storeFaderLevel(assignedFader, value)) - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach((item: { assignedFader: any }, index: number) => { - if (item.assignedFader === assignedFader) { - store.dispatch( - storeSetOutputLevel(this.mixerIndex, index, value) - ) + store.dispatch(storeFaderLevel(assignedFaderIndex, value)) + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (assignedChannel: IChannelReference) => { + if ( + assignedChannel.mixerIndex === this.mixerIndex && + assignedChannel.channelIndex !== channelArrayIndex + ) { + store.dispatch( + storeSetOutputLevel(this.mixerIndex, assignedChannel.channelIndex, value) + ) + } } - }) - if (!state.faders[0].fader[assignedFader].pgmOn) { + ) + + if (!state.faders[0].fader[assignedFaderIndex].pgmOn) { if (value > 0) { - store.dispatch(storeTogglePgm(assignedFader)) + store.dispatch(storeTogglePgm(assignedFaderIndex)) } } - global.mainThreadHandler.updatePartialStore(assignedFader) - remoteConnections.updateRemoteFaderState(assignedFader, value) + global.mainThreadHandler.updatePartialStore(assignedFaderIndex) + remoteConnections.updateRemoteFaderState(assignedFaderIndex, value) } } @@ -272,10 +281,7 @@ export class StuderVistaMixerConnection { : false // Update store: - let assignedFader = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - this.findChannelInArray(channelType, channelTypeIndex) - ].assignedFader + let assignedFader = this.getAssignedFaderIndex(this.findChannelInArray(channelType, channelTypeIndex)) store.dispatch(storeSetMute(assignedFader, mute)) global.mainThreadHandler.updatePartialStore(assignedFader) @@ -366,10 +372,11 @@ export class StuderVistaMixerConnection { pingChannel(mixerMessage: string) { state.faders[0].fader.forEach((fader: IFader, index: number) => { - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach((channel: IChannel) => { - if (channel.assignedFader === index) { + fader.assignedChannels?.forEach((channelReference: IChannelReference) => { + if (channelReference.mixerIndex === this.mixerIndex) { + const channel = state.channels[0].chMixerConnection[ + this.mixerIndex + ].channel[channelReference.channelIndex] let message = mixerMessage .replace( '{ch-type}', @@ -627,7 +634,7 @@ export class StuderVistaMixerConnection { return } - loadMixerPreset(presetName: string) {} + loadMixerPreset(presetName: string) { } injectCommand(command: string[]) { return true diff --git a/server/src/utils/mixerConnections/VMixMixerConnection.ts b/server/src/utils/mixerConnections/VMixMixerConnection.ts index f26463ef..3078d293 100644 --- a/server/src/utils/mixerConnections/VMixMixerConnection.ts +++ b/server/src/utils/mixerConnections/VMixMixerConnection.ts @@ -23,6 +23,7 @@ import { logger } from '../logger' import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' import { dbToFloat } from './LawoRubyConnection' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' export class VMixMixerConnection { mixerProtocol: IMixerProtocol @@ -32,6 +33,9 @@ export class VMixMixerConnection { vmixVuConnection: ConnectionTCP mixerOnlineTimer: any + audioOn: Record = {} + lastLevel: Record = {} + constructor(mixerProtocol: IMixerProtocol, mixerIndex: number) { this.sendOutMessage = this.sendOutMessage.bind(this) this.pingMixerCommand = this.pingMixerCommand.bind(this) @@ -58,6 +62,7 @@ export class VMixMixerConnection { port: parseInt( state.settings[0].mixers[this.mixerIndex].devicePort + '' ), + debug: true, } ) this.vmixVuConnection = new ConnectionTCP( @@ -76,6 +81,14 @@ export class VMixMixerConnection { global.mainThreadHandler.updateMixerOnline(this.mixerIndex, onLineState) } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + setupMixerConnection() { this.vmixConnection._socket .on('connect', () => { @@ -151,6 +164,12 @@ export class VMixMixerConnection { }) mappedInputs.forEach((input) => { + if ( + !state.channels[0].chMixerConnection[this.mixerIndex] + .channel[input.number - 1] + ) + return + if ('number' in input) { sendVuLevel( input.number - 1, @@ -172,11 +191,15 @@ export class VMixMixerConnection { return } - const { outputLevel, fadeActive, assignedFader } = + const { outputLevel, fadeActive } = state.channels[0].chMixerConnection[this.mixerIndex] .channel[input.number - 1] + const assignedFaderIndex = this.getAssignedFaderIndex(input.number - 1) + if (!state.faders[0].fader[assignedFaderIndex]) { + return + } const { inputGain, muteOn, pflOn, pgmOn, voOn } = - state.faders[0].fader[assignedFader] + state.faders[0].fader[assignedFaderIndex] let sendUpdate = false const dispatch = (update: any) => { store.dispatch(update) @@ -191,11 +214,11 @@ export class VMixMixerConnection { Math.abs(outputLevel - input.volume) > 0.01 ) { dispatch( - storeFaderLevel(assignedFader, input.volume) + storeFaderLevel(assignedFaderIndex, input.volume) ) store.dispatch({ type: SET_OUTPUT_LEVEL, - channel: assignedFader, + channel: assignedFaderIndex, mixerIndex: this.mixerIndex, level: voOn ? input.volume / @@ -204,31 +227,31 @@ export class VMixMixerConnection { }) } if (muteOn) { - dispatch(storeSetMute(assignedFader, false)) + dispatch(storeSetMute(assignedFaderIndex, false)) } if (!fadeActive && !pgmOn && !voOn) { - dispatch(storeSetPgm(assignedFader, true)) + dispatch(storeSetPgm(assignedFaderIndex, true)) store.dispatch({ type: SET_OUTPUT_LEVEL, - channel: assignedFader, + channel: assignedFaderIndex, mixerIndex: this.mixerIndex, level: input.volume, }) } } else if (!muteOn) { if (pgmOn) { - dispatch(storeSetPgm(assignedFader, false)) + dispatch(storeSetPgm(assignedFaderIndex, false)) } if (voOn) { - dispatch(storeSetVo(assignedFader, false)) + dispatch(storeSetVo(assignedFaderIndex, false)) } } if (inputGain !== input.gainDb) { - dispatch(storeInputGain(assignedFader, input.gainDb)) + dispatch(storeInputGain(assignedFaderIndex, input.gainDb)) } if (pflOn !== input.solo) { - dispatch(storeSetPfl(assignedFader, input.solo)) + dispatch(storeSetPfl(assignedFaderIndex, input.solo)) } } @@ -336,17 +359,16 @@ export class VMixMixerConnection { ) ) { let ch = message.address.split('/')[this.cmdChannelIndex] + const assignedFaderIndex = this.getAssignedFaderIndex(ch-1) store.dispatch( storeFaderFx( fxParamsList[fxKey], - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader, + assignedFaderIndex, message.args[0] ) ) global.mainThreadHandler.updatePartialStore( - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + assignedFaderIndex ) } @@ -609,8 +631,8 @@ export class VMixMixerConnection { let { muteOn } = state.faders[0].fader[channelIndex] outputLevel = Math.round(100 * outputLevel) - if (!muteOn && outputLevel > 0) { - this.sendOutMessage('AudioOn', channelTypeIndex + 1, 1, '') + if (this.lastLevel[channelIndex] === outputLevel) { + return } this.sendOutMessage( @@ -620,10 +642,22 @@ export class VMixMixerConnection { String(outputLevel), 'f' ) + this.lastLevel[channelIndex] = outputLevel - if (outputLevel <= 1) { + if (!muteOn && outputLevel > 0 && !this.audioOn[channelIndex]) { + this.sendOutMessage('AudioOn', channelTypeIndex + 1, 1, '') + this.audioOn[channelIndex] = true + } + + if (outputLevel < 1 && this.audioOn[channelIndex]) { this.sendOutMessage('AudioOff', channelTypeIndex + 1, 1, '') - this.sendOutMessage('SetVolume', channelTypeIndex + 1, 75, '') + // audio off command is a bit slow... + setTimeout(() => { + console.log('turn off') + this.sendOutMessage('SetVolume', channelTypeIndex + 1, 75, '') + }, 80) + // this.sendOutMessage('SetVolume', channelTypeIndex + 1, 75, '') + this.audioOn[channelIndex] = false } } diff --git a/server/src/utils/mixerConnections/YamahaQlClConnection.ts b/server/src/utils/mixerConnections/YamahaQlClConnection.ts index f149d467..cff345ee 100644 --- a/server/src/utils/mixerConnections/YamahaQlClConnection.ts +++ b/server/src/utils/mixerConnections/YamahaQlClConnection.ts @@ -18,6 +18,7 @@ import { logger } from '../logger' import { storeSetMixerOnline } from '../../../../shared/src/actions/settingsActions' import { sendVuLevel } from '../vuServer' import { VuType } from '../../../../shared/src/utils/vu-server-types' +import { IChannelReference, IFader } from '../../../../shared/src/reducers/fadersReducer' export class QlClMixerConnection { mixerProtocol: IMixerProtocol @@ -109,8 +110,7 @@ export class QlClMixerConnection { let ch = parseInt(mixerValues[3]) let assignedFader = 1 + - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + this.getAssignedFaderIndex(ch - 1) let mixerValue = parseInt(mixerValues[6]) sendVuLevel( assignedFader, @@ -127,9 +127,7 @@ export class QlClMixerConnection { ) { let ch = 1 + (message[11] | (message[10] << 8)) let assignedFader = - 1 + - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[ch - 1].assignedFader + 1 + this.getAssignedFaderIndex(ch - 1) let mixerLevel: number = message[16] | (message[15] << 8) // parseFloat(message[16]) let faderLevel = Math.pow(2, mixerLevel / 1920) - 1 @@ -160,15 +158,10 @@ export class QlClMixerConnection { if ( state.faders[0].fader[assignedFader - 1].pgmOn ) { - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach( - (channel: any, index: number) => { - if ( - channel.assignedFader === - assignedFader - 1 - ) { - this.updateOutLevel(index) + state.faders[0].fader[assignedFader - 1].assignedChannels?.forEach( + (ch: IChannelReference) => { + if (ch.mixerIndex === this.mixerIndex) { + this.updateOutLevel(ch.channelIndex) } } ) @@ -189,14 +182,11 @@ export class QlClMixerConnection { let value: boolean = message[16] === 0 ? true : false logger.trace( - `Receive Buffer Channel On/off - Channel ${ - channelIndex + 1 + `Receive Buffer Channel On/off - Channel ${channelIndex + 1 } Val :${message[16]}` ) - let assignedFaderIndex = - state.channels[0].chMixerConnection[this.mixerIndex] - .channel[channelIndex].assignedFader + let assignedFaderIndex = this.getAssignedFaderIndex(channelIndex) store.dispatch(storeSetMute(assignedFaderIndex, value)) @@ -206,20 +196,14 @@ export class QlClMixerConnection { value ? 1 : 0 ) } - state.channels[0].chMixerConnection[ - this.mixerIndex - ].channel.forEach((channel: any, index: number) => { - if ( - channel.assignedFader === assignedFaderIndex && - index !== channelIndex - ) { - this.updateMuteState( - index, - state.faders[0].fader[assignedFaderIndex] - .muteOn - ) + state.faders[0].fader[assignedFaderIndex].assignedChannels?.forEach( + (ch: IChannelReference) => { + if (ch.mixerIndex === this.mixerIndex) { + this.updateMuteState(ch.channelIndex, state.faders[0].fader[assignedFaderIndex] + .muteOn) + } } - }) + ) global.mainThreadHandler.updatePartialStore( assignedFaderIndex ) @@ -244,6 +228,14 @@ export class QlClMixerConnection { }, this.mixerProtocol.pingTime) } + private getAssignedFaderIndex(channelIndex: number) { + return state.faders[0].fader.findIndex( + (fader: IFader) => fader.assignedChannels?.some((assigned: IChannelReference) => { + return (assigned.mixerIndex === this.mixerIndex && assigned.channelIndex === channelIndex) + }) + ) + } + checkMidiCommand(midiMessage: number[], command: string) { if (!midiMessage) return false let commandArray = command.split(' ') @@ -312,10 +304,7 @@ export class QlClMixerConnection { state.channels[0].chMixerConnection[this.mixerIndex].channel[ channelIndex ].channelTypeIndex - let faderIndex = - state.channels[0].chMixerConnection[this.mixerIndex].channel[ - channelIndex - ].assignedFader + let faderIndex = this.getAssignedFaderIndex(channelIndex) if (state.faders[0].fader[faderIndex].pgmOn) { store.dispatch( storeSetOutputLevel( @@ -451,7 +440,7 @@ export class QlClMixerConnection { ) } - loadMixerPreset(presetName: string) {} + loadMixerPreset(presetName: string) { } injectCommand(command: string[]) { return true diff --git a/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts b/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts index 00ee4a13..29ca4967 100644 --- a/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts +++ b/server/src/utils/remoteConnections/SkaarhojRemoteConnection.ts @@ -95,8 +95,8 @@ export class SkaarhojRemoteConnection { ) let event = command.slice(command.indexOf('=') + 1) if (btnNumber <= state.faders[0].fader.length) { - let channelIndex = btnNumber - 1 - let level = state.faders[0].fader[channelIndex].faderLevel + let faderIndex = btnNumber - 1 + let level = state.faders[0].fader[faderIndex].faderLevel if (event === 'Enc:1') { level += 0.01 if (level > 1) { @@ -119,11 +119,11 @@ export class SkaarhojRemoteConnection { } } //Fader changed: - logger.debug(`Received Fader ${channelIndex + 1} Level : ${level}`) - store.dispatch(storeFaderLevel(channelIndex, level)) - mixerGenericConnection.updateOutLevel(channelIndex, -1) - global.mainThreadHandler.updatePartialStore(channelIndex) - this.updateRemoteFaderState(channelIndex, level) + logger.debug(`Received Fader ${faderIndex + 1} Level : ${level}`) + store.dispatch(storeFaderLevel(faderIndex, level)) + mixerGenericConnection.updateOutLevel(faderIndex, -1) + global.mainThreadHandler.updatePartialStore(faderIndex) + this.updateRemoteFaderState(faderIndex, level) } else if (btnNumber > 80) { this.handleAuxLevelCommand(command, btnNumber) } diff --git a/shared/src/constants/SOCKET_IO_DISPATCHERS.ts b/shared/src/constants/SOCKET_IO_DISPATCHERS.ts index aabd9851..711dd484 100644 --- a/shared/src/constants/SOCKET_IO_DISPATCHERS.ts +++ b/shared/src/constants/SOCKET_IO_DISPATCHERS.ts @@ -4,12 +4,13 @@ export const SOCKET_SET_FADERLEVEL = 'FaderLevel' export const SOCKET_SET_INPUT_GAIN = 'InputGain' export const SOCKET_SET_INPUT_SELECTOR = 'InputSelector' -export const SOCKET_SET_ASSIGNED_FADER = 'setAssignedFader' +export const SOCKET_ASSIGN_CH_TO_FADER = 'assignChToFader' +export const SOCKET_REMOVE_ALL_CH_ASSIGNMENTS = 'removeAllChAssignments' export const SOCKET_SET_FADER_MONITOR = 'FaderMonitor' export const SOCKET_SHOW_IN_MINI_MONITOR = 'showInMiniMonitor' export const SOCKET_SET_AUX_LEVEL = 'setAuxLevel' export const SOCKET_SET_INPUT_OPTION = 'setInputOption' -export const SOCKET_SET_FX = 'setHigh' +export const SOCKET_SET_FX = 'setFx' export const SOCKET_TOGGLE_PGM = 'togglePgm' export const SOCKET_TOGGLE_VO = 'toggleVo' export const SOCKET_TOGGLE_SLOW_FADE = 'toggleSlowFade' diff --git a/shared/src/reducers/channelsReducer.ts b/shared/src/reducers/channelsReducer.ts index 60984bb3..d0e13db8 100644 --- a/shared/src/reducers/channelsReducer.ts +++ b/shared/src/reducers/channelsReducer.ts @@ -12,13 +12,13 @@ import { export interface IChannels { chMixerConnection: IchMixerConnection[] - } - - export interface IchMixerConnection { +} + +export interface IchMixerConnection { channel: Array - } - - export interface IChannel { +} + +export interface IChannel { channelType: number channelTypeIndex: number assignedFader: number @@ -29,11 +29,11 @@ export interface IChannels { private?: { [key: string]: string } - } - - export interface InumberOfChannels { +} + +export interface InumberOfChannels { numberOfTypeInCh: number[] - } +} const defaultChannelsReducerState = ( numberOfChannels: InumberOfChannels[] @@ -124,9 +124,11 @@ export const channels = ( ].fadeActive = !!action.active return nextState case SET_ASSIGNED_FADER: - nextState[0].chMixerConnection[action.mixerIndex].channel[ - action.channel - ].assignedFader = action.faderNumber + if (nextState[0].chMixerConnection[action.mixerIndex].channel.length > action.channel) { + nextState[0].chMixerConnection[action.mixerIndex].channel[ + action.channel + ].assignedFader = action.faderNumber + } return nextState case SET_AUX_LEVEL: let auxLevels = diff --git a/shared/src/reducers/fadersReducer.ts b/shared/src/reducers/fadersReducer.ts index 65fb3efa..ddb54e1d 100644 --- a/shared/src/reducers/fadersReducer.ts +++ b/shared/src/reducers/fadersReducer.ts @@ -285,9 +285,9 @@ export const faders = ( if (action.assigned) { if ( - !newAssignments.includes({ - mixerIndex: action.mixerIndex, - channelIndex: action.channelIndex, + !newAssignments.some((channel) => { + return (channel.mixerIndex === action.mixerIndex && + channel.channelIndex === action.channelIndex) }) ) { newAssignments.push({ @@ -304,10 +304,10 @@ export const faders = ( ) } } else { - newAssignments = newAssignments.filter((channel) => { - return ( - channel.channelIndex !== action.channelIndex && - channel.mixerIndex !== action.mixerIndex + newAssignments = newAssignments.filter((channel: IChannelReference) => { + return !( + channel.channelIndex === action.channelIndex && + channel.mixerIndex === action.mixerIndex ) }) } diff --git a/yarn.lock b/yarn.lock index 07cad9a0..ba78aa27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,12 +22,25 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" + integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== + dependencies: + "@babel/highlight" "^7.22.10" + chalk "^2.4.2" + "@babel/compat-data@^7.21.5": version "7.21.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.7.tgz#61caffb60776e49a57ba61a88f02bedd8714f6bc" integrity sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.21.8": +"@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": version "7.21.8" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.8.tgz#2a8c7f0f53d60100ba4c32470ba0281c92aa9aa4" integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== @@ -48,6 +61,27 @@ json5 "^2.2.2" semver "^6.3.0" +"@babel/core@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35" + integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.10" + "@babel/parser" "^7.22.10" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + "@babel/generator@^7.21.5", "@babel/generator@^7.7.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.5.tgz#c0c0e5449504c7b7de8236d99338c3e2a340745f" @@ -58,6 +92,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" + integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== + dependencies: + "@babel/types" "^7.22.10" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-compilation-targets@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz#631e6cc784c7b660417421349aac304c94115366" @@ -69,11 +113,27 @@ lru-cache "^5.1.1" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" + integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz#c769afefd41d171836f7cb63e295bedf689d48ba" integrity sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ== +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + "@babel/helper-function-name@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" @@ -82,6 +142,14 @@ "@babel/template" "^7.20.7" "@babel/types" "^7.21.0" +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -89,6 +157,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.21.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" @@ -96,6 +171,13 @@ dependencies: "@babel/types" "^7.21.4" +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-module-transforms@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz#d937c82e9af68d31ab49039136a222b17ac0b420" @@ -110,6 +192,17 @@ "@babel/traverse" "^7.21.5" "@babel/types" "^7.21.5" +"@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" @@ -122,6 +215,13 @@ dependencies: "@babel/types" "^7.21.5" +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" @@ -129,21 +229,43 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz#2b3eea65443c6bdc31c22d037c65f6d323b6b2bd" integrity sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + "@babel/helper-validator-option@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + "@babel/helpers@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.5.tgz#5bac66e084d7a4d2d9696bdf0175a93f7fb63c08" @@ -153,6 +275,15 @@ "@babel/traverse" "^7.21.5" "@babel/types" "^7.21.5" +"@babel/helpers@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a" + integrity sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -162,11 +293,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" + integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.5", "@babel/parser@^7.21.8", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": version "7.21.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8" integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA== +"@babel/parser@^7.22.10", "@babel/parser@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" + integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -281,6 +426,15 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" +"@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/traverse@^7.21.5", "@babel/traverse@^7.7.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.5.tgz#ad22361d352a5154b498299d523cf72998a4b133" @@ -297,6 +451,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.10.tgz#20252acb240e746d27c2e82b4484f199cf8141aa" + integrity sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig== + dependencies: + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.10" + "@babel/types" "^7.22.10" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.6.1", "@babel/types@^7.9.6": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.5.tgz#18dfbd47c39d3904d5db3d3dc2cc80bedb60e5b6" @@ -306,6 +476,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.22.10", "@babel/types@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03" + integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1880,6 +2059,16 @@ browserslist@^4.14.5, browserslist@^4.21.3: node-releases "^2.0.8" update-browserslist-db "^1.0.10" +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -2039,6 +2228,11 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz#d882d1a34d89c11aea53b8cdc791931bdab5fe1b" integrity sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA== +caniuse-lite@^1.0.30001517: + version "1.0.30001520" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz#62e2b7a1c7b35269594cf296a80bdf8cb9565006" + integrity sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA== + casparcg-connection@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/casparcg-connection/-/casparcg-connection-5.1.0.tgz#6ea23c2895b5a28e2cd362a0ab0cd19c6ce68805" @@ -2053,7 +2247,7 @@ chalk@5.2.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== -chalk@^2.0.0: +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2860,6 +3054,11 @@ electron-to-chromium@^1.4.284: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.396.tgz#3d3664eb58d86376fbe2fece3705f68ca197205c" integrity sha512-pqKTdqp/c5vsrc0xUPYXTDBo9ixZuGY8es4ZOjjd6HD6bFYbu5QA09VoW3fkY4LF1T0zYk86lN6bZnNlBuOpdQ== +electron-to-chromium@^1.4.477: + version "1.4.490" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" + integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== + electron@16.2.6: version "16.2.6" resolved "https://registry.yarnpkg.com/electron/-/electron-16.2.6.tgz#2d22077edb5361ab52034bb3b19405380921931b" @@ -2869,17 +3068,17 @@ electron@16.2.6: "@types/node" "^14.6.2" extract-zip "^1.0.3" -emberplus-connection@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/emberplus-connection/-/emberplus-connection-0.1.2.tgz#001bb1db4ac28d340af59e6fbe8b4d2574dc1373" - integrity sha512-oTxY2wyUbWTD2hSaQOvhrQnrgqpXrc39UPQUqPUwbdPpH3UX9mChLtHUrp1GU2zl+/UsCMaPcG+okf1Td268QQ== +emberplus-connection@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/emberplus-connection/-/emberplus-connection-0.2.1.tgz#3166b29e228a1a2b561e346112c45d711f3238ea" + integrity sha512-M5/8fNk0u84xC8M3e4QZoKonaxfei92FynWfSqww1IoP4eAt9/A5xxmFaRTW/ivLgP58hXlYC6mhemSQzoL4bg== dependencies: asn1 evs-broadcast/node-asn1 - debug "^4.3.3" - enum "^2.4.0" + debug "^4.3.4" + eventemitter3 "^4.0.7" long "^3.2.0" smart-buffer "^3.0.3" - tslib "^2.3.1" + tslib "^2.6.2" emittery@^0.13.1: version "0.13.1" @@ -2958,13 +3157,6 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== -enum@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/enum/-/enum-2.5.0.tgz#f205b8c65a335a8ace8081105df971b18568b984" - integrity sha512-IN9mE0yf+9DoUvGpNQfvJNJ9HyS9VGeo7llLkPdRBtMU2LHLXiQ/JcOI03u8lig0lefGCewv9x82vK8LI8rNPg== - dependencies: - is-buffer "^1.1.0" - env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -3871,11 +4063,6 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-buffer@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -5048,6 +5235,11 @@ node-license-validator@^1.3.2: spdx-satisfies "^5.0.1" yargs "^17.0.1" +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -5901,7 +6093,7 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -redux@^4.1.2, redux@^4.2.1: +redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -6127,6 +6319,11 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -6896,6 +7093,11 @@ tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -7002,7 +7204,7 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.10: +update-browserslist-db@^1.0.10, update-browserslist-db@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==