FIX: Clone AI Var kế thừa midiChannel của track gốc → 2 track DÙNG CHUNG channel
This commit is contained in:
+65
-7
@@ -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 hiệu lực CHỈ khi mastering chain TẮT — khi chain ON, MỌI track
|
||||
// (solo/preview/play) PHẢI đi qua mastering chain (user requirement: âm phải
|
||||
// qua chain để đủ lớn). 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 → MỌI 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 → mọi track qua chain (♪ bị
|
||||
// override bởi effMidiBypass/effAudioBypass) — nút PWR bật/tắt phải á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 tại thời điểm routing (node có
|
||||
// thể tạo khi mastering OFF → route dry — sửa 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 tại thời điểm 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ế thừa midiChannel của track gốc: nếu dùng chung channel,
|
||||
// solo/mute track gốc gửi CC7=0 trên channel đó → clone (cùng
|
||||
// channel) bị NHỎ/CÂM. ensureTrackMidiChannel/assignTrackMidiChannel
|
||||
// sẽ cấp channel RIÊNG cho track mới.
|
||||
midiChannel: undefined,
|
||||
buffer: null,
|
||||
startTime: 0,
|
||||
clips: [],
|
||||
|
||||
Reference in New Issue
Block a user