From d53603cd083b2019039e1fc177807057d4375f07 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Thu, 5 Mar 2026 19:36:57 +0530 Subject: [PATCH] feat(32-02): add conditional dispatch to mixer categorization - Replace unconditional dispatches with mixerArraysEqual checks - Only dispatch when category content actually changes - Update prevCategoriesRef after each dispatch - Add console logs for debugging dispatch decisions - Run prettier to fix formatting --- jam-ui/src/hooks/useMixerHelper.js | 1151 ++++++++++++++++------------ 1 file changed, 673 insertions(+), 478 deletions(-) diff --git a/jam-ui/src/hooks/useMixerHelper.js b/jam-ui/src/hooks/useMixerHelper.js index 9656163c1..ff217572f 100644 --- a/jam-ui/src/hooks/useMixerHelper.js +++ b/jam-ui/src/hooks/useMixerHelper.js @@ -28,16 +28,8 @@ import { setMetronomeTrackMixers, setAdhocTrackMixers } from '../store/features/mixersSlice'; -import { - selectBackingTracks, - selectJamTracks, - selectRecordedTracks -} from '../store/features/mediaSlice'; -import { - selectMixMode, - selectCurrentMixerRange, - setCurrentMixerRange -} from '../store/features/sessionUISlice'; +import { selectBackingTracks, selectJamTracks, selectRecordedTracks } from '../store/features/mediaSlice'; +import { selectMixMode, selectCurrentMixerRange, setCurrentMixerRange } from '../store/features/sessionUISlice'; import { ChannelGroupIds, CategoryGroupIds, MIX_MODES, MIDI_TRACK } from '../helpers/globals.js'; import useVuHelpers from './useVuHelpers.js'; import useFaderHelpers from './useFaderHelpers.js'; @@ -64,10 +56,11 @@ const mixerArraysEqual = (prev, next) => { if (!prev || !next || prev.length !== next.length) return false; // Compare by mixer pair IDs (master.id + personal.id creates unique pair key) - const getIds = (arr) => arr - .map(pair => `${pair.master?.id || ''}-${pair.personal?.id || ''}`) - .sort() - .join(','); + const getIds = arr => + arr + .map(pair => `${pair.master?.id || ''}-${pair.personal?.id || ''}`) + .sort() + .join(','); return getIds(prev) === getIds(next); }; @@ -97,12 +90,23 @@ const useMixerHelper = () => { // Destructure for backward compatibility with rest of hook const { chatMixer, broadcastMixer, recordingMixer } = coreMixers; - const { recordingTrackMixers, backingTrackMixers, jamTrackMixers, - metronomeTrackMixers, adhocTrackMixers } = trackMixers; + const { + recordingTrackMixers, + backingTrackMixers, + jamTrackMixers, + metronomeTrackMixers, + adhocTrackMixers + } = trackMixers; const { allMixers, mixersByResourceId, mixersByTrackId } = lookupTables; const { masterMixers, personalMixers } = masterPersonal; - const { metronome, metronomeSettings, mediaSummary, noAudioUsers, - clientsWithAudioOverride, isReady: isReadyRedux } = metadata; + const { + metronome, + metronomeSettings, + mediaSummary, + noAudioUsers, + clientsWithAudioOverride, + isReady: isReadyRedux + } = metadata; const { simulatedMusicCategoryMixers, simulatedChatCategoryMixers } = simulatedMixers; // Media data from mediaSlice @@ -114,10 +118,20 @@ const useMixerHelper = () => { const mixMode = useSelector(selectMixMode); const currentMixerRange = useSelector(selectCurrentMixerRange); - const mediaTrackGroups = useMemo(() => [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, - ChannelGroupIds.MetronomeGroup], []); - const muteBothMasterAndPersonalGroups = useMemo(() => [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MidiInputMusicGroup, ChannelGroupIds.MediaTrackGroup, - ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup], []); + const mediaTrackGroups = useMemo( + () => [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup], + [] + ); + const muteBothMasterAndPersonalGroups = useMemo( + () => [ + ChannelGroupIds.AudioInputMusicGroup, + ChannelGroupIds.MidiInputMusicGroup, + ChannelGroupIds.MediaTrackGroup, + ChannelGroupIds.JamTrackGroup, + ChannelGroupIds.MetronomeGroup + ], + [] + ); // Phase 4: Replace CurrentSessionContext with Redux const currentSession = useSelector(selectActiveSession); @@ -139,96 +153,120 @@ const useMixerHelper = () => { // console.log("_XDEBUG_ useMixerHelper: allMixersRef updated", allMixersRef.current); }, [allMixers]); - const getMixer = useCallback((mixerId, mode) => { - // Only default to mixMode if mode is undefined, not if it's explicitly false - if (mode === undefined) { - mode = mixMode; - } - return allMixersRef.current[(mode ? 'M' : 'P') + mixerId]; - }, [mixMode]); + const getMixer = useCallback( + (mixerId, mode) => { + // Only default to mixMode if mode is undefined, not if it's explicitly false + if (mode === undefined) { + mode = mixMode; + } + return allMixersRef.current[(mode ? 'M' : 'P') + mixerId]; + }, + [mixMode] + ); - const fillTrackVolumeObject = useCallback((mixerId, mode, currentAllMixers, broadcast = true) => { - const mixer = getMixer(mixerId, mode, currentAllMixers); - if (mixer == null) { - return null; - } + const fillTrackVolumeObject = useCallback( + (mixerId, mode, currentAllMixers, broadcast = true) => { + const mixer = getMixer(mixerId, mode, currentAllMixers); + if (mixer == null) { + return null; + } - // Build volume object directly and return it (don't rely on async state update) - const volumeObj = { - id: mixer.id, - _id: mixer._id, - groupID: mixer.group_id, - clientID: mixer.client_id, - broadcast: broadcast, - master: mixer.master, - monitor: mixer.monitor, - mute: mixer.mute, - name: mixer.name, - record: mixer.record, - volL: mixer.volume_left, - pan: mixer.pan, - mediaType: mixer.media_type, - isJamTrack: mixer.is_jam_track, - isMetronome: mixer.is_metronome, - volR: mixer.volume_left, - loop: mixer.loop - }; - - // Also update React state for other consumers - setTrackVolumeObject(volumeObj); - - // Redux: Update mixer range in sessionUISlice - dispatch(setCurrentMixerRange({ - min: mixer.range_low, - max: mixer.range_high - })); - - // Return both mixer and the volume object - return { mixer, volumeObj }; - }, [getMixer, setTrackVolumeObject, dispatch]); - - const setMixerVolume = useCallback(async (mixer, volumePercent, relative, originalVolume, controlGroup, baseVolumeObj) => { - const newVolume = faderHelpers.convertPercentToAudioTaper(volumePercent); - - // Use the passed volumeObj instead of relying on async state - const sourceVolumeObj = baseVolumeObj || trackVolumeObject; - - let updatedTrackVolumeObject; - if (relative) { - updatedTrackVolumeObject = { - ...sourceVolumeObj, - volL: sourceVolumeObj.volL + (newVolume - originalVolume), - volR: sourceVolumeObj.volR + (newVolume - originalVolume), + // Build volume object directly and return it (don't rely on async state update) + const volumeObj = { + id: mixer.id, + _id: mixer._id, + groupID: mixer.group_id, + clientID: mixer.client_id, + broadcast: broadcast, + master: mixer.master, + monitor: mixer.monitor, + mute: mixer.mute, + name: mixer.name, + record: mixer.record, + volL: mixer.volume_left, + pan: mixer.pan, + mediaType: mixer.media_type, + isJamTrack: mixer.is_jam_track, + isMetronome: mixer.is_metronome, + volR: mixer.volume_left, + loop: mixer.loop }; - // Apply clamping - if (updatedTrackVolumeObject.volL < -80) updatedTrackVolumeObject.volL = -80; - if (updatedTrackVolumeObject.volL > 20) updatedTrackVolumeObject.volL = 20; - if (updatedTrackVolumeObject.volR < -80) updatedTrackVolumeObject.volR = -80; - if (updatedTrackVolumeObject.volR > 20) updatedTrackVolumeObject.volR = 20; - } else { - updatedTrackVolumeObject = { - ...sourceVolumeObj, - volL: newVolume, - volR: newVolume, - }; - } + // Also update React state for other consumers + setTrackVolumeObject(volumeObj); - // Update state - setTrackVolumeObject(updatedTrackVolumeObject); + // Redux: Update mixer range in sessionUISlice + dispatch( + setCurrentMixerRange({ + min: mixer.range_low, + max: mixer.range_high + }) + ); - // Use the computed object for jamClient call - if (controlGroup != null) { - const controlGroupsArg = mixer.mode === MIX_MODES.PERSONAL ? 0 : 1; - console.log("setMixerVolume: setting session mixer category playout state for controlGroup", controlGroup, "controlGroupsArg", controlGroupsArg, "volume", updatedTrackVolumeObject.volL); - await jamClient.setSessionMixerCategoryPlayoutState(controlGroup === 'music', controlGroupsArg, updatedTrackVolumeObject.volL); - } else { - await jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, updatedTrackVolumeObject); - } - }, [trackVolumeObject, faderHelpers, jamClient, setTrackVolumeObject]); + // Return both mixer and the volume object + return { mixer, volumeObj }; + }, + [getMixer, setTrackVolumeObject, dispatch] + ); + + const setMixerVolume = useCallback( + async (mixer, volumePercent, relative, originalVolume, controlGroup, baseVolumeObj) => { + const newVolume = faderHelpers.convertPercentToAudioTaper(volumePercent); + + // Use the passed volumeObj instead of relying on async state + const sourceVolumeObj = baseVolumeObj || trackVolumeObject; + + let updatedTrackVolumeObject; + if (relative) { + updatedTrackVolumeObject = { + ...sourceVolumeObj, + volL: sourceVolumeObj.volL + (newVolume - originalVolume), + volR: sourceVolumeObj.volR + (newVolume - originalVolume) + }; + + // Apply clamping + if (updatedTrackVolumeObject.volL < -80) updatedTrackVolumeObject.volL = -80; + if (updatedTrackVolumeObject.volL > 20) updatedTrackVolumeObject.volL = 20; + if (updatedTrackVolumeObject.volR < -80) updatedTrackVolumeObject.volR = -80; + if (updatedTrackVolumeObject.volR > 20) updatedTrackVolumeObject.volR = 20; + } else { + updatedTrackVolumeObject = { + ...sourceVolumeObj, + volL: newVolume, + volR: newVolume + }; + } + + // Update state + setTrackVolumeObject(updatedTrackVolumeObject); + + // Use the computed object for jamClient call + if (controlGroup != null) { + const controlGroupsArg = mixer.mode === MIX_MODES.PERSONAL ? 0 : 1; + console.log( + 'setMixerVolume: setting session mixer category playout state for controlGroup', + controlGroup, + 'controlGroupsArg', + controlGroupsArg, + 'volume', + updatedTrackVolumeObject.volL + ); + await jamClient.setSessionMixerCategoryPlayoutState( + controlGroup === 'music', + controlGroupsArg, + updatedTrackVolumeObject.volL + ); + } else { + await jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, updatedTrackVolumeObject); + } + }, + [trackVolumeObject, faderHelpers, jamClient, setTrackVolumeObject] + ); const mediaMixers = useCallback((masterMixer, isOpener, currentAllMixers) => { - const personalMixer = isOpener ? getMixerByResourceId(masterMixer.rid, MIX_MODES.PERSONAL, currentAllMixers) : masterMixer; + const personalMixer = isOpener + ? getMixerByResourceId(masterMixer.rid, MIX_MODES.PERSONAL, currentAllMixers) + : masterMixer; const personalVuMixer = isOpener ? personalMixer : masterMixer; return { isOpener: isOpener, @@ -246,15 +284,18 @@ const useMixerHelper = () => { }, []); // Redux: updateMixerData now dispatches Redux actions - const updateMixerData = useCallback((session, masterMixers, personalMixers, metro, noAudioUsers, clientsWithAudioOverride, mixMode) => { - //console.debug("useMixerHelper: updateMixerData called", { session, masterMixers, personalMixers, mixMode }); + const updateMixerData = useCallback( + (session, masterMixers, personalMixers, metro, noAudioUsers, clientsWithAudioOverride, mixMode) => { + //console.debug("useMixerHelper: updateMixerData called", { session, masterMixers, personalMixers, mixMode }); - // Dispatch Redux actions instead of setState calls - dispatch(setMasterMixers(masterMixers)); - dispatch(setPersonalMixers(personalMixers)); - // Note: session is tracked in activeSessionSlice, metro/noAudioUsers/clientsWithAudioOverride in mixersSlice - // mixMode is tracked in sessionUISlice - }, [dispatch]); + // Dispatch Redux actions instead of setState calls + dispatch(setMasterMixers(masterMixers)); + dispatch(setPersonalMixers(personalMixers)); + // Note: session is tracked in activeSessionSlice, metro/noAudioUsers/clientsWithAudioOverride in mixersSlice + // mixMode is tracked in sessionUISlice + }, + [dispatch] + ); // Redux: organizeMixers is now a reducer, trigger it via action useEffect(() => { @@ -303,9 +344,11 @@ const useMixerHelper = () => { break; default: // Other mixer types go into adhoc - if (masterMixer.group_id !== ChannelGroupIds.UserMusicInputGroup && - masterMixer.group_id !== ChannelGroupIds.ChatMicGroup && - masterMixer.group_id !== ChannelGroupIds.BroadcastGroup) { + if ( + masterMixer.group_id !== ChannelGroupIds.UserMusicInputGroup && + masterMixer.group_id !== ChannelGroupIds.ChatMicGroup && + masterMixer.group_id !== ChannelGroupIds.BroadcastGroup + ) { adhocTrackMixers.push(mixerPair); } } @@ -319,13 +362,38 @@ const useMixerHelper = () => { adhoc: adhocTrackMixers.length }); - // Dispatch to Redux - dispatch(setMetronomeTrackMixers(metronomeTrackMixers)); - dispatch(setBackingTrackMixers(backingTrackMixers)); - dispatch(setJamTrackMixers(jamTrackMixers)); - dispatch(setRecordingTrackMixers(recordingTrackMixers)); - dispatch(setAdhocTrackMixers(adhocTrackMixers)); + // Dispatch to Redux ONLY if content changed + // This prevents unnecessary re-renders when mixer objects change but categories stay same + if (!mixerArraysEqual(prevCategoriesRef.current.metronome, metronomeTrackMixers)) { + console.log('[useMixerHelper] Metronome mixers changed, dispatching'); + dispatch(setMetronomeTrackMixers(metronomeTrackMixers)); + prevCategoriesRef.current.metronome = metronomeTrackMixers; + } + + if (!mixerArraysEqual(prevCategoriesRef.current.backing, backingTrackMixers)) { + console.log('[useMixerHelper] Backing track mixers changed, dispatching'); + dispatch(setBackingTrackMixers(backingTrackMixers)); + prevCategoriesRef.current.backing = backingTrackMixers; + } + + if (!mixerArraysEqual(prevCategoriesRef.current.jam, jamTrackMixers)) { + console.log('[useMixerHelper] Jam track mixers changed, dispatching'); + dispatch(setJamTrackMixers(jamTrackMixers)); + prevCategoriesRef.current.jam = jamTrackMixers; + } + + if (!mixerArraysEqual(prevCategoriesRef.current.recording, recordingTrackMixers)) { + console.log('[useMixerHelper] Recording mixers changed, dispatching'); + dispatch(setRecordingTrackMixers(recordingTrackMixers)); + prevCategoriesRef.current.recording = recordingTrackMixers; + } + + if (!mixerArraysEqual(prevCategoriesRef.current.adhoc, adhocTrackMixers)) { + console.log('[useMixerHelper] Adhoc mixers changed, dispatching'); + dispatch(setAdhocTrackMixers(adhocTrackMixers)); + prevCategoriesRef.current.adhoc = adhocTrackMixers; + } }, [masterMixers, personalMixers, mixMode, dispatch]); // Sync local isReady ref with Redux isReady state @@ -364,145 +432,202 @@ const useMixerHelper = () => { previousMixerIdsRef.current = currentMixerIds; }, [allMixers, isReadyRedux, removeVuState]); - const getMixerByTrackId = useCallback((trackId, mode) => { - const mixerPair = mixersByTrackId[trackId]; + const getMixerByTrackId = useCallback( + (trackId, mode) => { + const mixerPair = mixersByTrackId[trackId]; - if (!mixerPair) return null; + if (!mixerPair) return null; - if (mode === undefined) { - return mixerPair; - } else { - if (mode === MIX_MODES.MASTER) { - return mixerPair.master; + if (mode === undefined) { + return mixerPair; } else { - return mixerPair.personal; + if (mode === MIX_MODES.MASTER) { + return mixerPair.master; + } else { + return mixerPair.personal; + } } - } - }, [mixersByTrackId]); + }, + [mixersByTrackId] + ); - const groupedMixersForClientId = useCallback((clientId, groupIds, usedMixers, mixMode, currentAllMixers) => { - const foundMixers = {}; - const mixers = mixMode === MIX_MODES.MASTER ? masterMixers : personalMixers; + const groupedMixersForClientId = useCallback( + (clientId, groupIds, usedMixers, mixMode, currentAllMixers) => { + const foundMixers = {}; + const mixers = mixMode === MIX_MODES.MASTER ? masterMixers : personalMixers; - for (const mixer of mixers) { - if (!mixer) { - continue; - } + for (const mixer of mixers) { + if (!mixer) { + continue; + } - if (mixer.client_id === clientId) { - for (const groupId of groupIds) { - if (mixer.group_id === groupId) { - if ((mixer.groupId !== ChannelGroupIds.UserMusicInputGroup) && !(mixer.id in usedMixers)) { - let mixers = foundMixers[mixer.group_id]; - if (!mixers) { - mixers = []; - foundMixers[mixer.group_id] = mixers; + if (mixer.client_id === clientId) { + for (const groupId of groupIds) { + if (mixer.group_id === groupId) { + if (mixer.groupId !== ChannelGroupIds.UserMusicInputGroup && !(mixer.id in usedMixers)) { + let mixers = foundMixers[mixer.group_id]; + if (!mixers) { + mixers = []; + foundMixers[mixer.group_id] = mixers; + } + mixers.push(mixer); } - mixers.push(mixer); } } } } - } - return foundMixers; - }, [masterMixers, personalMixers]); + return foundMixers; + }, + [masterMixers, personalMixers] + ); - const findMixerForTrack = useCallback((client_id, track, myTrack, mode) => { - let mixer = null; - let oppositeMixer = null; - let vuMixer = null; - let muteMixer = null; + const findMixerForTrack = useCallback( + (client_id, track, myTrack, mode) => { + let mixer = null; + let oppositeMixer = null; + let vuMixer = null; + let muteMixer = null; - if (myTrack) { - mixer = getMixerByTrackId(track.client_track_id, mode); - vuMixer = mixer; - muteMixer = mixer; + if (myTrack) { + mixer = getMixerByTrackId(track.client_track_id, mode); + vuMixer = mixer; + muteMixer = mixer; - if (mixer && (mixer.group_id !== ChannelGroupIds.AudioInputMusicGroup && mixer.group_id !== ChannelGroupIds.MidiInputMusicGroup)) { - logger.error("found local mixer that was not of groupID: AudioInputMusicGroup", mixer); - } - - if (mixer) { - oppositeMixer = getMixerByTrackId(track.client_track_id, !mode); - - if (mode === MIX_MODES.PERSONAL) { - muteMixer = oppositeMixer; + if ( + mixer && + (mixer.group_id !== ChannelGroupIds.AudioInputMusicGroup && + mixer.group_id !== ChannelGroupIds.MidiInputMusicGroup) + ) { + logger.error('found local mixer that was not of groupID: AudioInputMusicGroup', mixer); } - if (!oppositeMixer) { - logger.error("unable to find opposite mixer for local mixer", mixer); - } else if (oppositeMixer.group_id !== ChannelGroupIds.AudioInputMusicGroup && oppositeMixer.group_id !== ChannelGroupIds.MidiInputMusicGroup) { - logger.error("found local mixer in opposite mode that was not of groupID: AudioInputMusicGroup", mixer, oppositeMixer); + if (mixer) { + oppositeMixer = getMixerByTrackId(track.client_track_id, !mode); + + if (mode === MIX_MODES.PERSONAL) { + muteMixer = oppositeMixer; + } + + if (!oppositeMixer) { + logger.error('unable to find opposite mixer for local mixer', mixer); + } else if ( + oppositeMixer.group_id !== ChannelGroupIds.AudioInputMusicGroup && + oppositeMixer.group_id !== ChannelGroupIds.MidiInputMusicGroup + ) { + logger.error( + 'found local mixer in opposite mode that was not of groupID: AudioInputMusicGroup', + mixer, + oppositeMixer + ); + } + } else { + logger.debug('local track is not present: ', track, allMixers); } } else { - logger.debug("local track is not present: ", track, allMixers); - } - } else { - switch (mode) { - case MIX_MODES.MASTER: - mixer = getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER); + switch (mode) { + case MIX_MODES.MASTER: + mixer = getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER); - if (mixer && (mixer.group_id !== ChannelGroupIds.PeerAudioInputMusicGroup && mixer.group_id !== ChannelGroupIds.PeerMidiInputMusicGroup)) { - logger.warn("master: found remote mixer that was not of groupID: PeerAudioInputMusicGroup", client_id, track.client_track_id, mixer); - } - - vuMixer = mixer; - muteMixer = mixer; - - if (mixer) { - const oppositeMixers = groupedMixersForClientId(client_id, [ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL); - if (oppositeMixers[ChannelGroupIds.UserMusicInputGroup]) { - oppositeMixer = oppositeMixers[ChannelGroupIds.UserMusicInputGroup][0]; + if ( + mixer && + (mixer.group_id !== ChannelGroupIds.PeerAudioInputMusicGroup && + mixer.group_id !== ChannelGroupIds.PeerMidiInputMusicGroup) + ) { + logger.warn( + 'master: found remote mixer that was not of groupID: PeerAudioInputMusicGroup', + client_id, + track.client_track_id, + mixer + ); } - if (!oppositeMixer) { - logger.warn("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer, personalMixers); - } - } - break; - - case MIX_MODES.PERSONAL: - const mixers = groupedMixersForClientId(client_id, [ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL); - if (mixers[ChannelGroupIds.UserMusicInputGroup]) { - mixer = mixers[ChannelGroupIds.UserMusicInputGroup][0]; - vuMixer = mixer; muteMixer = mixer; if (mixer) { - oppositeMixer = getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER); + const oppositeMixers = groupedMixersForClientId( + client_id, + [ChannelGroupIds.UserMusicInputGroup], + {}, + MIX_MODES.PERSONAL + ); + if (oppositeMixers[ChannelGroupIds.UserMusicInputGroup]) { + oppositeMixer = oppositeMixers[ChannelGroupIds.UserMusicInputGroup][0]; + } + if (!oppositeMixer) { - logger.debug("personal: unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput", client_id, track.client_track_id); - } else if (oppositeMixer.group_id !== ChannelGroupIds.PeerAudioInputMusicGroup && oppositeMixer.group_id !== ChannelGroupIds.PeerMidiInputMusicGroup) { - logger.error("personal: found remote mixer that was not of groupID: PeerAudioInputMusicGroup", client_id, track.client_track_id, mixer); + logger.warn( + 'unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer', + mixer, + personalMixers + ); } } - } else { - logger.error("no UserMusicInputGroup for client_id #{client_id} in PERSONAL mode", mixers); - } - break; + break; + + case MIX_MODES.PERSONAL: + const mixers = groupedMixersForClientId( + client_id, + [ChannelGroupIds.UserMusicInputGroup], + {}, + MIX_MODES.PERSONAL + ); + if (mixers[ChannelGroupIds.UserMusicInputGroup]) { + mixer = mixers[ChannelGroupIds.UserMusicInputGroup][0]; + + vuMixer = mixer; + muteMixer = mixer; + + if (mixer) { + oppositeMixer = getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER); + if (!oppositeMixer) { + logger.debug( + 'personal: unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput', + client_id, + track.client_track_id + ); + } else if ( + oppositeMixer.group_id !== ChannelGroupIds.PeerAudioInputMusicGroup && + oppositeMixer.group_id !== ChannelGroupIds.PeerMidiInputMusicGroup + ) { + logger.error( + 'personal: found remote mixer that was not of groupID: PeerAudioInputMusicGroup', + client_id, + track.client_track_id, + mixer + ); + } + } + } else { + logger.error('no UserMusicInputGroup for client_id #{client_id} in PERSONAL mode', mixers); + } + break; + } } - } - // Ensure mixer objects have the correct mode set for proper persistence - const mixerWithMode = mixer ? { ...mixer, mode } : null; - const oppositeMode = mode === MIX_MODES.MASTER ? MIX_MODES.PERSONAL : MIX_MODES.MASTER; - const oppositeMixerWithMode = oppositeMixer ? { ...oppositeMixer, mode: oppositeMode } : null; - const vuMixerWithMode = vuMixer ? { ...vuMixer, mode } : null; - const muteMixerWithMode = muteMixer ? { ...muteMixer, mode: muteMixer === oppositeMixer ? oppositeMode : mode } : null; + // Ensure mixer objects have the correct mode set for proper persistence + const mixerWithMode = mixer ? { ...mixer, mode } : null; + const oppositeMode = mode === MIX_MODES.MASTER ? MIX_MODES.PERSONAL : MIX_MODES.MASTER; + const oppositeMixerWithMode = oppositeMixer ? { ...oppositeMixer, mode: oppositeMode } : null; + const vuMixerWithMode = vuMixer ? { ...vuMixer, mode } : null; + const muteMixerWithMode = muteMixer + ? { ...muteMixer, mode: muteMixer === oppositeMixer ? oppositeMode : mode } + : null; - return { - mixer: mixerWithMode, - oppositeMixer: oppositeMixerWithMode, - vuMixer: vuMixerWithMode, - muteMixer: muteMixerWithMode - }; - }, [getMixerByTrackId, groupedMixersForClientId, personalMixers, allMixers]); + return { + mixer: mixerWithMode, + oppositeMixer: oppositeMixerWithMode, + vuMixer: vuMixerWithMode, + muteMixer: muteMixerWithMode + }; + }, + [getMixerByTrackId, groupedMixersForClientId, personalMixers, allMixers] + ); // Compute myTracks - memoized to prevent infinite re-renders const myTracks = useMemo(() => { - console.debug("useMixerHelper: computing myTracks", { + console.debug('useMixerHelper: computing myTracks', { isConnected, currentSession, jamClient, @@ -511,28 +636,29 @@ const useMixerHelper = () => { }); if (!isConnected || !inSession || !jamClient || !allMixers) { - return previousMyTracksRef.current; // Return previous value, not [] + return previousMyTracksRef.current; // Return previous value, not [] } // Safety check: if allMixers is empty during state transition, return previous value if (typeof allMixers === 'object' && Object.keys(allMixers).length === 0) { - console.warn("useMixerHelper: allMixers is empty, returning previous myTracks"); - return previousMyTracksRef.current; // Return previous value, not [] + console.warn('useMixerHelper: allMixers is empty, returning previous myTracks'); + return previousMyTracksRef.current; // Return previous value, not [] } //const participant = currentSession.participants?.[jamClient.clientId]; const participant = getParticipant(server.clientId); if (!participant) { - return previousMyTracksRef.current; // Return previous value, not [] + return previousMyTracksRef.current; // Return previous value, not [] } const tracks = []; - const connStatsClientId = participant.client_role === 'child' && participant.parent_client_id - ? participant.parent_client_id - : server.clientId; + const connStatsClientId = + participant.client_role === 'child' && participant.parent_client_id + ? participant.parent_client_id + : server.clientId; - console.debug("useMixerHelper: my participant", participant, { connStatsClientId }); + console.debug('useMixerHelper: my participant', participant, { connStatsClientId }); const photoUrl = getAvatarUrl(participant.user.photo_url); const name = participant.user.name; @@ -551,7 +677,7 @@ const useMixerHelper = () => { const assignments = jamClient.VSTListTrackAssignments(); vstTrackAssignments = assignments || { vsts: [] }; } catch (error) { - console.warn("Failed to get VST track assignments:", error); + console.warn('Failed to get VST track assignments:', error); } const participantTracks = participant.tracks || []; @@ -568,9 +694,10 @@ const useMixerHelper = () => { // Check if this track has a VST plugin assigned // Native client uses 0-based track indices for VST assignments - const hasVst = vstTrackAssignments.vsts && Array.isArray(vstTrackAssignments.vsts) - ? vstTrackAssignments.vsts.some(vst => vst.track === trackIndex) - : false; + const hasVst = + vstTrackAssignments.vsts && Array.isArray(vstTrackAssignments.vsts) + ? vstTrackAssignments.vsts.some(vst => vst.track === trackIndex) + : false; tracks.push({ track: { @@ -602,7 +729,6 @@ const useMixerHelper = () => { // console.debug("useMixerHelper: myTracks updated", myTracks); // }, [myTracks]); - const mixersForGroupId = useCallback((groupId, mixMode, currentAllMixers) => { const foundMixers = []; const modePrefix = mixMode === MIX_MODES.MASTER ? 'M' : 'P'; @@ -619,132 +745,177 @@ const useMixerHelper = () => { return foundMixers; }, []); - const getGroupMixer = useCallback((categoryId, mode) => { - const groupId = mode === MIX_MODES.MASTER ? ChannelGroupIds.MasterCatGroup : ChannelGroupIds.MonitorCatGroup; - const oppositeGroupId = !mode === MIX_MODES.MASTER ? ChannelGroupIds.MasterCatGroup : ChannelGroupIds.MonitorCatGroup; - const mixers = mixersForGroupId(groupId, mode, allMixers); - const oppositeMixers = mixersForGroupId(oppositeGroupId, !mode, allMixers); + const getGroupMixer = useCallback( + (categoryId, mode) => { + const groupId = mode === MIX_MODES.MASTER ? ChannelGroupIds.MasterCatGroup : ChannelGroupIds.MonitorCatGroup; + const oppositeGroupId = + !mode === MIX_MODES.MASTER ? ChannelGroupIds.MasterCatGroup : ChannelGroupIds.MonitorCatGroup; + const mixers = mixersForGroupId(groupId, mode, allMixers); + const oppositeMixers = mixersForGroupId(oppositeGroupId, !mode, allMixers); - if (mixers.length === 0) { - return null; - } - - let found = null; - let oppositeFound = null; - for (const mixer of mixers) { - if (mixer.name === categoryId) { - found = mixer; - break; + if (mixers.length === 0) { + return null; } - } - for (const mixer of oppositeMixers) { - if (mixer.name === categoryId) { - oppositeFound = mixer; - break; + let found = null; + let oppositeFound = null; + for (const mixer of mixers) { + if (mixer.name === categoryId) { + found = mixer; + break; + } } - } - if (!found) { - logger.warn("could not find mixer with categoryId: " + categoryId); - return null; - } else { - return { - mixer: found, - muteMixer: found, - vuMixer: found, - oppositeMixer: oppositeFound - }; - } - }, [mixersForGroupId, allMixers]); + for (const mixer of oppositeMixers) { + if (mixer.name === categoryId) { + oppositeFound = mixer; + break; + } + } - const mixerForGroupId = useCallback((groupId, mixMode, currentAllMixers) => { - const mixers = mixersForGroupId(groupId, mixMode, currentAllMixers); - if (mixers && mixers.length > 0) { - return mixers[0]; - } else { - return null; - } - }, [mixersForGroupId]); - - const getAudioInputCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.AudioInputMusic, mode, currentAllMixers); - }, [getGroupMixer]); - - const getChatCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.AudioInputChat, mode, currentAllMixers); - }, [getGroupMixer]); - - const getUserChatCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.UserChat, mode, currentAllMixers); - }, [getGroupMixer]); - - const getMediaCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.MediaTrack, mode, currentAllMixers); - }, [getGroupMixer]); - - const getUserMediaCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.UserMedia, mode, currentAllMixers); - }, [getGroupMixer]); - - const getUserMusicCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.UserMusic, mode, currentAllMixers); - }, [getGroupMixer]); - - const getMetronomeCategoryMixer = useCallback((mode, currentAllMixers) => { - return getGroupMixer(CategoryGroupIds.Metronome, mode, currentAllMixers); - }, [getGroupMixer]); - - const getOutputCategoryMixer = useCallback((mode, currentAllMixers) => { - if (mode === MIX_MODES.MASTER) { - return getGroupMixer(CategoryGroupIds.MasterCatGroup, mode, currentAllMixers); - } else { - return getGroupMixer(CategoryGroupIds.MonitorCatGroup, mode, currentAllMixers); - } - }, [getGroupMixer]); - - const getOutputMixer = useCallback((mode, currentAllMixers) => { - if (mode === MIX_MODES.MASTER) { - return mixerForGroupId(ChannelGroupIds.MasterGroup, mode, currentAllMixers); - } else { - return mixerForGroupId(ChannelGroupIds.MonitorGroup, mode, currentAllMixers); - } - }, [mixerForGroupId]); - - const setMixerPan = useCallback(async (mixer, panPercent) => { - trackVolumeObject.pan = panHelpers.convertPercentToPan(panPercent); - await jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, trackVolumeObject); - }, [trackVolumeObject, panHelpers, jamClient]); - - const getMixerByResourceId = useCallback((resourceId, mode) => { - const mixerPair = mixersByResourceId[resourceId]; - - if (!mixerPair) return null; - - if (!mode) { - return mixerPair; - } else { - if (mode === MIX_MODES.MASTER) { - return mixerPair.master; + if (!found) { + logger.warn('could not find mixer with categoryId: ' + categoryId); + return null; } else { - return mixerPair.personal; + return { + mixer: found, + muteMixer: found, + vuMixer: found, + oppositeMixer: oppositeFound + }; } - } - }, [mixersByResourceId]); + }, + [mixersForGroupId, allMixers] + ); - const mute = useCallback(async (mixerId, mode, muting) => { - if (mode == null) { mode = mixMode; } + const mixerForGroupId = useCallback( + (groupId, mixMode, currentAllMixers) => { + const mixers = mixersForGroupId(groupId, mixMode, currentAllMixers); + if (mixers && mixers.length > 0) { + return mixers[0]; + } else { + return null; + } + }, + [mixersForGroupId] + ); - const result = fillTrackVolumeObject(mixerId, mode); - if (!result) return; + const getAudioInputCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.AudioInputMusic, mode, currentAllMixers); + }, + [getGroupMixer] + ); - const { volumeObj } = result; - const updatedVolumeObj = { ...volumeObj, mute: muting }; - await context.jamClient.SessionSetTrackVolumeData(mixerId, mode, updatedVolumeObj); + const getChatCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.AudioInputChat, mode, currentAllMixers); + }, + [getGroupMixer] + ); - const updatedMixer = getMixer(mixerId, mode); - updatedMixer.mute = muting; - }, [mixMode, getMixer, fillTrackVolumeObject]); + const getUserChatCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.UserChat, mode, currentAllMixers); + }, + [getGroupMixer] + ); + + const getMediaCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.MediaTrack, mode, currentAllMixers); + }, + [getGroupMixer] + ); + + const getUserMediaCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.UserMedia, mode, currentAllMixers); + }, + [getGroupMixer] + ); + + const getUserMusicCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.UserMusic, mode, currentAllMixers); + }, + [getGroupMixer] + ); + + const getMetronomeCategoryMixer = useCallback( + (mode, currentAllMixers) => { + return getGroupMixer(CategoryGroupIds.Metronome, mode, currentAllMixers); + }, + [getGroupMixer] + ); + + const getOutputCategoryMixer = useCallback( + (mode, currentAllMixers) => { + if (mode === MIX_MODES.MASTER) { + return getGroupMixer(CategoryGroupIds.MasterCatGroup, mode, currentAllMixers); + } else { + return getGroupMixer(CategoryGroupIds.MonitorCatGroup, mode, currentAllMixers); + } + }, + [getGroupMixer] + ); + + const getOutputMixer = useCallback( + (mode, currentAllMixers) => { + if (mode === MIX_MODES.MASTER) { + return mixerForGroupId(ChannelGroupIds.MasterGroup, mode, currentAllMixers); + } else { + return mixerForGroupId(ChannelGroupIds.MonitorGroup, mode, currentAllMixers); + } + }, + [mixerForGroupId] + ); + + const setMixerPan = useCallback( + async (mixer, panPercent) => { + trackVolumeObject.pan = panHelpers.convertPercentToPan(panPercent); + await jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, trackVolumeObject); + }, + [trackVolumeObject, panHelpers, jamClient] + ); + + const getMixerByResourceId = useCallback( + (resourceId, mode) => { + const mixerPair = mixersByResourceId[resourceId]; + + if (!mixerPair) return null; + + if (!mode) { + return mixerPair; + } else { + if (mode === MIX_MODES.MASTER) { + return mixerPair.master; + } else { + return mixerPair.personal; + } + } + }, + [mixersByResourceId] + ); + + const mute = useCallback( + async (mixerId, mode, muting) => { + if (mode == null) { + mode = mixMode; + } + + const result = fillTrackVolumeObject(mixerId, mode); + if (!result) return; + + const { volumeObj } = result; + const updatedVolumeObj = { ...volumeObj, mute: muting }; + await context.jamClient.SessionSetTrackVolumeData(mixerId, mode, updatedVolumeObj); + + const updatedMixer = getMixer(mixerId, mode); + updatedMixer.mute = muting; + }, + [mixMode, getMixer, fillTrackVolumeObject] + ); const getOriginalVolume = useCallback((mixers, gainType) => { let originalVolume = null; @@ -762,56 +933,62 @@ const useMixerHelper = () => { return originalVolume; }, []); - const faderChanged = useCallback(async (data, mixers, gainType, controlGroup) => { - //console.log("MixerHelper: faderChanged called", { data, mixers, gainType, controlGroup }); - if (!Array.isArray(mixers)) { - mixers = [mixers]; - } - const originalVolume = getOriginalVolume(mixers, gainType); - - - // Handle multiple mixers (master + personal pairs like web version) - const mixerIds = mixers.map(m => m.id); - const hasMasterAndPersonalControls = mixerIds.length === 2; - - for (let i = 0; i < mixers.length; i++) { - const m = mixers[i]; - - // Broadcast only when NOT dragging (matches web version logic) - const broadcast = !(data.dragging); - - // Determine mode for multiple mixers (like web version) - let mode = m.mode; - if (hasMasterAndPersonalControls) { - mode = i === 0 ? MIX_MODES.MASTER : MIX_MODES.PERSONAL; + const faderChanged = useCallback( + async (data, mixers, gainType, controlGroup) => { + //console.log("MixerHelper: faderChanged called", { data, mixers, gainType, controlGroup }); + if (!Array.isArray(mixers)) { + mixers = [mixers]; } + const originalVolume = getOriginalVolume(mixers, gainType); - const result = fillTrackVolumeObject(m.id, mode, allMixers, broadcast); - if (result == null) { - console.error("MixerHelper: faderChanged: mixer is null, skipping", m, gainType, controlGroup); - continue; - } + // Handle multiple mixers (master + personal pairs like web version) + const mixerIds = mixers.map(m => m.id); + const hasMasterAndPersonalControls = mixerIds.length === 2; - const { mixer, volumeObj } = result; + for (let i = 0; i < mixers.length; i++) { + const m = mixers[i]; - // Handle relative volume adjustments for music category (matches web version) - const relative = gainType === 'music' && (mixer.name === CategoryGroupIds.UserMedia || mixer.name === CategoryGroupIds.MediaTrack); + // Broadcast only when NOT dragging (matches web version logic) + const broadcast = !data.dragging; - await setMixerVolume(mixer, data.percentage, relative, originalVolume, controlGroup, volumeObj); - - // Redux: Update local mixer state via dispatch - const newVolume = faderHelpers.convertPercentToAudioTaper(data.percentage); - dispatch(updateMixer({ - mixerId: mixer.id, - mode: mixer.mode, - updates: { - volume_left: newVolume + // Determine mode for multiple mixers (like web version) + let mode = m.mode; + if (hasMasterAndPersonalControls) { + mode = i === 0 ? MIX_MODES.MASTER : MIX_MODES.PERSONAL; } - })); - } - }, [getOriginalVolume, getMixer, fillTrackVolumeObject, setMixerVolume, allMixers, trackVolumeObject, dispatch]); - const initGain = useCallback((mixer) => { + const result = fillTrackVolumeObject(m.id, mode, allMixers, broadcast); + if (result == null) { + console.error('MixerHelper: faderChanged: mixer is null, skipping', m, gainType, controlGroup); + continue; + } + + const { mixer, volumeObj } = result; + + // Handle relative volume adjustments for music category (matches web version) + const relative = + gainType === 'music' && + (mixer.name === CategoryGroupIds.UserMedia || mixer.name === CategoryGroupIds.MediaTrack); + + await setMixerVolume(mixer, data.percentage, relative, originalVolume, controlGroup, volumeObj); + + // Redux: Update local mixer state via dispatch + const newVolume = faderHelpers.convertPercentToAudioTaper(data.percentage); + dispatch( + updateMixer({ + mixerId: mixer.id, + mode: mixer.mode, + updates: { + volume_left: newVolume + } + }) + ); + } + }, + [getOriginalVolume, getMixer, fillTrackVolumeObject, setMixerVolume, allMixers, trackVolumeObject, dispatch] + ); + + const initGain = useCallback(mixer => { if (Array.isArray(mixer)) { mixer = mixer[0]; } @@ -822,43 +999,54 @@ const useMixerHelper = () => { console.debug('initGain called for mixer:', mixer?.id); }, []); - const panChanged = useCallback(async (data, mixers, groupId) => { - if (!Array.isArray(mixers)) { mixers = [mixers]; } - const result = []; - for (const mixer of mixers) { - const broadcast = !(data.dragging); - const fillResult = fillTrackVolumeObject(mixer.id, mixer.mode, allMixers, broadcast); - if (!fillResult) continue; + const panChanged = useCallback( + async (data, mixers, groupId) => { + if (!Array.isArray(mixers)) { + mixers = [mixers]; + } + const result = []; + for (const mixer of mixers) { + const broadcast = !data.dragging; + const fillResult = fillTrackVolumeObject(mixer.id, mixer.mode, allMixers, broadcast); + if (!fillResult) continue; - const { mixer: filledMixer } = fillResult; - await setMixerPan(filledMixer, data.percentage); + const { mixer: filledMixer } = fillResult; + await setMixerPan(filledMixer, data.percentage); - const updatedMixer = getMixer(filledMixer.id, filledMixer.mode, allMixers); - updatedMixer.pan = trackVolumeObject.pan; - result.push(trackVolumeObject.pan); - } - return result; - }, [getMixer, fillTrackVolumeObject, setMixerPan, allMixers, trackVolumeObject]); + const updatedMixer = getMixer(filledMixer.id, filledMixer.mode, allMixers); + updatedMixer.pan = trackVolumeObject.pan; + result.push(trackVolumeObject.pan); + } + return result; + }, + [getMixer, fillTrackVolumeObject, setMixerPan, allMixers, trackVolumeObject] + ); - const initPan = useCallback((mixer) => { - const panPercent = panHelpers.convertPanToPercent(mixer.pan); - faderHelpers.setFaderValue(mixer.id, panPercent, Math.abs(mixer.pan)); - faderHelpers.showFader(mixer.id); - }, [faderHelpers, panHelpers]); + const initPan = useCallback( + mixer => { + const panPercent = panHelpers.convertPanToPercent(mixer.pan); + faderHelpers.setFaderValue(mixer.id, panPercent, Math.abs(mixer.pan)); + faderHelpers.showFader(mixer.id); + }, + [faderHelpers, panHelpers] + ); - const loopChanged = useCallback(async (mixer, shouldLoop) => { - const result = fillTrackVolumeObject(mixer.id, mixer.mode, allMixers); - if (!result) return; + const loopChanged = useCallback( + async (mixer, shouldLoop) => { + const result = fillTrackVolumeObject(mixer.id, mixer.mode, allMixers); + if (!result) return; - const { volumeObj } = result; - const updatedVolumeObj = { ...volumeObj, loop: shouldLoop }; + const { volumeObj } = result; + const updatedVolumeObj = { ...volumeObj, loop: shouldLoop }; - setTrackVolumeObject(updatedVolumeObj); - await context.jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, updatedVolumeObj); + setTrackVolumeObject(updatedVolumeObj); + await context.jamClient.SessionSetTrackVolumeData(mixer.id, mixer.mode, updatedVolumeObj); - const updatedMixer = getMixer(mixer.id, mixer.mode, allMixers); - updatedMixer.loop = shouldLoop; - }, [getMixer, fillTrackVolumeObject, allMixers, setTrackVolumeObject]); + const updatedMixer = getMixer(mixer.id, mixer.mode, allMixers); + updatedMixer.loop = shouldLoop; + }, + [getMixer, fillTrackVolumeObject, allMixers, setTrackVolumeObject] + ); const percentFromMixerValue = useCallback((min, max, value) => { try { @@ -874,7 +1062,7 @@ const useMixerHelper = () => { const percentToMixerValue = useCallback((min, max, percent) => { const range = Math.abs(max - min); const multiplier = percent / 100; - let value = min + (multiplier * range); + let value = min + multiplier * range; if (value < min) { value = min; @@ -898,26 +1086,29 @@ const useMixerHelper = () => { mixerStats.count++; }, []); - const dumpVUStats = useCallback((currentVuStats) => { - logger.debug("VU STAT DUMP"); + const dumpVUStats = useCallback(currentVuStats => { + logger.debug('VU STAT DUMP'); for (const mixerId in currentVuStats) { const mixerStat = currentVuStats[mixerId]; - logger.debug("VU STAT: #{mixerStat.group_name} count=#{mixerStat.count}"); + logger.debug('VU STAT: #{mixerStat.group_name} count=#{mixerStat.count}'); } }, []); // Change updateVU to use the ref - const updateVU = useCallback((mixerId, mode, leftValue, leftClipping, rightValue, rightClipping) => { - if (!isReady.current) { - return; - } + const updateVU = useCallback( + (mixerId, mode, leftValue, leftClipping, rightValue, rightClipping) => { + if (!isReady.current) { + return; + } - const mixer = getMixer(mixerId, mode); + const mixer = getMixer(mixerId, mode); - if (mixer) { - updateVU3(mixer, leftValue, leftClipping, rightValue, rightClipping); - } - }, [getMixer, updateVU3]); + if (mixer) { + updateVU3(mixer, leftValue, leftClipping, rightValue, rightClipping); + } + }, + [getMixer, updateVU3] + ); const getTrackInfo = useCallback(async () => { return await context.JK.TrackHelpers.getTrackInfo(context.jamClient, masterMixers); @@ -939,54 +1130,59 @@ const useMixerHelper = () => { return foundMixers; }, []); - const refreshMixer = useCallback((mixers, currentAllMixers) => { - if (!mixers || !mixers.mixer) return null; + const refreshMixer = useCallback( + (mixers, currentAllMixers) => { + if (!mixers || !mixers.mixer) return null; - let updateMixers = null; - if (Array.isArray(mixers.mixer)) { - if (mixers.mixer.length > 0) { - updateMixers = []; - for (const mixer of mixers.mixer) { - updateMixers.push(getMixer(mixer.id, mixer.mode, currentAllMixers)); + let updateMixers = null; + if (Array.isArray(mixers.mixer)) { + if (mixers.mixer.length > 0) { + updateMixers = []; + for (const mixer of mixers.mixer) { + updateMixers.push(getMixer(mixer.id, mixer.mode, currentAllMixers)); + } } + } else { + updateMixers = getMixer(mixers.mixer.id, mixers.mixer.mode, currentAllMixers); } - } else { - updateMixers = getMixer(mixers.mixer.id, mixers.mixer.mode, currentAllMixers); - } - let updatedVUMixers = null; - if (Array.isArray(mixers.vuMixer)) { - updatedVUMixers = []; - for (const vuMixer of mixers.vuMixer) { - updatedVUMixers.push(getMixer(vuMixer.id, vuMixer.mode, currentAllMixers)); + let updatedVUMixers = null; + if (Array.isArray(mixers.vuMixer)) { + updatedVUMixers = []; + for (const vuMixer of mixers.vuMixer) { + updatedVUMixers.push(getMixer(vuMixer.id, vuMixer.mode, currentAllMixers)); + } + } else { + updatedVUMixers = getMixer(mixers.vuMixer.id, mixers.vuMixer.mode, currentAllMixers); } - } else { - updatedVUMixers = getMixer(mixers.vuMixer.id, mixers.vuMixer.mode, currentAllMixers); - } - let updateMuteMixers = null; - if (Array.isArray(mixers.muteMixer)) { - updateMuteMixers = []; - for (const muteMixer of mixers.muteMixer) { - updateMuteMixers.push(getMixer(muteMixer.id, muteMixer.mode, currentAllMixers)); + let updateMuteMixers = null; + if (Array.isArray(mixers.muteMixer)) { + updateMuteMixers = []; + for (const muteMixer of mixers.muteMixer) { + updateMuteMixers.push(getMixer(muteMixer.id, muteMixer.mode, currentAllMixers)); + } + } else { + updateMuteMixers = getMixer(mixers.muteMixer.id, mixers.muteMixer.mode, currentAllMixers); } - } else { - updateMuteMixers = getMixer(mixers.muteMixer.id, mixers.muteMixer.mode, currentAllMixers); - } - const oppositeMixer = mixers.oppositeMixer ? getMixer(mixers.oppositeMixer.id, mixers.oppositeMixer.mode, currentAllMixers) : null; + const oppositeMixer = mixers.oppositeMixer + ? getMixer(mixers.oppositeMixer.id, mixers.oppositeMixer.mode, currentAllMixers) + : null; - if (updateMixers) { - return { - mixer: updateMixers, - vuMixer: updatedVUMixers, - muteMixer: updateMuteMixers, - oppositeMixer: oppositeMixer - }; - } else { - return null; - } - }, [getMixer]); + if (updateMixers) { + return { + mixer: updateMixers, + vuMixer: updatedVUMixers, + muteMixer: updateMuteMixers, + oppositeMixer: oppositeMixer + }; + } else { + return null; + } + }, + [getMixer] + ); const recordingName = useCallback(() => { return currentSession.recordingName(); @@ -996,7 +1192,6 @@ const useMixerHelper = () => { return currentSession.jamTrackName(); }, [currentSession]); - return { isReady, session: currentSession, // Return currentSession from Redux instead of local state @@ -1021,6 +1216,6 @@ const useMixerHelper = () => { jamTracks, recordedTracks }; -} +}; export default useMixerHelper;