fix: play MIDI item luôn dùng instrument của track chứa item - sửa startLocalTrackPlayback thiếu channel/synth_engine + đồng nhất assignTrackMidiChannel mọi đường phát

This commit is contained in:
2026-08-03 11:07:58 +07:00
parent 9b6de7f857
commit 0182abf7ea
4 changed files with 33 additions and 30 deletions
+17 -19
View File
@@ -6226,7 +6226,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
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);
var pvCh = pvTrk ? assignTrackMidiChannel(pvTrk, activeTracks) : 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);
});
@@ -6560,7 +6560,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
if (window.SonicSF) {
const ctx = getAudioContext();
var clTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var clCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(clTrk, activeTracks) : (clTrk ? clTrk.midiChannel : 0);
var clCh = clTrk ? assignTrackMidiChannel(clTrk, activeTracks) : 0;
window.SonicSF.playNote(notes[clickedNoteIdx].pitch, 100, 300, ctx.currentTime, st.instrumentProgram, null, clCh, clTrk ? clTrk.synth_engine : undefined);
}
}
@@ -6784,7 +6784,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
if (window.SonicSF && window.SonicSF._playNoteFallback) {
const ctx = getAudioContext();
var dwTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var dwCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(dwTrk, activeTracks) : (dwTrk ? dwTrk.midiChannel : 0);
var dwCh = dwTrk ? assignTrackMidiChannel(dwTrk, activeTracks) : 0;
var dwPitch = snapToScaleRef.current ? snapPitchToScale(pitch, selectedScaleRef.current) : pitch;
var dwDurMs = Math.max(100, Math.round(initialDur * (60 / bpm) * 1000));
var dwNodes = window.SonicSF._playNoteFallback(dwPitch, Math.round(brushVelocityRef.current * 127), dwDurMs, ctx.currentTime, dwTrk ? dwTrk.instrumentProgram : undefined, null, dwCh, dwTrk ? dwTrk.synth_engine : undefined);
@@ -6880,7 +6880,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
if (window.SonicSF && window.SonicSF._playNoteFallback) {
var pvCtx = getAudioContext();
var pvTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var pvCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(pvTrk, activeTracks) : (pvTrk ? pvTrk.midiChannel : 0);
var pvCh = pvTrk ? assignTrackMidiChannel(pvTrk, activeTracks) : 0;
var pvVel = Math.round(brushVelocityRef.current * 127);
var pvNodes = window.SonicSF._playNoteFallback(p, pvVel, durMs, pvCtx.currentTime, pvTrk ? pvTrk.instrumentProgram : undefined, null, pvCh, pvTrk ? pvTrk.synth_engine : undefined);
if (pvNodes) previewNodesRef.current = pvNodes;
@@ -7197,7 +7197,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
const renderKeybed = () => {
var kbTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var kbCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(kbTrk, activeTracks) : (kbTrk ? kbTrk.midiChannel : 0);
var kbCh = kbTrk ? assignTrackMidiChannel(kbTrk, activeTracks) : 0;
var kbSynth = kbTrk ? kbTrk.synth_engine : undefined;
const keys = [];
for (let pitch = 127; pitch >= PITCH_START; pitch--) {
@@ -15373,7 +15373,7 @@ const App = () => {
const track = activeTracks.find(t => t.id === trackId);
const destNode = getOrCreateTrackNode(track, context);
const program = track ? track.instrumentProgram : undefined;
var prevCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(track, activeTracks) : (track ? track.midiChannel : 0);
var prevCh = track ? assignTrackMidiChannel(track, activeTracks) : 0;
window.SonicSF.playNote(
pitch,
velocity,
@@ -15426,7 +15426,7 @@ const App = () => {
// MIDI items playback
const midiItems = track.midiItems || [];
if ((track.type === 'MIDI' || midiItems.length > 0) && window.SonicSF) {
var trkCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(track, allPlayTracks) : (track.midiChannel !== undefined ? track.midiChannel : 0);
var trkCh = assignTrackMidiChannel(track, allPlayTracks);
// Ensure instrument is loaded in FluidSynth
if (track.synth_engine && track.synth_engine.type === 'soundfont' && track.synth_engine.soundfont_id) {
window.SonicSF.selectInstrument(trkCh, track.synth_engine.soundfont_bank || 0, track.synth_engine.soundfont_program || 0, track.synth_engine.soundfont_id);
@@ -15566,7 +15566,7 @@ const App = () => {
if (noteStartMain >= secStart && noteStartMain < secEnd && offsetTime < noteEndMain) {
const notePlayEndMain = Math.min(noteEndMain, secEnd);
const program = subTrack.instrumentProgram;
var subCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(subTrack, secTracks) : (subTrack.midiChannel !== undefined ? subTrack.midiChannel : (subIdx % 16));
var subCh = assignTrackMidiChannel(subTrack, secTracks);
if (offsetTime < noteStartMain) {
const delay = noteStartMain - offsetTime;
@@ -15645,6 +15645,7 @@ const App = () => {
// MIDI items playback
const midiItems = track.midiItems || [];
if ((track.type === 'MIDI' || midiItems.length > 0) && window.SonicSF) {
var lcCh = assignTrackMidiChannel(track, tracks);
const bpmVal = parseInt(bpm) || 120;
const secondsPerBeat = 60.0 / bpmVal;
midiItems.forEach(item => {
@@ -15665,7 +15666,9 @@ const App = () => {
durationMs,
startTime,
program,
gainNode
gainNode,
lcCh,
track.synth_engine
);
} else {
const remainingDurMs = (noteEndSec - offsetTime) * 1000;
@@ -15675,7 +15678,9 @@ const App = () => {
remainingDurMs,
context.currentTime,
program,
gainNode
gainNode,
lcCh,
track.synth_engine
);
}
}
@@ -15695,7 +15700,7 @@ const App = () => {
const instrumentProgram = track ? track.instrumentProgram : undefined;
const synthEngine = track ? track.synth_engine : undefined;
var allTracks = activeTracksRef.current || [];
var mainCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(track, allTracks) : (track ? track.midiChannel : 0);
var mainCh = track ? assignTrackMidiChannel(track, allTracks) : 0;
// Compute session beat offset from target item
var sessionBeatOffset = 0;
var targetTrk = allTracks.find(function(t) { return t.id === st.trackId; });
@@ -15726,14 +15731,7 @@ const App = () => {
var ghostSynth = layer.synthEngine || (ghostTrack ? ghostTrack.synth_engine : undefined);
if (ghostProg === undefined && !ghostSynth) return;
var ghostDest = getOrCreateTrackNode(ghostTrack, context);
var ghostCh = 0;
if (ghostTrack) {
if (ghostTrack.midiChannel !== undefined) {
ghostCh = ghostTrack.midiChannel;
} else {
ghostCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(ghostTrack, allTracks) : (ghostTrack ? ghostTrack.midiChannel : 0);
}
}
var ghostCh = ghostTrack ? assignTrackMidiChannel(ghostTrack, allTracks) : 0;
layer.notes.forEach(function(note) {
var beat = (note.start_beat || 0) + sessionBeatOffset;
var dur = note.duration_beats || 1;
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -24,7 +24,7 @@
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
<script src="/static/js/app.precompiled.js?v=202608031130" defer></script>
<script src="/static/js/app.precompiled.js?v=202608031150" defer></script>
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
<style>
:root {