fix: piano roll playback now uses musical time instead of absolute seconds
The Part events were pre-converted to seconds via Tone.Time().toSeconds(), making the BPM setting ineffective. Now uses bars:quarters:sixteenths notation so the Transport BPM actually controls playback speed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -242,20 +242,31 @@ export default function PianoRollWidget({ moduleId }) {
|
||||
|
||||
Tone.getTransport().bpm.value = bpm;
|
||||
|
||||
// Build Tone.Part from notes
|
||||
const events = notesRef.current.map(n => ({
|
||||
time: `0:0:${n.start * 4}`, // convert beats to 16th notes for Tone
|
||||
// Build Tone.Part from notes using musical time (bars:quarters:sixteenths)
|
||||
// This lets the Transport BPM control actual playback speed
|
||||
const events = notesRef.current.map(n => {
|
||||
// Convert beats to bars:quarters:sixteenths notation
|
||||
const totalSixteenths = Math.round(n.start * 4);
|
||||
const barNum = Math.floor(totalSixteenths / 16);
|
||||
const remainder = totalSixteenths % 16;
|
||||
const quarterNum = Math.floor(remainder / 4);
|
||||
const sixteenthNum = remainder % 4;
|
||||
return {
|
||||
time: `${barNum}:${quarterNum}:${sixteenthNum}`,
|
||||
note: n.note,
|
||||
dur: n.duration,
|
||||
}));
|
||||
};
|
||||
});
|
||||
|
||||
// Use a simpler approach: schedule directly
|
||||
const part = new Tone.Part((time, ev) => {
|
||||
setSequencerSignals(moduleId, midiToFreq(ev.note), true);
|
||||
// Note-off: convert duration beats to musical time for proper BPM-relative timing
|
||||
const durSixteenths = Math.round(ev.dur * 4);
|
||||
const noteOffTime = time + (durSixteenths * (60 / (bpm * 4))) * 0.9;
|
||||
Tone.getTransport().scheduleOnce(() => {
|
||||
setSequencerSignals(moduleId, midiToFreq(ev.note), false);
|
||||
}, time + Tone.Time(`0:0:${ev.dur * 4}`).toSeconds() * 0.9);
|
||||
}, events.map(ev => [Tone.Time(ev.time).toSeconds(), { note: ev.note, dur: ev.dur }]));
|
||||
}, noteOffTime);
|
||||
}, events.map(ev => [ev.time, { note: ev.note, dur: ev.dur }]));
|
||||
|
||||
part.loop = loop;
|
||||
part.loopEnd = `${bars}m`;
|
||||
|
||||
Reference in New Issue
Block a user