FIX: Clone AI Var kế thừa midiChannel của track gốc → 2 track DÙNG CHUNG channel

This commit is contained in:
2026-08-05 15:49:44 +07:00
parent 4233c1eeda
commit b3ced7a7b3
5 changed files with 150 additions and 31 deletions
+65 -7
View File
@@ -112,6 +112,20 @@ const trackMasteringBypassMap = {};
const trackAudioBypassMap = {};
const trackMidiBypassMap = {};
// Mastering chain ON? (masterConnected && !isBypassed)
const masteringChainOn = () => !!(window.currentMasteringSettings && window.currentMasteringSettings.masterConnected && !window.currentMasteringSettings.isBypassed);
// bypass hiu lc CH khi mastering chain TT khi chain ON, MI track
// (solo/preview/play) PHI đi qua mastering chain (user requirement: âm phi
// qua chain đ đ ln). Chain OFF theo maps như cũ.
const effMidiBypass = (track) => {
if (masteringChainOn()) return false;
return trackMidiBypassMap[track.id] !== undefined ? !!trackMidiBypassMap[track.id] : !!(track.midiBypass ?? track.masteringBypass);
};
const effAudioBypass = (track) => {
if (masteringChainOn()) return false;
return trackAudioBypassMap[track.id] !== undefined ? !!trackAudioBypassMap[track.id] : !!(track.audioBypass ?? track.masteringBypass);
};
// Build the dual routing for one track: routeGain -> mastering chain (normal),
// dryGain -> dry bus (bypass). Gains start at complementary 1/0 values.
function createMasteringRoute(ctx, track, bus) {
@@ -121,9 +135,11 @@ function createMasteringRoute(ctx, track, bus) {
let bypass = false;
if (track && track.id && trackAudioBypassMap[track.id] !== undefined) {
bypass = !!trackAudioBypassMap[track.id];
} else {
bypass = !!(track && (track.audioBypass ?? track.masteringBypass));
} else if (track) {
bypass = !!(track.audioBypass ?? track.masteringBypass);
}
// Mastering chain ON MI track qua chain ( b override user requirement)
if (masteringChainOn()) bypass = false;
const routeGain = ctx.createGain();
const dryGain = ctx.createGain();
const masterDest = bus ? bus.input : ctx.destination;
@@ -1012,7 +1028,7 @@ function buildOfflineTrackNode(track, ctx, nodeMap) {
sfOut.connect(sfPan);
const sfRouteGain = ctx.createGain();
const sfDryGain = ctx.createGain();
const sfBypass = trackMidiBypassMap[track.id] !== undefined ? !!trackMidiBypassMap[track.id] : !!(track.midiBypass ?? track.masteringBypass);
const sfBypass = effMidiBypass(track);
sfRouteGain.gain.value = sfBypass ? 0 : 1;
sfDryGain.gain.value = sfBypass ? 1 : 0;
sfPan.connect(sfRouteGain);
@@ -14519,9 +14535,10 @@ const App = () => {
list.forEach(t => {
// state SF mastering route (sfRouteGain/sfDryGain), live on existing nodes
const sn = activeTrackNodesRef.current[t.id];
if (sn && sn.sfRouteGain && sn.sfDryGain && (sn.sfRouteGain.gain.value > 0) !== !trackMidiBypassMap[t.id]) {
sn.sfRouteGain.gain.value = trackMidiBypassMap[t.id] ? 0 : 1;
sn.sfDryGain.gain.value = trackMidiBypassMap[t.id] ? 1 : 0;
if (sn && sn.sfRouteGain && sn.sfDryGain && (sn.sfRouteGain.gain.value > 0) !== !effMidiBypass(t)) {
const _b = effMidiBypass(t);
sn.sfRouteGain.gain.value = _b ? 0 : 1;
sn.sfDryGain.gain.value = _b ? 1 : 0;
}
const sig = (t.muted ? '1' : '0') + (t.solo ? '1' : '0') + ':' + (t.volumeDb ?? 0);
if (trackMuteSoloSigRef.current[t.id] === sig) return;
@@ -14630,6 +14647,28 @@ const App = () => {
if (audioCtx && masterBus) {
toggleMasteringOnMaster(masteringSettings.masterConnected, masteringSettings.isBypassed);
applyMasteringSettings(masteringSettings);
// Re-sync live track routes: mastering ON mi track qua chain ( b
// override bi effMidiBypass/effAudioBypass) nút PWR bt/tt phi áp
// ngay lên node đang phát (không ch tracks effect).
try {
const _list = (activeTracksRef.current && activeTracksRef.current.length) ? activeTracksRef.current : tracks;
_list.forEach(_t => {
const _n = activeTrackNodesRef.current[_t.id];
if (_n) {
if (_n.sfRouteGain && _n.sfDryGain) {
const _b = effMidiBypass(_t);
_n.sfRouteGain.gain.value = _b ? 0 : 1;
_n.sfDryGain.gain.value = _b ? 1 : 0;
}
if (_n.route && _n.route.routeGain && _n.route.dryGain) {
const _ab = effAudioBypass(_t);
_n.route.routeGain.gain.value = _ab ? 0 : 1;
_n.route.dryGain.gain.value = _ab ? 1 : 0;
}
}
});
updateSfRouting();
} catch (e) {}
}
}, [masteringSettings]);
@@ -18221,7 +18260,7 @@ const App = () => {
// button: bypass Mastering FX Chain for the soundfont ONLY (track FX
// Rack modules are still applied PWR controls those). sfRouteGain
// masterBus.input (mastering), sfDryGain dry bus (skip mastering).
const sfBypass = trackMidiBypassMap[track.id] !== undefined ? !!trackMidiBypassMap[track.id] : !!(track.midiBypass ?? track.masteringBypass);
const sfBypass = effMidiBypass(track);
sfRouteGain = context.createGain();
sfDryGain = context.createGain();
sfRouteGain.gain.value = sfBypass ? 0 : 1;
@@ -18327,6 +18366,14 @@ const App = () => {
if (_prNode && window.SonicSF && window.SonicSF.setOutputDestination) {
if (_prNode.sfEntry) {
window.SonicSF.setOutputDestination(_prNode.sfEntry);
// Ép route qua mastering chain NGAY ti thi đim routing (node có
// th to khi mastering OFF route dry sa ngay nếu chain ON).
if (_prNode.sfRouteGain && _prNode.sfDryGain) {
const _prTrk = list.find(t => t.id === _activeSub.trackId);
const _b = effMidiBypass(_prTrk || { id: _activeSub.trackId });
_prNode.sfRouteGain.gain.value = _b ? 0 : 1;
_prNode.sfDryGain.gain.value = _b ? 1 : 0;
}
return;
}
if (_prNode.gainNode) {
@@ -18344,6 +18391,12 @@ const App = () => {
// sfDryGain) to skip or include the Mastering FX Chain.
if (node && node.sfEntry && window.SonicSF && window.SonicSF.setOutputDestination) {
window.SonicSF.setOutputDestination(node.sfEntry);
// Ép route qua mastering chain NGAY ti thi đim routing.
if (node.sfRouteGain && node.sfDryGain) {
const _b = effMidiBypass(t.id);
node.sfRouteGain.gain.value = _b ? 0 : 1;
node.sfDryGain.gain.value = _b ? 1 : 0;
}
return;
}
if (node && node.gainNode && window.SonicSF && window.SonicSF.setOutputDestination) {
@@ -22990,6 +23043,11 @@ STRICT CONSTRAINTS:
...(srcTrack || {}),
id: newTrackId,
name: '[AI Var] ' + title,
// KHÔNG kế tha midiChannel ca track gc: nếu dùng chung channel,
// solo/mute track gc gi CC7=0 trên channel đó clone (cùng
// channel) b NH/CÂM. ensureTrackMidiChannel/assignTrackMidiChannel
// s cp channel RIÊNG cho track mi.
midiChannel: undefined,
buffer: null,
startTime: 0,
clips: [],