fix: session-absolute timing for playhead + MIDI scheduling
- st.currentTime is now session-absolute (0 = session bar 0) - schedulePianoRollMidi adds sessionBeatOffset to note timing so notes at renderBeatOffset beats are scheduled with correct delay - Playhead rendering: removed renderBeatOffset (uses st.currentTime directly as session-absolute beats) - handleEditMidiInTab/handleSwitchMidiItem: currentTime = 0 - Ruler click: clickTime = clickBeat * beatSec (session-absolute)
This commit is contained in:
+14
-11
@@ -4646,7 +4646,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
var trk = (activeTracks || []).find(function(t) { return t.id === match._trackId; });
|
||||
var newBeatOff = (match.startTime / secondsPerBar) * timeSigNum;
|
||||
var spb = 60.0 / (parseInt(bpm) || 120);
|
||||
var newTime = -newBeatOff * spb;
|
||||
var newTime = 0;
|
||||
setSubTabs(function(prev) {
|
||||
return prev.map(function(s) {
|
||||
if (s.id !== st.id) return s;
|
||||
@@ -4986,7 +4986,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
|
||||
|
||||
// Draw playhead
|
||||
if (st.currentTime !== undefined && st.currentTime !== null) {
|
||||
const phBeat = renderBeatOffset + st.currentTime / (60.0 / (parseInt(bpm) || 120));
|
||||
const phBeat = st.currentTime / (60.0 / (parseInt(bpm) || 120));
|
||||
const phX = phBeat * pixelsPerBeat;
|
||||
if (phX >= 0 && phX <= viewWidth) {
|
||||
ctx.strokeStyle = '#f59e0b';
|
||||
@@ -6017,7 +6017,7 @@ const beatSec = 60.0 / (parseInt(bpm) || 120);
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left + e.currentTarget.scrollLeft;
|
||||
const clickBeat = x / pixelsPerBeat;
|
||||
const clickTime = (clickBeat - renderBeatOffset) * beatSec;
|
||||
const clickTime = clickBeat * beatSec;
|
||||
const clickInRange = loopStartBeat !== null && loopEndBeat !== null && clickBeat >= loopStartBeat && clickBeat <= loopEndBeat;
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
setLoopStartBeat(null);
|
||||
@@ -8282,10 +8282,6 @@ const App = () => {
|
||||
const tabLabel = `Piano Roll: ${midiItem.name || 'MIDI'}`;
|
||||
const ctx = getAudioContext();
|
||||
const silentBuffer = ctx.createBuffer(1, 128, ctx.sampleRate);
|
||||
var bpmVal = parseInt(bpm) || 120;
|
||||
var beatSec = 60.0 / bpmVal;
|
||||
var secPerBar = beatSec * 4;
|
||||
var beatOff = (midiItem.startTime / secPerBar) * 4;
|
||||
const newTab = {
|
||||
id: tabId,
|
||||
label: tabLabel,
|
||||
@@ -8298,7 +8294,7 @@ const App = () => {
|
||||
buffer: silentBuffer,
|
||||
instrumentProgram: track.instrumentProgram,
|
||||
instrumentName: track.instrumentName,
|
||||
currentTime: -beatOff * beatSec,
|
||||
currentTime: 0,
|
||||
isPlaying: false,
|
||||
selectionStart: null,
|
||||
selectionEnd: null,
|
||||
@@ -10403,8 +10399,15 @@ const App = () => {
|
||||
var allTracks = activeTracksRef.current || [];
|
||||
var mainCh = 0;
|
||||
for (var i = 0; i < allTracks.length; i++) { if (allTracks[i].id === st.trackId) { mainCh = i >= 9 ? i + 1 : i; if (mainCh >= 16) mainCh = 0; break; } }
|
||||
// Compute session beat offset from target item
|
||||
var sessionBeatOffset = 0;
|
||||
var targetTrk = allTracks.find(function(t) { return t.id === st.trackId; });
|
||||
if (targetTrk) {
|
||||
var targetIt = (targetTrk.midiItems || []).find(function(m) { return m.id === st.target_id; });
|
||||
if (targetIt) sessionBeatOffset = (targetIt.startTime / ((60.0 / bpmVal) * 4)) * 4;
|
||||
}
|
||||
midiNotes.forEach(note => {
|
||||
const noteOnBeat = note.start_beat || 0;
|
||||
const noteOnBeat = (note.start_beat || 0) + sessionBeatOffset;
|
||||
const noteDurBeat = note.duration_beats || 1;
|
||||
const noteStartSec = noteOnBeat * secondsPerBeat;
|
||||
const noteDurSec = noteDurBeat * secondsPerBeat;
|
||||
@@ -10424,12 +10427,12 @@ const App = () => {
|
||||
var ghostTrack = allTracks.find(function(t) { return t.id === layer.trackId; });
|
||||
var ghostProg = layer.instrumentProgram !== undefined ? layer.instrumentProgram : (ghostTrack ? ghostTrack.instrumentProgram : undefined);
|
||||
var ghostSynth = layer.synthEngine || (ghostTrack ? ghostTrack.synth_engine : undefined);
|
||||
if (ghostProg === undefined && !ghostSynth) return; // skip tracks with no instrument
|
||||
if (ghostProg === undefined && !ghostSynth) return;
|
||||
var ghostDest = getOrCreateTrackNode(ghostTrack, context);
|
||||
var ghostCh = 0;
|
||||
for (var i = 0; i < allTracks.length; i++) { if (allTracks[i].id === layer.trackId) { ghostCh = i >= 9 ? i + 1 : i; if (ghostCh >= 16) ghostCh = 0; break; } }
|
||||
layer.notes.forEach(function(note) {
|
||||
var beat = note.start_beat || 0;
|
||||
var beat = (note.start_beat || 0) + sessionBeatOffset;
|
||||
var dur = note.duration_beats || 1;
|
||||
var startSec = beat * secondsPerBeat;
|
||||
var durSec = dur * secondsPerBeat;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user