fix(ui): persist VST plugin selection across page reloads

- Use FTUESave(true) instead of TrackSaveAssignments() to properly
  persist VST assignments to the profile file
- Always call VSTLoad() when modal opens if VST not already loaded,
  removing unreliable hasVstAssignment() check
- Pass correct trackIndex to JKSessionPluginModal for multi-track support
- Add trackIndex prop to track data in useMixerHelper for VST operations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-02-18 17:58:52 +05:30
parent 78cdafbb8a
commit c344decea4
3 changed files with 51 additions and 11 deletions

View File

@ -21,6 +21,7 @@ import pluginIcon from '../../assets/img/client/plugin.svg';
const JKSessionMyTrack = ({
track,
trackIndex = 0, // 0-based index for native client VST operations
mixers,
hasMixer,
name,
@ -314,7 +315,7 @@ const JKSessionMyTrack = ({
<JKSessionPluginModal
isOpen={showPluginModal}
toggle={() => setShowPluginModal(false)}
trackNumber={ASSIGNMENT.TRACK1}
trackNumber={trackIndex + 1}
/>
</>
)}

View File

@ -10,7 +10,6 @@ import {
Label,
Input,
Spinner,
Alert,
} from 'reactstrap';
import { useJamClient } from '../../context/JamClientContext';
import JKSessionPluginFoldersModal from './JKSessionPluginFoldersModal';
@ -34,18 +33,34 @@ const JKSessionPluginModal = ({ isOpen, toggle, trackNumber = 1 }) => {
const loadAvailablePlugins = async () => {
try {
setIsLoading(true);
// Load the audio profile configuration first to restore saved VST assignments
const profileName = await jamClient.LastUsedProfileName();
if (profileName) {
await jamClient.FTUELoadAudioConfiguration(profileName);
}
// Always try to load VST assignments from profile after loading profile config
const isVstLoaded = await jamClient.IsVstLoaded();
if (!isVstLoaded) {
await jamClient.VSTLoad();
// Give the native client time to load the VST
await new Promise(resolve => setTimeout(resolve, 500));
}
const pluginsResponse = await jamClient.VSTListVsts();
const plugins = pluginsResponse?.vsts || [];
setAvailablePlugins(plugins);
console.log('loadAvailablePlugins Available plugins:', plugins);
// Load current track assignments
const assignmentsResponse = await jamClient.VSTListTrackAssignments();
console.log('loadAvailablePlugins Current track assignments:', assignmentsResponse);
const assignments = assignmentsResponse?.vsts || [];
const currentAssignment = assignments.find(assignment => assignment.track === trackNumber - 1);
const targetTrackIndex = trackNumber - 1;
const currentAssignment = assignments.find(assignment => assignment.track === targetTrackIndex);
if (currentAssignment) {
setSelectedPlugin(currentAssignment.id || currentAssignment.file || '');
setSelectedPlugin(currentAssignment.file || '');
} else {
setSelectedPlugin('');
}
@ -60,7 +75,6 @@ const JKSessionPluginModal = ({ isOpen, toggle, trackNumber = 1 }) => {
const handlePluginChange = async (event) => {
const pluginFile = event.target.value;
setSelectedPlugin(pluginFile);
const selectedPluginObj = availablePlugins.find(plugin =>
@ -69,8 +83,22 @@ const JKSessionPluginModal = ({ isOpen, toggle, trackNumber = 1 }) => {
if (pluginFile && selectedPluginObj) {
try {
console.log('handlePluginChange Selected plugin object:', selectedPluginObj, 'for track number: ', trackNumber - 1);
// Establish profile context first
const profileName = await jamClient.LastUsedProfileName();
if (profileName) {
await jamClient.FTUELoadAudioConfiguration(profileName);
}
// Set the VST assignment
await jamClient.VSTSetTrackAssignment(selectedPluginObj, trackNumber - 1);
// Save the entire profile to persist VST assignment
// FTUESave(true) persists the profile to disk
try {
await jamClient.FTUESave(true);
} catch (saveError) {
console.warn('FTUESave failed:', saveError);
}
} catch (error) {
console.error('Failed to assign VST plugin:', error);
}
@ -90,7 +118,6 @@ const JKSessionPluginModal = ({ isOpen, toggle, trackNumber = 1 }) => {
setLoadingText('scanning');
setIsLoading(true);
await jamClient.VSTScan("window.ConfigureTracksStore.onVstScanComplete");
// Callback after scan completes
setIsLoading(false);
setLoadingText('');
loadAvailablePlugins();

View File

@ -524,15 +524,25 @@ const useMixerHelper = () => {
const name = participant.user.name;
// Get VST track assignments
// First ensure VST is loaded from persistent storage (needed after page reload)
let vstTrackAssignments = { vsts: [] };
try {
const isVstLoaded = jamClient.IsVstLoaded();
const hasVstAssignment = jamClient.hasVstAssignment();
if (hasVstAssignment && !isVstLoaded) {
// Load VST from persistent storage - this is async but we proceed anyway
// The UI will update on next render cycle after VST loads
jamClient.VSTLoad();
}
const assignments = jamClient.VSTListTrackAssignments();
vstTrackAssignments = assignments || { vsts: [] };
} catch (error) {
console.warn("Failed to get VST track assignments:", error);
}
for (const track of participant.tracks || []) {
const participantTracks = participant.tracks || [];
for (let trackIndex = 0; trackIndex < participantTracks.length; trackIndex++) {
const track = participantTracks[trackIndex];
// Get mixers for BOTH modes to support independent Audio Mix (personal) and Session Mix (master) controls
const masterMixerData = findMixerForTrack(participant.client_id, track, true, MIX_MODES.MASTER);
const personalMixerData = findMixerForTrack(participant.client_id, track, true, MIX_MODES.PERSONAL);
@ -543,8 +553,9 @@ const useMixerHelper = () => {
const trackName = name;
// 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 === track.client_track_id)
? vstTrackAssignments.vsts.some(vst => vst.track === trackIndex)
: false;
tracks.push({
@ -552,6 +563,7 @@ const useMixerHelper = () => {
...track,
hasVst
},
trackIndex, // 0-based index for native client VST operations
mixerFinder: [participant.client_id, track, true],
mixers: mixerData,
// Store both master and personal mixers for independent control