import React from 'react'; import { FaMousePointer, FaPencilAlt } from 'react-icons/fa'; import { TbArrowBarToUp } from 'react-icons/tb'; import { KGDropdown } from '../common'; import { KGPianoRollState } from '../../core/state/KGPianoRollState'; import { KGCore } from '../../core/KGCore'; import { PIANO_ROLL_AUTOMATION_OPTIONS, type PianoRollAutomationType, } from './pianoRollAutomation'; const POWER_OPTIONS = [ { label: 'Linear', value: '1.0' }, { label: '√ (default)', value: '0.5' }, { label: 'Mild', value: '0.4' }, { label: 'Strong', value: '0.3' }, ]; interface PianoRollToolbarProps { sheetMusicViewEnabled?: boolean; onSheetMusicViewToggle?: () => void; sheetMusicTrackScopeEnabled?: boolean; onSheetMusicTrackScopeToggle?: () => void; sheetQuantization?: string; onSheetQuantizationChange?: (value: string) => void; sheetQuantizationOptions?: string[]; activeTool: 'pointer' | 'pencil'; onToolSelect: (tool: 'pointer' | 'pencil') => void; quantPosition: string; quantLength: string; onQuantSelect: (type: 'position' | 'length', value: string) => void; snapping: string; onSnappingSelect: (value: string) => void; selectedMode: string; onModeChange: (value: string) => void; chordGuide: string; onChordGuideChange: (value: string) => void; blinkButton?: string | null; mode?: 'midi-edit' | 'spectrogram' | 'hybrid'; thresholdDb?: number; onThresholdChange?: (db: number) => void; power?: number; onPowerChange?: (power: number) => void; zoom: number; onZoomChange: (value: number) => void; showAutomationControls?: boolean; automationEnabled?: boolean; automationType?: PianoRollAutomationType; onAutomationToggle?: () => void; onAutomationTypeChange?: (value: PianoRollAutomationType) => void; onDetectChords?: () => void | Promise; detectingChords?: boolean; } const PianoRollToolbar: React.FC = ({ sheetMusicViewEnabled = false, onSheetMusicViewToggle, sheetMusicTrackScopeEnabled = false, onSheetMusicTrackScopeToggle, sheetQuantization = '16,48', onSheetQuantizationChange, sheetQuantizationOptions = [], activeTool, onToolSelect, quantPosition, quantLength, onQuantSelect, snapping, onSnappingSelect, selectedMode, onModeChange, chordGuide, onChordGuideChange, blinkButton = null, mode = 'midi-edit', thresholdDb = -25, onThresholdChange, power = 0.5, onPowerChange, zoom, onZoomChange, showAutomationControls = false, automationEnabled = false, automationType = 'pitch-bend', onAutomationToggle, onAutomationTypeChange, onDetectChords, detectingChords = false, }) => { const showMidiControls = mode !== 'spectrogram' && !sheetMusicViewEnabled; // midi-edit and hybrid const showSpecControls = !sheetMusicViewEnabled && (mode === 'spectrogram' || mode === 'hybrid'); const [showZoomSlider, setShowZoomSlider] = React.useState(false); const zoomSliderRef = React.useRef(null); React.useEffect(() => { if (!showZoomSlider) return; const handleClickOutside = (e: MouseEvent) => { if (zoomSliderRef.current && !zoomSliderRef.current.contains(e.target as Node)) { setShowZoomSlider(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [showZoomSlider]); const [showSpecMenu, setShowSpecMenu] = React.useState(false); const specMenuRef = React.useRef(null); React.useEffect(() => { if (!showSpecMenu) return; const handleClickOutside = (e: MouseEvent) => { if (specMenuRef.current && !specMenuRef.current.contains(e.target as Node)) { setShowSpecMenu(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [showSpecMenu]); return (
{showMidiControls && (
{showAutomationControls && (
onAutomationTypeChange?.(value as PianoRollAutomationType)} label="Automation" buttonClassName="automation-type-dropdown" showValueAsLabel={true} />
)} ({ label: data.name, value: id }))} value={selectedMode} onChange={(value) => onModeChange(value)} label="Mode" buttonClassName="mode-dropdown" showValueAsLabel={true} /> onChordGuideChange(value)} label="Chord" buttonClassName="chord-guide-dropdown" showValueAsLabel={true} />
)} {sheetMusicViewEnabled && (
{mode !== 'spectrogram' && ( )}
)}
{sheetMusicViewEnabled && ( onSheetQuantizationChange?.(value)} label="Sheet Quant." buttonClassName="sheet-quantization" showValueAsLabel={true} /> )} {showMidiControls && ( <> onSnappingSelect(value)} label="Snap" buttonClassName="snapping" showValueAsLabel={true} /> onQuantSelect('position', value)} label="Qua. Pos." buttonClassName={`quant-position ${blinkButton === 'quant-position' ? 'button-blink' : ''}`} /> onQuantSelect('length', value)} label="Qua. Len." buttonClassName={`quant-length ${blinkButton === 'quant-length' ? 'button-blink' : ''}`} /> )} {showSpecControls && (
Floor onThresholdChange?.(parseInt(e.target.value))} title={`Noise floor: ${thresholdDb} dB`} /> {thresholdDb} dB onPowerChange?.(parseFloat(v))} label="Curve" buttonClassName="curve-dropdown" showValueAsLabel={true} />
)} {!sheetMusicViewEnabled && (
{showZoomSlider && (
onZoomChange(parseInt(e.target.value))} /> {zoom}x
)}
)} {showSpecControls && (
{showSpecMenu && (
{ if (!onDetectChords || detectingChords) { return; } setShowSpecMenu(false); void onDetectChords(); }} aria-disabled={!onDetectChords || detectingChords} > {detectingChords ? 'Detecting chords...' : 'Detect chords...'}
)}
)}
); }; export default PianoRollToolbar;