FIX: sửa volume main out
This commit is contained in:
+76
-24
@@ -58,6 +58,7 @@ function initMasterBus(ctx) {
|
|||||||
masterBus.compressor.connect(masterBus.output);
|
masterBus.compressor.connect(masterBus.output);
|
||||||
masterBus.output.connect(masterBus.analyser);
|
masterBus.output.connect(masterBus.analyser);
|
||||||
masterBus.analyser.connect(ctx.destination);
|
masterBus.analyser.connect(ctx.destination);
|
||||||
|
window.masterBus = masterBus;
|
||||||
return masterBus;
|
return masterBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +117,9 @@ function getAudioContext() {
|
|||||||
if (audioCtx.state === 'suspended') {
|
if (audioCtx.state === 'suspended') {
|
||||||
audioCtx.resume();
|
audioCtx.resume();
|
||||||
}
|
}
|
||||||
|
if (!masterBus) {
|
||||||
|
initMasterBus(audioCtx);
|
||||||
|
}
|
||||||
if (window.SonicSF && window.SonicSF.init) {
|
if (window.SonicSF && window.SonicSF.init) {
|
||||||
window.SonicSF.init(audioCtx);
|
window.SonicSF.init(audioCtx);
|
||||||
}
|
}
|
||||||
@@ -456,7 +460,7 @@ const MixerStrip = ({ track, index, onUpdateTrack }) => {
|
|||||||
var vuColor = pct >= 80 ? '#ef4444' : pct >= 50 ? '#eab308' : '#22c55e';
|
var vuColor = pct >= 80 ? '#ef4444' : pct >= 50 ? '#eab308' : '#22c55e';
|
||||||
var trackColor = track.color || '#06b6d4';
|
var trackColor = track.color || '#06b6d4';
|
||||||
return React.createElement("div", {
|
return React.createElement("div", {
|
||||||
className: "flex flex-col items-stretch w-14 shrink-0 bg-[#2b2b2b] border border-black/70 overflow-hidden rounded-sm"
|
className: "flex flex-col items-stretch w-[84px] shrink-0 bg-[#2b2b2b] border border-black/70 overflow-hidden rounded-sm"
|
||||||
},
|
},
|
||||||
React.createElement("div", {
|
React.createElement("div", {
|
||||||
className: "flex items-center justify-between px-1 py-0.5 bg-[#222] border-b border-black/60 shrink-0"
|
className: "flex items-center justify-between px-1 py-0.5 bg-[#222] border-b border-black/60 shrink-0"
|
||||||
@@ -476,17 +480,39 @@ const MixerStrip = ({ track, index, onUpdateTrack }) => {
|
|||||||
}, "S")),
|
}, "S")),
|
||||||
React.createElement("div", {
|
React.createElement("div", {
|
||||||
className: "flex-1 flex items-stretch justify-center gap-1 px-1 py-1 min-h-0"
|
className: "flex-1 flex items-stretch justify-center gap-1 px-1 py-1 min-h-0"
|
||||||
}, React.createElement("input", {
|
}, React.createElement("div", {
|
||||||
type: "range",
|
className: "w-[30px] rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60 flex flex-col items-center cursor-pointer",
|
||||||
min: "-60",
|
onMouseDown: function(e) {
|
||||||
max: "12",
|
e.preventDefault();
|
||||||
step: "0.5",
|
var rect = e.currentTarget.getBoundingClientRect();
|
||||||
value: vol,
|
var tid = track.id;
|
||||||
onChange: e => { if (onUpdateTrack) onUpdateTrack(track.id, { volumeDb: parseFloat(e.target.value) }); },
|
function onMove(ev) {
|
||||||
className: "w-3 bg-[#161616] rounded appearance-none cursor-pointer accent-orange-500 border border-black/60",
|
var pct = 1 - Math.max(0, Math.min(1, (ev.clientY - rect.top) / rect.height));
|
||||||
style: { writingMode: 'vertical-lr', direction: 'rtl' }
|
var val = Math.round((pct * 72 - 60) * 2) / 2;
|
||||||
}), React.createElement("div", {
|
if (onUpdateTrack) onUpdateTrack(tid, { volumeDb: val });
|
||||||
className: "w-2.5 rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60"
|
}
|
||||||
|
function onUp() { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); }
|
||||||
|
document.addEventListener('mousemove', onMove);
|
||||||
|
document.addEventListener('mouseup', onUp);
|
||||||
|
onMove(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 0dB reference line */
|
||||||
|
React.createElement("div", {
|
||||||
|
className: "absolute w-full h-px bg-amber-400/60 z-10 pointer-events-none",
|
||||||
|
style: { bottom: '83.333%' }
|
||||||
|
}),
|
||||||
|
/* Background gradient */
|
||||||
|
React.createElement("div", {
|
||||||
|
className: "absolute inset-0",
|
||||||
|
style: { background: 'linear-gradient(to top, #22c55e, #eab308, #ef4444)' }
|
||||||
|
}),
|
||||||
|
/* Level overlay - dark at TOP, gradient visible at bottom */
|
||||||
|
React.createElement("div", {
|
||||||
|
className: "absolute top-0 w-full transition-all duration-75 bg-[#0d0d0d]",
|
||||||
|
style: { height: (100 - pct) + '%' }
|
||||||
|
})), React.createElement("div", {
|
||||||
|
className: "w-[15px] rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60"
|
||||||
}, React.createElement("div", {
|
}, React.createElement("div", {
|
||||||
className: "absolute bottom-0 w-full transition-all duration-75",
|
className: "absolute bottom-0 w-full transition-all duration-75",
|
||||||
style: { height: pct + '%', backgroundColor: vuColor }
|
style: { height: pct + '%', backgroundColor: vuColor }
|
||||||
@@ -11394,6 +11420,8 @@ const App = () => {
|
|||||||
gainNode.gain.setValueAtTime(volLinear, context.currentTime);
|
gainNode.gain.setValueAtTime(volLinear, context.currentTime);
|
||||||
const pannerNode = context.createStereoPanner();
|
const pannerNode = context.createStereoPanner();
|
||||||
pannerNode.pan.setValueAtTime((track.pan ?? 0) / 100, context.currentTime);
|
pannerNode.pan.setValueAtTime((track.pan ?? 0) / 100, context.currentTime);
|
||||||
|
// Ensure master bus is initialized for MAIN OUT routing
|
||||||
|
if (!masterBus) initMasterBus(context);
|
||||||
// Route through master bus if available, else direct to destination
|
// Route through master bus if available, else direct to destination
|
||||||
const dest = masterBus ? masterBus.input : context.destination;
|
const dest = masterBus ? masterBus.input : context.destination;
|
||||||
pannerNode.connect(dest);
|
pannerNode.connect(dest);
|
||||||
@@ -18950,28 +18978,52 @@ const App = () => {
|
|||||||
})))), /*#__PURE__*/React.createElement("div", {
|
})))), /*#__PURE__*/React.createElement("div", {
|
||||||
className: "flex-1 flex overflow-x-auto p-1.5 gap-1.5 items-stretch"
|
className: "flex-1 flex overflow-x-auto p-1.5 gap-1.5 items-stretch"
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: "flex flex-col items-stretch w-[72px] shrink-0 bg-[#2b2b2b] border border-black/70 overflow-hidden rounded-sm"
|
className: "flex flex-col items-stretch w-[108px] shrink-0 bg-[#2b2b2b] border border-black/70 overflow-hidden rounded-sm"
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: "text-[9px] font-bold text-zinc-300 uppercase tracking-wider w-full text-center py-0.5 bg-[#222] border-b border-black/60 shrink-0"
|
className: "text-[9px] font-bold text-zinc-300 uppercase tracking-wider w-full text-center py-0.5 bg-[#222] border-b border-black/60 shrink-0"
|
||||||
}, "MASTER"), /*#__PURE__*/React.createElement("div", {
|
}, "MASTER"), /*#__PURE__*/React.createElement("div", {
|
||||||
className: "flex-1 flex items-stretch justify-center gap-1 px-1 py-1 min-h-0"
|
className: "flex-1 flex items-stretch justify-center gap-1 px-1 py-1 min-h-0"
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: "w-6 rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60 flex flex-col items-center"
|
className: "w-9 rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60 flex flex-col items-center cursor-pointer",
|
||||||
}, /*#__PURE__*/React.createElement("input", {
|
onMouseDown: function(e) {
|
||||||
type: "range",
|
e.preventDefault();
|
||||||
min: "-60", max: "12", step: "0.5",
|
var rect = e.currentTarget.getBoundingClientRect();
|
||||||
value: masterVolume,
|
function onMove(ev) {
|
||||||
onChange: e => { const v = parseFloat(e.target.value); setMasterVolume(v); const linear = v <= -50 ? 0 : Math.pow(10, v / 20); if (masterBus && masterBus.output) masterBus.output.gain.setValueAtTime(linear, getAudioContext().currentTime); },
|
var pct = 1 - Math.max(0, Math.min(1, (ev.clientY - rect.top) / rect.height));
|
||||||
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10",
|
var val = Math.round((pct * 72 - 60) * 2) / 2;
|
||||||
style: { writingMode: 'vertical-lr', direction: 'rtl' }
|
setMasterVolume(val);
|
||||||
}), /*#__PURE__*/React.createElement("div", {
|
var linear = val <= -50 ? 0 : Math.pow(10, val / 20);
|
||||||
className: "flex-1 w-full flex flex-col-reverse items-center pb-0.5",
|
getAudioContext();
|
||||||
|
if (masterBus && masterBus.output) masterBus.output.gain.setValueAtTime(linear, audioCtx.currentTime);
|
||||||
|
}
|
||||||
|
function onUp() { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); }
|
||||||
|
document.addEventListener('mousemove', onMove);
|
||||||
|
document.addEventListener('mouseup', onUp);
|
||||||
|
onMove(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 0dB reference line */
|
||||||
|
React.createElement("div", {
|
||||||
|
className: "absolute w-full h-px bg-amber-400/70 z-10 pointer-events-none",
|
||||||
|
style: { bottom: '83.333%' }
|
||||||
|
}),
|
||||||
|
/* Tick marks */
|
||||||
|
[-48,-36,-24,-12,0,6].map(function(db) {
|
||||||
|
var pct = (db + 60) / 72 * 100;
|
||||||
|
return React.createElement("div", {
|
||||||
|
key: db,
|
||||||
|
className: "absolute w-1.5 h-px bg-slate-600/50 z-10 pointer-events-none",
|
||||||
|
style: { bottom: pct + '%', left: db === 0 ? '0' : 'auto', right: db === 0 ? 'auto' : '0', width: db === 0 ? '100%' : '4px' }
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
React.createElement("div", {
|
||||||
|
className: "flex-1 w-full flex flex-col items-center pb-0.5",
|
||||||
style: { background: 'linear-gradient(to top, #38bdf8, #f59e0b, #ef4444)' }
|
style: { background: 'linear-gradient(to top, #38bdf8, #f59e0b, #ef4444)' }
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: "w-full bg-[#0d0d0d] transition-all duration-75",
|
className: "w-full bg-[#0d0d0d] transition-all duration-75",
|
||||||
style: { height: `${(1 - Math.min(1, Math.max(0, (masterVolume + 60) / 72))) * 100}%` }
|
style: { height: `${(1 - Math.min(1, Math.max(0, (masterVolume + 60) / 72))) * 100}%` }
|
||||||
}))), /*#__PURE__*/React.createElement("div", {
|
}))), /*#__PURE__*/React.createElement("div", {
|
||||||
className: "w-3 rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60"
|
className: "w-[18px] rounded-sm relative overflow-hidden bg-[#0d0d0d] border border-black/60"
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: "absolute bottom-0 w-full transition-all duration-75",
|
className: "absolute bottom-0 w-full transition-all duration-75",
|
||||||
style: { height: `${Math.min(100, masterVU * 100)}%`, background: masterVU > 0.85 ? '#ef4444' : masterVU > 0.7 ? '#f59e0b' : '#38bdf8' }
|
style: { height: `${Math.min(100, masterVU * 100)}%`, background: masterVU > 0.85 ? '#ef4444' : masterVU > 0.7 ? '#f59e0b' : '#38bdf8' }
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@
|
|||||||
if (!_gainNode) {
|
if (!_gainNode) {
|
||||||
_gainNode = ctx.createGain();
|
_gainNode = ctx.createGain();
|
||||||
_gainNode.gain.value = 0.3;
|
_gainNode.gain.value = 0.3;
|
||||||
_gainNode.connect(ctx.destination);
|
_gainNode.connect(window.masterBus ? window.masterBus.input : ctx.destination);
|
||||||
}
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@@ -119,8 +119,8 @@
|
|||||||
if (!_useScriptNode) {
|
if (!_useScriptNode) {
|
||||||
try {
|
try {
|
||||||
_workletNode = new AudioWorkletNode(_audioCtx, 'fluidsynth-bridge');
|
_workletNode = new AudioWorkletNode(_audioCtx, 'fluidsynth-bridge');
|
||||||
_workletNode.connect(_audioCtx.destination);
|
_workletNode.connect(_gainNode);
|
||||||
console.log("[SonicSF] AudioWorklet node connected");
|
console.log("[SonicSF] AudioWorklet node connected via gain");
|
||||||
_startRenderLoop();
|
_startRenderLoop();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("[SonicSF] AudioWorkletNode failed:", e);
|
console.warn("[SonicSF] AudioWorkletNode failed:", e);
|
||||||
@@ -146,9 +146,9 @@
|
|||||||
}
|
}
|
||||||
} catch (er) {}
|
} catch (er) {}
|
||||||
};
|
};
|
||||||
spn.connect(_audioCtx.destination);
|
spn.connect(_gainNode);
|
||||||
_workletNode = spn;
|
_workletNode = spn;
|
||||||
console.log("[SonicSF] ScriptProcessorNode fallback active (buf:", spBufSz, ")");
|
console.log("[SonicSF] ScriptProcessorNode connected via gain (buf:", spBufSz, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user