238 lines
6.8 KiB
JavaScript
238 lines
6.8 KiB
JavaScript
import { useCallback } from 'react';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import {
|
|
openBackingTrack as openBackingTrackThunk,
|
|
loadJamTrack as loadJamTrackThunk,
|
|
closeMedia as closeMediaThunk,
|
|
clearJamTrackState,
|
|
updateJamTrackState
|
|
} from '../store/features/mediaSlice';
|
|
import {
|
|
setMetronome,
|
|
setMetronomeSettings,
|
|
updateMediaSummary
|
|
} from '../store/features/mixersSlice';
|
|
import {
|
|
setShowMyMixes,
|
|
toggleMyMixes as toggleMyMixesAction,
|
|
setShowCustomMixes,
|
|
toggleCustomMixes as toggleCustomMixesAction,
|
|
setEditingMixdownId,
|
|
setCreatingMixdown,
|
|
setCreateMixdownErrors
|
|
} from '../store/features/sessionUISlice';
|
|
import { selectSessionId } from '../store/features/activeSessionSlice';
|
|
import { useJamServerContext } from '../context/JamServerContext';
|
|
import { syncTracksToServer } from '../services/trackSyncService';
|
|
|
|
/**
|
|
* Custom hook that provides Redux-based media actions
|
|
* Replaces MediaContext actions with Redux thunks and dispatchers
|
|
*/
|
|
const useMediaActions = () => {
|
|
const dispatch = useDispatch();
|
|
const sessionId = useSelector(selectSessionId);
|
|
const { jamClient } = useJamServerContext();
|
|
|
|
/**
|
|
* Open a backing track file
|
|
* @param {string} file - Path to the backing track file
|
|
*/
|
|
const openBackingTrack = useCallback(async (file) => {
|
|
try {
|
|
await dispatch(openBackingTrackThunk({ file, jamClient })).unwrap();
|
|
|
|
// Update media summary
|
|
dispatch(updateMediaSummary({
|
|
backingTrackOpen: true,
|
|
userNeedsMediaControls: true
|
|
}));
|
|
|
|
// Sync tracks to server after opening backing track
|
|
if (sessionId && jamClient) {
|
|
console.log('[Track Sync] Backing track opened, syncing tracks');
|
|
dispatch(syncTracksToServer(sessionId, jamClient));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error opening backing track:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient, sessionId]);
|
|
|
|
/**
|
|
* Close all media (backing tracks, jam tracks, recordings, metronome)
|
|
* @param {boolean} force - Force close even if media is playing
|
|
*/
|
|
const closeMedia = useCallback(async (force = false) => {
|
|
try {
|
|
await dispatch(closeMediaThunk({ force, jamClient })).unwrap();
|
|
|
|
// Update media summary
|
|
dispatch(updateMediaSummary({
|
|
mediaOpen: false,
|
|
backingTrackOpen: false,
|
|
jamTrackOpen: false,
|
|
recordingOpen: false,
|
|
metronomeOpen: false,
|
|
userNeedsMediaControls: false
|
|
}));
|
|
} catch (error) {
|
|
console.error('Error closing media:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient]);
|
|
|
|
/**
|
|
* Open metronome with specified settings
|
|
* @param {number} bpm - Beats per minute (default: 120)
|
|
* @param {string} sound - Metronome sound type (default: "Beep")
|
|
* @param {number} meter - Time signature meter (default: 1)
|
|
* @param {number} mode - Metronome mode (default: 0)
|
|
*/
|
|
const openMetronome = useCallback(async (bpm = 120, sound = "Beep", meter = 1, mode = 0) => {
|
|
try {
|
|
const result = await jamClient.SessionOpenMetronome(bpm, sound, meter, mode);
|
|
|
|
// Update Redux state
|
|
dispatch(setMetronome({ bpm, sound, meter, mode }));
|
|
dispatch(setMetronomeSettings({ tempo: bpm, sound, cricket: mode === 1 }));
|
|
dispatch(updateMediaSummary({
|
|
metronomeOpen: true,
|
|
userNeedsMediaControls: true
|
|
}));
|
|
|
|
// Sync tracks to server after opening metronome
|
|
if (sessionId && jamClient) {
|
|
console.log('[Track Sync] Metronome opened, syncing tracks');
|
|
dispatch(syncTracksToServer(sessionId, jamClient));
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error('Error opening metronome:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient, sessionId]);
|
|
|
|
/**
|
|
* Close the metronome
|
|
*/
|
|
const closeMetronome = useCallback(async () => {
|
|
try {
|
|
await jamClient.SessionCloseMetronome();
|
|
|
|
// Update Redux state
|
|
dispatch(setMetronome(null));
|
|
dispatch(updateMediaSummary({
|
|
metronomeOpen: false
|
|
}));
|
|
|
|
// Sync tracks to server after closing metronome
|
|
if (sessionId && jamClient) {
|
|
console.log('[Track Sync] Metronome closed, syncing tracks');
|
|
dispatch(syncTracksToServer(sessionId, jamClient));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error closing metronome:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient, sessionId]);
|
|
|
|
/**
|
|
* Load and play a JamTrack
|
|
* @param {object} jamTrack - JamTrack object with id and optional jmep data
|
|
*/
|
|
const loadJamTrack = useCallback(async (jamTrack) => {
|
|
try {
|
|
await dispatch(loadJamTrackThunk({ jamTrack, jamClient })).unwrap();
|
|
|
|
// Update media summary
|
|
dispatch(updateMediaSummary({
|
|
jamTrackOpen: true,
|
|
userNeedsMediaControls: true
|
|
}));
|
|
|
|
// Sync tracks to server after opening jam track
|
|
if (sessionId && jamClient) {
|
|
console.log('[Track Sync] Jam track opened, syncing tracks');
|
|
dispatch(syncTracksToServer(sessionId, jamClient));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading jam track:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient, sessionId]);
|
|
|
|
/**
|
|
* Stop and close the currently playing JamTrack
|
|
*/
|
|
const closeJamTrack = useCallback(async () => {
|
|
try {
|
|
await jamClient.JamTrackStopPlay();
|
|
|
|
// Update Redux state
|
|
dispatch(clearJamTrackState());
|
|
dispatch(updateMediaSummary({
|
|
jamTrackOpen: false
|
|
}));
|
|
} catch (error) {
|
|
console.error('Error closing jam track:', error);
|
|
throw error;
|
|
}
|
|
}, [dispatch, jamClient]);
|
|
|
|
/**
|
|
* Update JamTrack playback state (position, playing, etc.)
|
|
* @param {object} changes - JamTrack state changes
|
|
*/
|
|
const updateJamTrackPlayback = useCallback((changes) => {
|
|
dispatch(updateJamTrackState(changes));
|
|
}, [dispatch]);
|
|
|
|
// UI Actions
|
|
const toggleMyMixes = useCallback(() => {
|
|
dispatch(toggleMyMixesAction());
|
|
}, [dispatch]);
|
|
|
|
const toggleCustomMixes = useCallback(() => {
|
|
dispatch(toggleCustomMixesAction());
|
|
}, [dispatch]);
|
|
|
|
const editMixdown = useCallback((mixdownId) => {
|
|
dispatch(setEditingMixdownId(mixdownId));
|
|
}, [dispatch]);
|
|
|
|
const startCreatingMixdown = useCallback(() => {
|
|
dispatch(setCreatingMixdown(true));
|
|
}, [dispatch]);
|
|
|
|
const stopCreatingMixdown = useCallback(() => {
|
|
dispatch(setCreatingMixdown(false));
|
|
}, [dispatch]);
|
|
|
|
const setMixdownErrors = useCallback((errors) => {
|
|
dispatch(setCreateMixdownErrors(errors));
|
|
}, [dispatch]);
|
|
|
|
return {
|
|
// Core media actions
|
|
openBackingTrack,
|
|
closeMedia,
|
|
openMetronome,
|
|
closeMetronome,
|
|
loadJamTrack,
|
|
closeJamTrack,
|
|
updateJamTrackPlayback,
|
|
|
|
// UI actions
|
|
toggleMyMixes,
|
|
toggleCustomMixes,
|
|
editMixdown,
|
|
startCreatingMixdown,
|
|
stopCreatingMixdown,
|
|
setMixdownErrors
|
|
};
|
|
};
|
|
|
|
export default useMediaActions;
|