feat: enhanced the note scheduling logic to support loop mode

pending cases: user disabled the loop mode or updated the loop range during playback.
This commit is contained in:
Xiaohan-Tian
2026-01-23 13:22:51 -08:00
parent b46442bd9d
commit b767d2176f
2 changed files with 102 additions and 20 deletions
+41 -3
View File
@@ -264,9 +264,41 @@ export class KGAudioInterface {
Tone.Transport.bpm.value = project.getBpm();
const timeSignature = project.getTimeSignature();
Tone.Transport.timeSignature = [timeSignature.numerator, timeSignature.denominator];
console.log(`Setting Tone.js BPM to ${project.getBpm()}, actual value: ${Tone.Transport.bpm.value}`);
// Configure loop settings
const isLooping = project.getIsLooping();
let scheduleStartBeat = 0;
let scheduleEndBeat = Infinity;
if (isLooping) {
const [startBar, endBarOriginal] = project.getLoopingRange();
const beatsPerBar = timeSignature.numerator;
// Handle [0, 0] case - use full project
const endBar = (startBar === 0 && endBarOriginal === 0) ? project.getMaxBars() : endBarOriginal;
scheduleStartBeat = startBar * beatsPerBar;
scheduleEndBeat = (endBar + 1) * beatsPerBar; // +1 because endBar is inclusive
// Configure Tone.Transport loop boundaries
const loopStartTime = this.beatsToToneTime(scheduleStartBeat);
const loopEndTime = this.beatsToToneTime(scheduleEndBeat);
Tone.Transport.setLoopPoints(loopStartTime, loopEndTime);
Tone.Transport.loop = true;
console.log(`Loop mode enabled: bars [${startBar}, ${endBar}], beats [${scheduleStartBeat}, ${scheduleEndBeat}]`);
// Adjust start position to loop start if before loop range
if (startPosition < scheduleStartBeat) {
startPosition = scheduleStartBeat;
}
} else {
Tone.Transport.loop = false;
console.log("Loop mode disabled");
}
// Set transport position (convert beats to Tone.js format)
this.setTransportPosition(startPosition);
@@ -290,8 +322,14 @@ export class KGAudioInterface {
// Calculate absolute note timing in beats (note position + region start position)
const regionStartBeat = region.getStartFromBeat();
const noteStartBeat = note.getStartBeat() + regionStartBeat;
const noteEndBeat = note.getEndBeat() + regionStartBeat;
const noteDurationBeats = note.getEndBeat() - note.getStartBeat();
// Skip notes outside loop range when looping
if (noteStartBeat >= scheduleEndBeat || noteEndBeat <= scheduleStartBeat) {
return; // Skip notes outside the loop range
}
// Only schedule notes that start at or after the playback start position
if (noteStartBeat < startPosition) {
return; // Skip notes that would have already finished before playback starts