feat: opened MIDI item notes darker than same-track siblings
This commit is contained in:
@@ -6256,14 +6256,14 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Layer 2: Ghost Notes (same-track = active amber, other tracks = reference)
|
||||
// Layer 2: Ghost Notes (same-track = lighter reference, other tracks = faint)
|
||||
if (showGhostNotes && sessionSyncMode && ghostLayers.length > 0) {
|
||||
ghostLayers.forEach(function(layer) {
|
||||
ctx.save();
|
||||
var isSameTrackLayer = layer.isSameTrack;
|
||||
ctx.globalAlpha = isSameTrackLayer ? 0.65 : 0.25;
|
||||
ctx.fillStyle = isSameTrackLayer ? 'rgba(251, 191, 36, 0.55)' : (layer.track_color || '#888');
|
||||
ctx.strokeStyle = isSameTrackLayer ? 'rgba(245, 158, 11, 0.9)' : (layer.track_color || '#888');
|
||||
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 snapStart = snapValue !== 'free' ? getSnapBeat(note.relative_start_beat, snapValue) : note.relative_start_beat;
|
||||
var rawEnd = note.relative_start_beat + note.duration_beats;
|
||||
@@ -6290,9 +6290,9 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
const isSelected = selectedNoteIds.includes(note.id);
|
||||
|
||||
// Draw background of note
|
||||
ctx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.4)' : 'rgba(234, 179, 8, 0.25)';
|
||||
ctx.strokeStyle = isSelected ? '#3b82f6' : '#ca8a04';
|
||||
ctx.lineWidth = isSelected ? 1.5 : 1;
|
||||
ctx.fillStyle = isSelected ? 'rgba(59, 130, 246, 0.5)' : 'rgba(234, 179, 8, 0.5)';
|
||||
ctx.strokeStyle = isSelected ? '#3b82f6' : '#f59e0b';
|
||||
ctx.lineWidth = isSelected ? 1.5 : 1.2;
|
||||
ctx.fillRect(x + 1, y + 1, w - 2, NoteHeight - 2);
|
||||
ctx.strokeRect(x + 1, y + 1, w - 2, NoteHeight - 2);
|
||||
|
||||
|
||||
@@ -180,9 +180,9 @@ const scrollBeat=mx/pixelsPerBeat-renderBeatOffset;const clickedNote=notes.find(
|
||||
const container=gridScrollRef.current;if(container)container.scrollLeft+=e.deltaY;}return;}if(e.altKey){e.preventDefault();const scrollDelta=e.deltaY;const beatSec=60.0/(parseInt(bpm)||120);const step=scrollDelta<0?-0.25:0.25;const currentBeat=(st.currentTime||0)/beatSec;const maxBeats=totalBeats;const newBeat=Math.max(0,Math.min(maxBeats,currentBeat+step));const newTime=newBeat*beatSec;setSubTabs(prev=>prev.map(s=>s.id===st.id?{...s,currentTime:newTime}:s));if(window.SonicSF){const ctx=getAudioContext();const playing=notes.filter(n=>currentBeat<n.start_beat&&newBeat>=n.start_beat);var pvTrk=activeTracks.find(function(t){return t.id===st.trackId;});var pvCh=window.SonicPianoRoll?window.SonicPianoRoll.getTrackMidiChannel(pvTrk,activeTracks):pvTrk?pvTrk.midiChannel:0;playing.forEach(n=>{window.SonicSF.playNote(n.pitch,(n.velocity||0.8)*127,200,ctx.currentTime,st.instrumentProgram,null,pvCh,pvTrk?pvTrk.synth_engine:undefined);});}}};const canvas=canvasRef.current;if(canvas){canvas.addEventListener('wheel',handleCanvasWheel,{passive:false});}return()=>{if(canvas){canvas.removeEventListener('wheel',handleCanvasWheel);}};},[notes,st.currentTime,pixelsPerBeat,st.id,totalBeats,bpm]);React.useLayoutEffect(()=>{const canvas=canvasRef.current;if(!canvas)return;const ctx=canvas.getContext('2d');const dpr=window.devicePixelRatio||1;const h=128*NoteHeight;canvas.width=viewWidth*dpr;canvas.height=h*dpr;ctx.scale(dpr,dpr);// Draw background rows
|
||||
for(let pitch=0;pitch<128;pitch++){const y=(127-pitch)*NoteHeight;const isBlack=[1,3,6,8,10].includes(pitch%12);ctx.fillStyle=isBlack?'#1a1a1e':'#25252a';ctx.fillRect(0,y,viewWidth,NoteHeight);ctx.strokeStyle='#2d2d35';ctx.lineWidth=0.5;ctx.beginPath();ctx.moveTo(0,y+NoteHeight);ctx.lineTo(viewWidth,y+NoteHeight);ctx.stroke();}// Draw snap lines
|
||||
let snapBeats=0.25;if(snapValue==='1')snapBeats=1.0;else if(snapValue==='1/2')snapBeats=0.5;else if(snapValue==='1/4')snapBeats=0.25;else if(snapValue==='1/8')snapBeats=0.125;else if(snapValue==='1/16')snapBeats=0.0625;else if(snapValue==='4')snapBeats=4.0;else if(snapValue==='1/32')snapBeats=0.03125;for(let beat=0;beat<=viewBeats;beat+=snapBeats){const x=beat*pixelsPerBeat;if(x>viewWidth)break;const isBar=beat%timeSigNum===0;ctx.strokeStyle=isBar?'#444450':'#2d2d35';ctx.lineWidth=isBar?1.2:0.6;ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,h);ctx.stroke();}// Layer 2: Ghost Notes (background reference from other tracks)
|
||||
if(showGhostNotes&&sessionSyncMode&&ghostLayers.length>0){ghostLayers.forEach(function(layer){ctx.save();var isSameTrackLayer=layer.isSameTrack;ctx.globalAlpha=isSameTrackLayer?0.65:0.25;ctx.fillStyle=isSameTrackLayer?'rgba(251, 191, 36, 0.55)':(layer.track_color||'#888');ctx.strokeStyle=isSameTrackLayer?'rgba(245, 158, 11, 0.9)':(layer.track_color||'#888');layer.notes.forEach(function(note){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;var x=(renderBeatOffset+snapStart)*pixelsPerBeat;var y=(127-note.pitch)*NoteHeight;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);});ctx.restore();});}// Layer 3: Active notes with velocity layer representation
|
||||
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 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;var x=(renderBeatOffset+snapStart)*pixelsPerBeat;var y=(127-note.pitch)*NoteHeight;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);});ctx.restore();});}// Layer 3: Active notes with velocity layer representation
|
||||
notes.forEach(note=>{const snapStart=snapValue!=='free'?getSnapBeat(note.start_beat,snapValue):note.start_beat;const rawEnd=note.start_beat+note.duration_beats;const snapEnd=snapValue!=='free'?getSnapBeat(rawEnd,snapValue):rawEnd;const x=(renderBeatOffset+snapStart)*pixelsPerBeat;const y=(127-note.pitch)*NoteHeight;const w=Math.max(2,(snapEnd-snapStart)*pixelsPerBeat);const isSelected=selectedNoteIds.includes(note.id);// Draw background of note
|
||||
ctx.fillStyle=isSelected?'rgba(59, 130, 246, 0.4)':'rgba(234, 179, 8, 0.25)';ctx.strokeStyle=isSelected?'#3b82f6':'#ca8a04';ctx.lineWidth=isSelected?1.5:1;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)
|
||||
ctx.fillStyle=isSelected?'rgba(59, 130, 246, 0.5)':'rgba(234, 179, 8, 0.5)';ctx.strokeStyle=isSelected?'#3b82f6':'#f59e0b';ctx.lineWidth=isSelected?1.5:1.2;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?'#3b82f6':'#eab308';ctx.fillRect(x+1,y+1,velW,NoteHeight-2);});// Draw real-time recording notes
|
||||
if(recordingState==='RECORDING'&&recTempMidiNotes&&recTempMidiNotes.length>0){recTempMidiNotes.forEach(note=>{const snapStart=snapValue!=='free'?getSnapBeat(note.start_beat,snapValue):note.start_beat;const rawEnd=note.start_beat+(note.duration_beats||0.25);const snapEnd=snapValue!=='free'?getSnapBeat(rawEnd,snapValue):rawEnd;const x=(renderBeatOffset+snapStart)*pixelsPerBeat;const y=(127-note.pitch)*NoteHeight;const w=Math.max(2,(snapEnd-snapStart)*pixelsPerBeat);ctx.fillStyle='rgba(255, 100, 100, 0.35)';ctx.strokeStyle='#ff6464';ctx.lineWidth=1;ctx.fillRect(x+1,y+1,Math.max(2,w-2),NoteHeight-2);ctx.strokeRect(x+1,y+1,Math.max(2,w-2),NoteHeight-2);const vel=Math.min(1,note.velocity||0.8);ctx.fillStyle='#ff6464';ctx.fillRect(x+1,y+1,Math.max(2,(w-2)*vel),NoteHeight-2);});}// Draw selection marquee if active
|
||||
if(selectionMarquee){const minBeat=Math.min(selectionMarquee.startBeat,selectionMarquee.currentBeat);const maxBeat=Math.max(selectionMarquee.startBeat,selectionMarquee.currentBeat);const minPitch=Math.min(selectionMarquee.startPitch,selectionMarquee.currentPitch);const maxPitch=Math.max(selectionMarquee.startPitch,selectionMarquee.currentPitch);const mx=minBeat*pixelsPerBeat;const my=(127-maxPitch)*NoteHeight;const mw=(maxBeat-minBeat)*pixelsPerBeat;const mh=(maxPitch-minPitch+1)*NoteHeight;ctx.fillStyle='rgba(59, 130, 246, 0.15)';ctx.strokeStyle='#3b82f6';ctx.lineWidth=1;ctx.setLineDash([4,4]);ctx.fillRect(mx,my,mw,mh);ctx.strokeRect(mx,my,mw,mh);ctx.setLineDash([]);}// Draw playhead
|
||||
|
||||
Reference in New Issue
Block a user