Add centre-panned vocal reduction to live and saved audio
This commit is contained in:
@@ -6540,8 +6540,9 @@ const EqRender = (() => {
|
||||
const g = EQ.gains();
|
||||
const lufs = Level.enabled() ? Level.remembered(id) : null;
|
||||
const levelDb = lufs == null ? 0 : Math.round(Level.gainFor(lufs) * 2) / 2;
|
||||
if (g.every((v) => v === 0) && Math.abs(levelDb) < 0.5) return null;
|
||||
return { gains: g, levelDb, sig: g.join(',') + '|' + levelDb };
|
||||
const vocal = VocalReducer.amount(data.settings.vocalLevel ?? 100);
|
||||
if (g.every((v) => v === 0) && Math.abs(levelDb) < 0.5 && vocal === 100) return null;
|
||||
return { gains: g, levelDb, vocal, sig: g.join(',') + '|' + levelDb + '|vocal:' + vocal };
|
||||
}
|
||||
async function dir() { return (await navigator.storage.getDirectory()).getDirectoryHandle(DIR, { create: true }); }
|
||||
async function drop(id) {
|
||||
@@ -6609,7 +6610,8 @@ const EqRender = (() => {
|
||||
const gain = off.createGain(); gain.gain.value = Math.pow(10, w.levelDb / 20);
|
||||
const lim = off.createDynamicsCompressor();
|
||||
lim.threshold.value = -1; lim.knee.value = 0; lim.ratio.value = 20; lim.attack.value = 0.003; lim.release.value = 0.25;
|
||||
node.connect(gain); gain.connect(lim); lim.connect(off.destination);
|
||||
const vocal = VocalReducer.create(off, node, w.vocal);
|
||||
vocal.output.connect(gain); gain.connect(lim); lim.connect(off.destination);
|
||||
src.start();
|
||||
const out = await off.startRendering();
|
||||
if (wanted(id)?.sig !== w.sig) return; // settings changed meanwhile — the queue re-runs it
|
||||
@@ -6741,7 +6743,8 @@ const EQ = (() => {
|
||||
st.limiter = st.ctx.createDynamicsCompressor();
|
||||
st.limiter.threshold.value = -1; st.limiter.knee.value = 0; st.limiter.ratio.value = 20;
|
||||
st.limiter.attack.value = 0.003; st.limiter.release.value = 0.25;
|
||||
st.filters[st.filters.length - 1].connect(st.level);
|
||||
st.vocal = VocalReducer.create(st.ctx, st.filters[st.filters.length - 1]);
|
||||
st.vocal.output.connect(st.level);
|
||||
st.level.connect(st.limiter);
|
||||
st.limiter.connect(st.ctx.destination);
|
||||
return true;
|
||||
@@ -6760,12 +6763,13 @@ const EQ = (() => {
|
||||
// Apply the stored curve; wires the graph up the first time it's non-flat.
|
||||
function apply() {
|
||||
if (!available()) return;
|
||||
if (!st.ctx && isFlat()) return;
|
||||
if (!st.ctx && isFlat() && VocalReducer.amount(data.settings.vocalLevel ?? 100) === 100) return;
|
||||
if (!build()) return;
|
||||
attach(els.video);
|
||||
attach(els.audio);
|
||||
const g = rendered() ? EQ_BANDS.map(() => 0) : gains();
|
||||
st.filters.forEach((f, i) => { f.gain.value = g[i]; });
|
||||
st.vocal.set(rendered() ? 100 : data.settings.vocalLevel ?? 100);
|
||||
if (st.ctx.state === 'suspended') st.ctx.resume().catch(() => {});
|
||||
renderButton();
|
||||
}
|
||||
@@ -12457,6 +12461,7 @@ async function boot() {
|
||||
LyricsWindow.configure({ prepare: () => { if (!isServiceModeOpen()) Notes.stageLyrics.set(true); }, view: () => isServiceModeOpen() && data.settings.serviceLyrics ? $('serviceLyrics') : $('stageLyrics'), line: () => $('serviceLyricsList')?.querySelector('.active')?.textContent || $('stageLyricsList')?.querySelector('.active')?.textContent || current?.meta?.title || 'Nothing playing', toggle: () => { Player.toggle(); updatePlayBtn(); }, next: playNext, refresh: () => { Notes.stageLyrics.render(true); Notes.serviceRefresh(); }, toast });
|
||||
EQ.renderButton();
|
||||
EQ.apply();
|
||||
VocalReducer.register({ settings: () => data.settings, persist, apply: () => { EQ.apply(); EqRender.scheduleAll(); } });
|
||||
MidiPedals.configure({ settings: () => data.settings, persist, action: action => {
|
||||
if (action === 'toggle') { Player.toggle(); updatePlayBtn(); }
|
||||
else if (action === 'next') playNext();
|
||||
|
||||
Reference in New Issue
Block a user