feat: implemented piano roll hybrid mode to allow user edit MIDI notes while observing spectrogram as reference
This commit is contained in:
@@ -140,6 +140,27 @@
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.region-hybrid-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 24px;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
color: #fff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 3px;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.region-hybrid-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
/* Instrument dropdown specific styles */
|
||||
.instrument-dropdown .quant-dropdown {
|
||||
min-width: 80px;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import './Region.css';
|
||||
import { FaPencilAlt } from 'react-icons/fa';
|
||||
import { FaPencilAlt, FaPlus } from 'react-icons/fa';
|
||||
import { MdGraphicEq } from 'react-icons/md';
|
||||
import type { ResizeAction } from '../interfaces';
|
||||
import { REGION_CONSTANTS, DEBUG_MODE } from '../../constants';
|
||||
@@ -30,6 +30,9 @@ interface RegionItemProps {
|
||||
onOpenPianoRoll?: (regionId: string) => void;
|
||||
// Open spectrogram viewer for audio regions
|
||||
onOpenSpectrogram?: (regionId: string) => void;
|
||||
// Enter hybrid mode (show + when piano roll is open with the opposite region type selected)
|
||||
showHybridButton?: boolean;
|
||||
onOpenHybrid?: (regionId: string) => void;
|
||||
// MIDI region data for rendering notes
|
||||
midiRegion?: KGMidiRegion;
|
||||
// Audio region data for rendering waveform
|
||||
@@ -53,6 +56,8 @@ const RegionItem: React.FC<RegionItemProps> = ({
|
||||
onClick,
|
||||
onOpenPianoRoll,
|
||||
onOpenSpectrogram,
|
||||
showHybridButton,
|
||||
onOpenHybrid,
|
||||
midiRegion,
|
||||
audioRegion,
|
||||
audioBuffer
|
||||
@@ -64,7 +69,7 @@ const RegionItem: React.FC<RegionItemProps> = ({
|
||||
const [resizeEdge, setResizeEdge] = useState<ResizeAction>('none');
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const initialMousePosRef = useRef<{x: number, y: number}>({x: 0, y: 0});
|
||||
const initialMousePosRef = useRef<{ x: number, y: number }>({ x: 0, y: 0 });
|
||||
// Use refs to track states for immediate access
|
||||
const isResizingRef = useRef<boolean>(false);
|
||||
const isDraggingRef = useRef<boolean>(false);
|
||||
@@ -600,6 +605,26 @@ const RegionItem: React.FC<RegionItemProps> = ({
|
||||
<MdGraphicEq size={10} />
|
||||
</button>
|
||||
)}
|
||||
{showHybridButton && (
|
||||
<button
|
||||
className="region-hybrid-btn"
|
||||
title="Open in hybrid mode"
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (onOpenHybrid) {
|
||||
onOpenHybrid(id);
|
||||
}
|
||||
}}
|
||||
aria-label="Open hybrid mode"
|
||||
>
|
||||
<FaPlus size={10} />
|
||||
</button>
|
||||
)}
|
||||
<canvas ref={canvasRef} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,6 +27,9 @@ interface TrackGridItemProps {
|
||||
onRegionClick?: (regionId: string) => void;
|
||||
onOpenPianoRoll?: (regionId: string) => void;
|
||||
onOpenSpectrogram?: (regionId: string) => void;
|
||||
showHybridButtonForAudio?: boolean;
|
||||
showHybridButtonForMidi?: boolean;
|
||||
onOpenHybrid?: (regionId: string) => void;
|
||||
allTracks?: KGTrack[]; // Added to access all tracks for drag operations
|
||||
onKGOneClipDrop?: (e: React.DragEvent<HTMLDivElement>, trackIndex: number) => void;
|
||||
}
|
||||
@@ -49,6 +52,9 @@ const TrackGridItem: React.FC<TrackGridItemProps> = ({
|
||||
onRegionClick,
|
||||
onOpenPianoRoll,
|
||||
onOpenSpectrogram,
|
||||
showHybridButtonForAudio,
|
||||
showHybridButtonForMidi,
|
||||
onOpenHybrid,
|
||||
allTracks,
|
||||
onKGOneClipDrop,
|
||||
}) => {
|
||||
@@ -571,6 +577,8 @@ const TrackGridItem: React.FC<TrackGridItemProps> = ({
|
||||
onOpenSpectrogram={audioRegion ? (regionId) => {
|
||||
onOpenSpectrogram?.(regionId);
|
||||
} : undefined}
|
||||
showHybridButton={audioRegion ? showHybridButtonForAudio : showHybridButtonForMidi}
|
||||
onOpenHybrid={onOpenHybrid}
|
||||
midiRegion={midiRegion}
|
||||
audioRegion={audioRegion}
|
||||
audioBuffer={audioBuffer}
|
||||
|
||||
@@ -31,6 +31,9 @@ interface TrackGridPanelProps {
|
||||
onRegionClick?: (regionId: string) => void;
|
||||
onOpenPianoRoll?: (regionId: string) => void;
|
||||
onOpenSpectrogram?: (regionId: string) => void;
|
||||
showHybridButtonForAudio?: boolean;
|
||||
showHybridButtonForMidi?: boolean;
|
||||
onOpenHybrid?: (regionId: string) => void;
|
||||
onExternalDropComplete?: (trackIndex: number, regionUI: RegionUI) => void;
|
||||
}
|
||||
|
||||
@@ -48,6 +51,9 @@ const TrackGridPanel: React.FC<TrackGridPanelProps> = ({
|
||||
onRegionClick,
|
||||
onOpenPianoRoll,
|
||||
onOpenSpectrogram,
|
||||
showHybridButtonForAudio,
|
||||
showHybridButtonForMidi,
|
||||
onOpenHybrid,
|
||||
onExternalDropComplete,
|
||||
}) => {
|
||||
const gridContainerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -654,6 +660,9 @@ const TrackGridPanel: React.FC<TrackGridPanelProps> = ({
|
||||
onRegionClick={handleRegionClick}
|
||||
onOpenPianoRoll={onOpenPianoRoll}
|
||||
onOpenSpectrogram={onOpenSpectrogram}
|
||||
showHybridButtonForAudio={showHybridButtonForAudio}
|
||||
showHybridButtonForMidi={showHybridButtonForMidi}
|
||||
onOpenHybrid={onOpenHybrid}
|
||||
allTracks={tracks}
|
||||
onKGOneClipDrop={handleExternalDrop}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user