Skip to content

Commit c5fc652

Browse files
Add target LUFS slider with adjustable range (-16 to -6)
- Replace fixed -14 LUFS normalization with user-configurable target - Add slider in Loudness panel with range -16 to -6 LUFS - Default to -9 LUFS for louder modern masters - Update mini checklist to show dynamic LUFS value - Apply changes to both Electron and web versions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3fe8b82 commit c5fc652

4 files changed

Lines changed: 48 additions & 12 deletions

File tree

index.html

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
</div>
3737
<div class="header-right">
3838
<div class="checklist-mini">
39-
<div class="check-item" id="mini-lufs"><span></span> -14 LUFS</div>
39+
<div class="check-item" id="mini-lufs"><span></span> <span id="mini-lufs-value">-9 LUFS</span></div>
4040
<div class="check-item" id="mini-peak"><span></span> True Peak</div>
4141
<div class="check-item" id="mini-format"><span></span> WAV Ready</div>
4242
</div>
@@ -219,11 +219,16 @@ <h3>Loudness <span class="live-badge">Live</span></h3>
219219
<div id="ceilingFader" class="fader-container" data-tip="Maximum peak level. -1dB is standard for streaming."></div>
220220
</div>
221221
<div class="loudness-toggles">
222-
<label class="toggle-row" data-tip="Adjusts overall volume to Spotify's -14 LUFS standard. Processed in background on file load.">
223-
<span>Normalize -14 LUFS</span>
222+
<label class="toggle-row" data-tip="Normalize loudness to target LUFS. -14 for Spotify, -9 for louder masters.">
223+
<span>Normalize Loudness</span>
224224
<input type="checkbox" id="normalizeLoudness" checked>
225225
<span class="toggle"></span>
226226
</label>
227+
<div class="slider-row target-lufs-row" data-tip="Target loudness: -16 (quiet) to -6 (loud). -14 is Spotify standard, -9 is typical for modern masters.">
228+
<span>Target</span>
229+
<input type="range" id="targetLufs" min="-16" max="-6" step="1" value="-9">
230+
<span class="slider-value" id="targetLufsValue">-9 LUFS</span>
231+
</div>
227232
<label class="toggle-row" data-tip="Prevents audio from clipping by limiting peaks to the ceiling value.">
228233
<span>True Peak Limit</span>
229234
<input type="checkbox" id="truePeakLimit" checked>

src/renderer.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ function measureLUFS(audioBuffer) {
109109
// Minimum block size required for LUFS measurement
110110
if (audioBuffer.duration < LUFS_CONSTANTS.BLOCK_SIZE_SEC) {
111111
console.warn(`[LUFS] Audio too short for reliable measurement (< ${LUFS_CONSTANTS.BLOCK_SIZE_SEC * 1000}ms)`);
112-
return -14; // Return target LUFS as fallback
112+
return targetLufsDb; // Return target LUFS as fallback
113113
}
114114

115115
const channels = [];
@@ -355,6 +355,9 @@ const addAir = document.getElementById('addAir');
355355
const tameHarsh = document.getElementById('tameHarsh');
356356
const sampleRate = document.getElementById('sampleRate');
357357
const bitDepth = document.getElementById('bitDepth');
358+
const targetLufsSlider = document.getElementById('targetLufs');
359+
const targetLufsValue = document.getElementById('targetLufsValue');
360+
const miniLufsValue = document.getElementById('mini-lufs-value');
358361

359362
// EQ values (managed by faders)
360363
let eqValues = {
@@ -368,6 +371,7 @@ let eqValues = {
368371
// Input gain and ceiling values (managed by faders)
369372
let inputGainValue = 0; // dB
370373
let ceilingValueDb = -1; // dB
374+
let targetLufsDb = -9; // Target LUFS for normalization (default -9)
371375

372376
// Level meter elements
373377
const meterCanvas = document.getElementById('meterCanvas');
@@ -1603,8 +1607,8 @@ async function loadAudioFile(filePath) {
16031607

16041608
showLoadingModal('Analyzing audio levels...', 50);
16051609

1606-
// Normalize to -14 LUFS using pure JavaScript
1607-
const normalizedBuffer = normalizeToLUFS(decodedBuffer, -14);
1610+
// Normalize to target LUFS using pure JavaScript
1611+
const normalizedBuffer = normalizeToLUFS(decodedBuffer, targetLufsDb);
16081612

16091613
showLoadingModal('Applying normalization...', 70);
16101614

@@ -2105,6 +2109,15 @@ stereoWidthSlider.addEventListener('input', () => {
21052109
updateStereoWidth();
21062110
});
21072111

2112+
// Target LUFS slider
2113+
targetLufsSlider.addEventListener('input', () => {
2114+
targetLufsDb = parseInt(targetLufsSlider.value);
2115+
targetLufsValue.textContent = `${targetLufsDb} LUFS`;
2116+
if (miniLufsValue) {
2117+
miniLufsValue.textContent = `${targetLufsDb} LUFS`;
2118+
}
2119+
});
2120+
21082121
// Output format presets
21092122
const outputPresets = {
21102123
streaming: { sampleRate: 44100, bitDepth: 16 },

web/app.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function measureLUFS(audioBuffer) {
110110
// Minimum block size required for LUFS measurement
111111
if (audioBuffer.duration < LUFS_CONSTANTS.BLOCK_SIZE_SEC) {
112112
console.warn(`[LUFS] Audio too short for reliable measurement (< ${LUFS_CONSTANTS.BLOCK_SIZE_SEC * 1000}ms)`);
113-
return -14; // Return target LUFS as fallback
113+
return targetLufsDb; // Return target LUFS as fallback
114114
}
115115

116116
const channels = [];
@@ -342,6 +342,9 @@ const addAir = document.getElementById('addAir');
342342
const tameHarsh = document.getElementById('tameHarsh');
343343
const sampleRate = document.getElementById('sampleRate');
344344
const bitDepth = document.getElementById('bitDepth');
345+
const targetLufsSlider = document.getElementById('targetLufs');
346+
const targetLufsValue = document.getElementById('targetLufsValue');
347+
const miniLufsValue = document.getElementById('mini-lufs-value');
345348

346349
// EQ values (managed by faders)
347350
let eqValues = {
@@ -355,6 +358,7 @@ let eqValues = {
355358
// Input gain and ceiling values (managed by faders)
356359
let inputGainValue = 0; // dB
357360
let ceilingValueDb = -1; // dB
361+
let targetLufsDb = -9; // Target LUFS for normalization (default -9)
358362

359363
// Level meter elements
360364
const meterCanvas = document.getElementById('meterCanvas');
@@ -1568,8 +1572,8 @@ async function loadAudioFile(file) {
15681572

15691573
showLoadingModal('Analyzing audio levels...', 50);
15701574

1571-
// Normalize to -14 LUFS using pure JavaScript
1572-
const normalizedBuffer = normalizeToLUFS(decodedBuffer, -14);
1575+
// Normalize to target LUFS using pure JavaScript
1576+
const normalizedBuffer = normalizeToLUFS(decodedBuffer, targetLufsDb);
15731577

15741578
showLoadingModal('Applying normalization...', 70);
15751579

@@ -2070,6 +2074,15 @@ stereoWidthSlider.addEventListener('input', () => {
20702074
updateStereoWidth();
20712075
});
20722076

2077+
// Target LUFS slider
2078+
targetLufsSlider.addEventListener('input', () => {
2079+
targetLufsDb = parseInt(targetLufsSlider.value);
2080+
targetLufsValue.textContent = `${targetLufsDb} LUFS`;
2081+
if (miniLufsValue) {
2082+
miniLufsValue.textContent = `${targetLufsDb} LUFS`;
2083+
}
2084+
});
2085+
20732086
// Output format presets
20742087
const outputPresets = {
20752088
streaming: { sampleRate: 44100, bitDepth: 16 },

web/index.html

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</div>
2121
<div class="header-right">
2222
<div class="checklist-mini">
23-
<div class="check-item" id="mini-lufs"><span></span> -14 LUFS</div>
23+
<div class="check-item" id="mini-lufs"><span></span> <span id="mini-lufs-value">-9 LUFS</span></div>
2424
<div class="check-item" id="mini-peak"><span></span> True Peak</div>
2525
<div class="check-item" id="mini-format"><span></span> WAV Ready</div>
2626
</div>
@@ -204,11 +204,16 @@ <h3>Loudness <span class="live-badge">Live</span></h3>
204204
<div id="ceilingFader" class="fader-container" data-tip="Maximum peak level. -1dB is standard for streaming."></div>
205205
</div>
206206
<div class="loudness-toggles">
207-
<label class="toggle-row" data-tip="Adjusts overall volume to Spotify's -14 LUFS standard. Processed in background on file load.">
208-
<span>Normalize -14 LUFS</span>
207+
<label class="toggle-row" data-tip="Normalize loudness to target LUFS. -14 for Spotify, -9 for louder masters.">
208+
<span>Normalize Loudness</span>
209209
<input type="checkbox" id="normalizeLoudness" checked>
210210
<span class="toggle"></span>
211211
</label>
212+
<div class="slider-row target-lufs-row" data-tip="Target loudness: -16 (quiet) to -6 (loud). -14 is Spotify standard, -9 is typical for modern masters.">
213+
<span>Target</span>
214+
<input type="range" id="targetLufs" min="-16" max="-6" step="1" value="-9">
215+
<span class="slider-value" id="targetLufsValue">-9 LUFS</span>
216+
</div>
212217
<label class="toggle-row" data-tip="Prevents audio from clipping by limiting peaks to the ceiling value.">
213218
<span>True Peak Limit</span>
214219
<input type="checkbox" id="truePeakLimit" checked>

0 commit comments

Comments
 (0)