feat: per-MIDI-item focus brightness in piano roll
This commit is contained in:
+35
-11
@@ -6256,15 +6256,38 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Layer 2: Ghost Notes (same-track = lighter reference, other tracks = faint)
|
||||
// Determine which MIDI item is focused (selected note → opened item; playing → item under playhead)
|
||||
var focusedItemId = st.target_id;
|
||||
if (selectedNoteIds && selectedNoteIds.length > 0) {
|
||||
focusedItemId = st.target_id;
|
||||
} else if (st.isPlaying && st.currentTime != null && activeTracks) {
|
||||
var curSec = st.currentTime || 0;
|
||||
var fidxTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
|
||||
var itemsArr = fidxTrk ? (fidxTrk.midiItems || []) : [];
|
||||
for (var fi = 0; fi < itemsArr.length; fi++) {
|
||||
var fit = itemsArr[fi];
|
||||
var fStart = fit.startTime || 0;
|
||||
var fEnd = fStart + (fit.duration || 4);
|
||||
if (curSec >= fStart && curSec < fEnd) { focusedItemId = fit.id; break; }
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 2: Ghost Notes (same-track: focused item bright, siblings dim; other tracks faint)
|
||||
if (showGhostNotes && sessionSyncMode && ghostLayers.length > 0) {
|
||||
ghostLayers.forEach(function(layer) {
|
||||
ctx.save();
|
||||
var isSameTrackLayer = layer.isSameTrack;
|
||||
ctx.globalAlpha = isSameTrackLayer ? 0.35 : 0.25;
|
||||
ctx.fillStyle = isSameTrackLayer ? 'rgba(251, 191, 36, 0.35)' : (layer.track_color || '#888');
|
||||
ctx.strokeStyle = isSameTrackLayer ? 'rgba(245, 158, 11, 0.6)' : (layer.track_color || '#888');
|
||||
layer.notes.forEach(function(note) {
|
||||
var isFocusedNote = isSameTrackLayer && note.item_id === focusedItemId;
|
||||
if (isSameTrackLayer) {
|
||||
ctx.globalAlpha = isFocusedNote ? 0.7 : 0.3;
|
||||
ctx.fillStyle = isFocusedNote ? 'rgba(253, 224, 71, 0.7)' : 'rgba(251, 191, 36, 0.3)';
|
||||
ctx.strokeStyle = isFocusedNote ? '#fde047' : 'rgba(245, 158, 11, 0.6)';
|
||||
} else {
|
||||
ctx.globalAlpha = 0.25;
|
||||
ctx.fillStyle = layer.track_color || '#888';
|
||||
ctx.strokeStyle = layer.track_color || '#888';
|
||||
}
|
||||
var snapStart = snapValue !== 'free' ? getSnapBeat(note.relative_start_beat, snapValue) : note.relative_start_beat;
|
||||
var rawEnd = note.relative_start_beat + note.duration_beats;
|
||||
var snapEnd = snapValue !== 'free' ? getSnapBeat(rawEnd, snapValue) : rawEnd;
|
||||
@@ -6273,7 +6296,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
var w = Math.max(2, (snapEnd - snapStart) * pixelsPerBeat);
|
||||
var h = NoteHeight - 1;
|
||||
ctx.fillRect(x, y, w, h);
|
||||
if (isSameTrackLayer) ctx.strokeRect(x + 0.5, y + 0.5, w - 1, h - 1);
|
||||
if (isSameTrackLayer && isFocusedNote) ctx.strokeRect(x + 0.5, y + 0.5, w - 1, h - 1);
|
||||
});
|
||||
ctx.restore();
|
||||
});
|
||||
@@ -6289,18 +6312,19 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
const w = Math.max(2, (snapEnd - snapStart) * pixelsPerBeat);
|
||||
const isSelected = selectedNoteIds.includes(note.id);
|
||||
|
||||
// Draw background of note (focused item = brighter)
|
||||
// Draw background of note (focused item = brighter, siblings = dim)
|
||||
const playingNow = st.isPlaying;
|
||||
ctx.fillStyle = isSelected ? 'rgba(96, 165, 250, 0.6)' : (playingNow ? 'rgba(254, 240, 138, 0.75)' : 'rgba(253, 224, 71, 0.6)');
|
||||
ctx.strokeStyle = isSelected ? '#60a5fa' : (playingNow ? '#fef08a' : '#fde047');
|
||||
ctx.lineWidth = isSelected ? 1.5 : 1.2;
|
||||
const mainFocused = focusedItemId === st.target_id;
|
||||
ctx.fillStyle = isSelected ? 'rgba(96, 165, 250, 0.6)' : (mainFocused ? (playingNow ? 'rgba(254, 240, 138, 0.75)' : 'rgba(253, 224, 71, 0.6)') : 'rgba(120, 100, 40, 0.35)');
|
||||
ctx.strokeStyle = isSelected ? '#60a5fa' : (mainFocused ? (playingNow ? '#fef08a' : '#fde047') : '#8a7504');
|
||||
ctx.lineWidth = isSelected ? 1.5 : (mainFocused ? 1.2 : 0.8);
|
||||
ctx.fillRect(x + 1, y + 1, w - 2, NoteHeight - 2);
|
||||
ctx.strokeRect(x + 1, y + 1, w - 2, NoteHeight - 2);
|
||||
|
||||
// Draw velocity layer (solid yellow/blue bar inside, proportional to velocity)
|
||||
const vel = note.velocity !== undefined ? note.velocity : 0.8;
|
||||
const velW = Math.max(2, (w - 2) * vel);
|
||||
ctx.fillStyle = isSelected ? '#60a5fa' : (playingNow ? '#fde047' : '#facc15');
|
||||
ctx.fillStyle = isSelected ? '#60a5fa' : (mainFocused ? (playingNow ? '#fde047' : '#facc15') : '#7a6a10');
|
||||
ctx.fillRect(x + 1, y + 1, velW, NoteHeight - 2);
|
||||
});
|
||||
|
||||
@@ -6358,7 +6382,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}, [notes, snapValue, rollZoom, selectedNoteIds, selectionMarquee, st.currentTime, bpm, viewWidth, viewBeats, recordingState, recTempMidiNotes, showGhostNotes, sessionSyncMode, ghostLayers, renderBeatOffset, renderTick]);
|
||||
}, [notes, snapValue, rollZoom, selectedNoteIds, selectionMarquee, st.currentTime, bpm, viewWidth, viewBeats, recordingState, recTempMidiNotes, showGhostNotes, sessionSyncMode, ghostLayers, renderBeatOffset, renderTick, activeTracks]);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
const canvas = ccCanvasRef.current;
|
||||
|
||||
Reference in New Issue
Block a user