diff --git a/jam-ui/src/components/client/JKSessionMyTrack.js b/jam-ui/src/components/client/JKSessionMyTrack.js
index b4aa54ba6..598d4e7f6 100644
--- a/jam-ui/src/components/client/JKSessionMyTrack.js
+++ b/jam-ui/src/components/client/JKSessionMyTrack.js
@@ -6,6 +6,7 @@ import SessionTrackVU from './SessionTrackVU';
import SessionTrackGain from './SessionTrackGain';
import TrackDiagnostics from './TrackDiagnostics';
import JKSessionInstrumentModal from './JKSessionInstrumentModal';
+import JKSessionPluginModal from './JKSessionPluginModal';
import { UncontrolledTooltip } from 'reactstrap';
import { getInstrumentName } from '../../helpers/utils';
import { ASSIGNMENT } from '../../helpers/globals';
@@ -19,6 +20,7 @@ const JKSessionMyTrack = ({ track, mixers, hasMixer, name, trackName, instrument
const [showMenu, setShowMenu] = useState(false);
const [showDiagnostics, setShowDiagnostics] = useState(false);
const [showInstrumentModal, setShowInstrumentModal] = useState(false);
+ const [showPluginModal, setShowPluginModal] = useState(false);
useEffect(() => {
if (mixers?.mixer) {
@@ -75,9 +77,6 @@ const JKSessionMyTrack = ({ track, mixers, hasMixer, name, trackName, instrument
>
-
- remote?: {JSON.stringify(isRemote)}
-
)}
@@ -134,12 +133,19 @@ const JKSessionMyTrack = ({ track, mixers, hasMixer, name, trackName, instrument
{!isRemote && (
-
+ <>
+
+ setShowPluginModal(false)}
+ trackNumber={ASSIGNMENT.TRACK1}
+ />
+ >
)}
);
diff --git a/jam-ui/src/components/client/JKSessionPluginModal.js b/jam-ui/src/components/client/JKSessionPluginModal.js
new file mode 100644
index 000000000..6a09c0a9f
--- /dev/null
+++ b/jam-ui/src/components/client/JKSessionPluginModal.js
@@ -0,0 +1,167 @@
+import React, { useState, useEffect } from 'react';
+import {
+ Modal,
+ ModalHeader,
+ ModalBody,
+ ModalFooter,
+ Button,
+ Form,
+ FormGroup,
+ Label,
+ Input,
+} from 'reactstrap';
+import { useJamClient } from '../../context/JamClientContext';
+
+const JKSessionPluginModal = ({ isOpen, toggle, trackNumber = 1 }) => {
+ const jamClient = useJamClient();
+ const [selectedPlugin, setSelectedPlugin] = useState('');
+ const [availablePlugins, setAvailablePlugins] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+
+ useEffect(() => {
+ if (isOpen) {
+ loadAvailablePlugins();
+ }
+ }, [isOpen]);
+
+ const loadAvailablePlugins = async () => {
+ try {
+ setIsLoading(true);
+ const plugins = await jamClient.VSTListVsts();
+ setAvailablePlugins(plugins || []);
+ } catch (error) {
+ console.error('Failed to load VST plugins:', error);
+ setAvailablePlugins([]);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handlePluginChange = async (event) => {
+ const pluginId = event.target.value;
+ setSelectedPlugin(pluginId);
+
+ if (pluginId) {
+ try {
+ await jamClient.VSTSetTrackAssignment(trackNumber, pluginId);
+ } catch (error) {
+ console.error('Failed to assign VST plugin:', error);
+ }
+ }
+ };
+
+ const handleOpenPluginApp = () => {
+ // Placeholder for opening plugin app
+ console.log('Open Plugin App clicked');
+ };
+
+ const handleScanPlugins = async () => {
+ try {
+ setIsLoading(true);
+ await jamClient.VSTScan(() => {
+ // Callback after scan completes
+ loadAvailablePlugins();
+ });
+ } catch (error) {
+ console.error('Failed to scan for plugins:', error);
+ setIsLoading(false);
+ }
+ };
+
+ const handleManageFolders = async () => {
+ try {
+ const paths = await jamClient.VSTListSearchPaths();
+ console.log('Current search paths:', paths);
+ // TODO: Implement folder management UI
+ } catch (error) {
+ console.error('Failed to get search paths:', error);
+ }
+ };
+
+ const handleClearPluginList = async () => {
+ if (window.confirm('Are you sure you want to clear the plugin list?')) {
+ try {
+ await jamClient.VSTClearAll();
+ setAvailablePlugins([]);
+ setSelectedPlugin('');
+ } catch (error) {
+ console.error('Failed to clear plugin list:', error);
+ }
+ }
+ };
+
+ return (
+
+
+ VST/AU Virtual Instrument
+
+
+
+
+
+
+
+
+ );
+};
+
+export default JKSessionPluginModal;
diff --git a/jam-ui/src/components/client/SessionTrackGain.js b/jam-ui/src/components/client/SessionTrackGain.js
index 107b7d843..c27db49f5 100644
--- a/jam-ui/src/components/client/SessionTrackGain.js
+++ b/jam-ui/src/components/client/SessionTrackGain.js
@@ -1,15 +1,10 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';
+import PropTypes from 'prop-types';
import './VolumeSlider.css'; // Keep the same CSS for now
import { useMixersContext } from '../../context/MixersContext';
import useFaderHelpers from '../../hooks/useFaderHelpers';
-const SessionTrackGain = ({
- mixers,
- gainType,
- controlGroup,
- sessionController,
- orientation = 'vertical'
-}) => {
+const SessionTrackGain = ({ mixers, gainType, controlGroup, sessionController, orientation = 'vertical' }) => {
//console.debug("SessionTrackGain: Rendering for mixers", mixers, "gainType", gainType, "controlGroup", controlGroup);
const mixerHelper = useMixersContext();
@@ -35,6 +30,7 @@ const SessionTrackGain = ({
}, [getMixer, faderHelpers]);
const [currentValue, setCurrentValue] = useState(getInitialValue);
+ const [displayedVolume, setDisplayedVolume] = useState(getMixer()?.volume_left || 0);
const prevVolumeRef = useRef();
// Update value when mixer changes or volume changes
@@ -48,69 +44,80 @@ const SessionTrackGain = ({
if (mixer && currentVolume !== undefined) {
const newValue = faderHelpers.convertAudioTaperToPercent(currentVolume);
- console.log("SessionTrackGain: initial value", newValue);
+ console.log('SessionTrackGain: initial value', newValue);
setCurrentValue(newValue);
+ setDisplayedVolume(currentVolume);
mixerHelper.initGain(mixer);
} else {
setCurrentValue(50); // fallback
+ setDisplayedVolume(0);
}
}
}, [mixers, faderHelpers, mixerHelper]);
-
// Function to calculate and update the slider's position and value
- const updateSlider = useCallback(async (clientPos) => {
- if (!sliderTrackRef.current) return;
+ const updateSlider = useCallback(
+ async clientPos => {
+ if (!sliderTrackRef.current) return;
- const trackRect = sliderTrackRef.current.getBoundingClientRect();
- let positionInTrack, trackSize;
+ const trackRect = sliderTrackRef.current.getBoundingClientRect();
+ let positionInTrack, trackSize;
- if (orientation === 'vertical') {
- // Calculate position from the BOTTOM of the track
- positionInTrack = trackRect.bottom - clientPos;
- trackSize = trackRect.height;
- } else {
- // Calculate position from the LEFT of the track
- positionInTrack = clientPos - trackRect.left;
- trackSize = trackRect.width;
- }
+ if (orientation === 'vertical') {
+ // Calculate position from the BOTTOM of the track
+ positionInTrack = trackRect.bottom - clientPos;
+ trackSize = trackRect.height;
+ } else {
+ // Calculate position from the LEFT of the track
+ positionInTrack = clientPos - trackRect.left;
+ trackSize = trackRect.width;
+ }
- // Clamp the position within the valid track bounds (0 to trackSize)
- const clampedPosition = Math.max(0, Math.min(positionInTrack, trackSize));
+ // Clamp the position within the valid track bounds (0 to trackSize)
+ const clampedPosition = Math.max(0, Math.min(positionInTrack, trackSize));
- // Calculate the percentage
- const percentage = clampedPosition / trackSize * 100;
+ // Calculate the percentage
+ const percentage = (clampedPosition / trackSize) * 100;
- // Update the mixer - now mixers is a real mixer object directly
- if (mixers) {
- await mixerHelper.faderChanged(
- { percentage, dragging: isDragging },
- mixers, // Pass the real mixer object directly
- gainType,
- controlGroup
- );
- }
+ // Update the mixer - now mixers is a real mixer object directly
+ if (mixers) {
+ await mixerHelper.faderChanged(
+ { percentage, dragging: isDragging },
+ mixers, // Pass the real mixer object directly
+ gainType,
+ controlGroup
+ );
+ }
- console.log("SessionTrackGain: updateSlider", { clientPos, clampedPosition, percentage });
+ console.log('SessionTrackGain: updateSlider', { clientPos, clampedPosition, percentage });
- // Update local state for UI
- setCurrentValue(Math.round(percentage));
+ // Update local state for UI
+ setCurrentValue(Math.round(percentage));
- // Directly manipulating the DOM for immediate visual updates during drag
- if (orientation === 'vertical') {
- sliderThumbRef.current.style.bottom = `${clampedPosition}px`;
- sliderFillRef.current.style.height = `${clampedPosition}px`;
- } else {
- sliderThumbRef.current.style.left = `${clampedPosition}px`;
- sliderFillRef.current.style.width = `${clampedPosition}px`;
- }
- }, [orientation, mixers, gainType, controlGroup, mixerHelper, isDragging]);
+ // Update displayed volume during dragging
+ const newVolumeDb = faderHelpers.convertPercentToAudioTaper(percentage);
+ setDisplayedVolume(newVolumeDb);
+
+ // Directly manipulating the DOM for immediate visual updates during drag
+ if (orientation === 'vertical') {
+ sliderThumbRef.current.style.bottom = `${clampedPosition}px`;
+ sliderFillRef.current.style.height = `${clampedPosition}px`;
+ } else {
+ sliderThumbRef.current.style.left = `${clampedPosition}px`;
+ sliderFillRef.current.style.width = `${clampedPosition}px`;
+ }
+ },
+ [orientation, mixers, faderHelpers, mixerHelper, isDragging, gainType, controlGroup]
+ );
// Mouse Move and Up Handlers (Global listeners)
- const handleMouseMove = useCallback((e) => {
- e.preventDefault(); // Prevent text selection
- updateSlider(orientation === 'vertical' ? e.clientY : e.clientX);
- }, [updateSlider, orientation]);
+ const handleMouseMove = useCallback(
+ e => {
+ e.preventDefault(); // Prevent text selection
+ updateSlider(orientation === 'vertical' ? e.clientY : e.clientX);
+ },
+ [updateSlider, orientation]
+ );
const handleMouseUp = useCallback(() => {
setIsDragging(false);
@@ -122,7 +129,7 @@ const SessionTrackGain = ({
}, [handleMouseMove]);
// Mouse Down Handler (Starts the drag)
- const handleMouseDown = (e) => {
+ const handleMouseDown = e => {
e.preventDefault();
setIsDragging(true);
// Add global listeners when dragging starts
@@ -134,7 +141,7 @@ const SessionTrackGain = ({
};
// Click on Track Handler (Jump to value)
- const handleTrackClick = (e) => {
+ const handleTrackClick = e => {
updateSlider(orientation === 'vertical' ? e.clientY : e.clientX);
};
@@ -157,19 +164,32 @@ const SessionTrackGain = ({
return (
-
{getMixer()?.volume_left || 0}db
-
+
+ {displayedVolume}db
+
+
);
};
+SessionTrackGain.propTypes = {
+ mixers: PropTypes.object,
+ gainType: PropTypes.string,
+ controlGroup: PropTypes.string,
+ sessionController: PropTypes.object,
+ orientation: PropTypes.string
+};
+
export default SessionTrackGain;