feat: exponential volume
This commit is contained in:
parent
43be45b76f
commit
af1c0fc1ee
4 changed files with 78 additions and 16 deletions
40
index.html
40
index.html
|
|
@ -2646,21 +2646,21 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lastfm-credential-auth" style="display: none; margin-top: 12px">
|
||||
<div id="lastfm-credential-auth-secondary" style="display: none; margin-top: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<div id="lastfm-credential-toggle-container">
|
||||
<div id="lastfm-credential-toggle-container-secondary">
|
||||
<button
|
||||
id="lastfm-show-credential-auth"
|
||||
id="lastfm-show-credential-auth-secondary"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem; width: 100%"
|
||||
>
|
||||
Login with Username/Password
|
||||
</button>
|
||||
</div>
|
||||
<div id="lastfm-credential-form" style="display: none">
|
||||
<div id="lastfm-credential-form-secondary" style="display: none">
|
||||
<input
|
||||
type="text"
|
||||
id="lastfm-username"
|
||||
id="lastfm-username-secondary"
|
||||
placeholder="Last.fm Username"
|
||||
style="
|
||||
padding: 8px;
|
||||
|
|
@ -2674,7 +2674,7 @@
|
|||
/>
|
||||
<input
|
||||
type="password"
|
||||
id="lastfm-password"
|
||||
id="lastfm-password-secondary"
|
||||
placeholder="Last.fm Password"
|
||||
style="
|
||||
padding: 8px;
|
||||
|
|
@ -2688,14 +2688,14 @@
|
|||
/>
|
||||
<div style="display: flex; gap: 8px">
|
||||
<button
|
||||
id="lastfm-login-credentials"
|
||||
id="lastfm-login-credentials-secondary"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem; flex: 1"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
id="lastfm-use-oauth"
|
||||
id="lastfm-use-oauth-secondary"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem; flex: 1"
|
||||
>
|
||||
|
|
@ -2705,11 +2705,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lastfm-credential-auth" style="margin-top: 12px; display: none">
|
||||
<div id="lastfm-credential-auth-alt" style="margin-top: 12px; display: none">
|
||||
<div style="display: flex; flex-direction: column; gap: 8px">
|
||||
<input
|
||||
type="text"
|
||||
id="lastfm-username"
|
||||
id="lastfm-username-alt"
|
||||
placeholder="Last.fm Username"
|
||||
style="
|
||||
padding: 8px;
|
||||
|
|
@ -2721,7 +2721,7 @@
|
|||
/>
|
||||
<input
|
||||
type="password"
|
||||
id="lastfm-password"
|
||||
id="lastfm-password-alt"
|
||||
placeholder="Last.fm Password"
|
||||
style="
|
||||
padding: 8px;
|
||||
|
|
@ -2733,14 +2733,14 @@
|
|||
/>
|
||||
<div style="display: flex; gap: 8px; margin-top: 4px">
|
||||
<button
|
||||
id="lastfm-login-credentials"
|
||||
id="lastfm-login-credentials-alt"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem"
|
||||
>
|
||||
Login with Credentials
|
||||
</button>
|
||||
<button
|
||||
id="lastfm-use-oauth"
|
||||
id="lastfm-use-oauth-alt"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem"
|
||||
>
|
||||
|
|
@ -2749,7 +2749,7 @@
|
|||
</div>
|
||||
<div style="display: flex; gap: 8px; margin-top: 4px">
|
||||
<button
|
||||
id="lastfm-show-credential-auth"
|
||||
id="lastfm-show-credential-auth-alt"
|
||||
class="btn-secondary"
|
||||
style="padding: 6px 12px; font-size: 0.85rem"
|
||||
>
|
||||
|
|
@ -3069,6 +3069,18 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Exponential Volume</span>
|
||||
<span class="description"
|
||||
>Use logarithmic volume curve for finer low-volume control</span
|
||||
>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="exponential-volume-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- 16-Band Equalizer -->
|
||||
<div class="setting-item">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
getTrackYearDisplay,
|
||||
createQualityBadgeHTML,
|
||||
} from './utils.js';
|
||||
import { queueManager, replayGainSettings, trackDateSettings } from './storage.js';
|
||||
import { queueManager, replayGainSettings, trackDateSettings, exponentialVolumeSettings } from './storage.js';
|
||||
import { audioContextManager } from './audio-context.js';
|
||||
|
||||
export class Player {
|
||||
|
|
@ -99,8 +99,11 @@ export class Player {
|
|||
scale = 1.0 / peak;
|
||||
}
|
||||
|
||||
// Apply exponential volume curve if enabled
|
||||
const curvedVolume = exponentialVolumeSettings.applyCurve(this.userVolume);
|
||||
|
||||
// Calculate effective volume
|
||||
const effectiveVolume = this.userVolume * scale;
|
||||
const effectiveVolume = curvedVolume * scale;
|
||||
|
||||
// Apply to audio element
|
||||
this.audio.volume = Math.max(0, Math.min(1, effectiveVolume));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import {
|
|||
sidebarSectionSettings,
|
||||
fontSettings,
|
||||
monoAudioSettings,
|
||||
exponentialVolumeSettings,
|
||||
} from './storage.js';
|
||||
import { audioContextManager, EQ_PRESETS } from './audio-context.js';
|
||||
import { getButterchurnPresets } from './visualizers/butterchurn.js';
|
||||
|
|
@ -774,6 +775,17 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
|||
});
|
||||
}
|
||||
|
||||
// Exponential Volume Toggle
|
||||
const exponentialVolumeToggle = document.getElementById('exponential-volume-toggle');
|
||||
if (exponentialVolumeToggle) {
|
||||
exponentialVolumeToggle.checked = exponentialVolumeSettings.isEnabled();
|
||||
exponentialVolumeToggle.addEventListener('change', (e) => {
|
||||
exponentialVolumeSettings.setEnabled(e.target.checked);
|
||||
// Re-apply current volume to use new curve
|
||||
player.applyReplayGain();
|
||||
});
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 16-Band Equalizer Settings
|
||||
// ========================================
|
||||
|
|
|
|||
|
|
@ -860,6 +860,41 @@ export const monoAudioSettings = {
|
|||
},
|
||||
};
|
||||
|
||||
export const exponentialVolumeSettings = {
|
||||
STORAGE_KEY: 'exponential-volume-enabled',
|
||||
|
||||
isEnabled() {
|
||||
try {
|
||||
return localStorage.getItem(this.STORAGE_KEY) === 'true';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
setEnabled(enabled) {
|
||||
localStorage.setItem(this.STORAGE_KEY, enabled ? 'true' : 'false');
|
||||
},
|
||||
|
||||
// Apply exponential curve to linear volume (0-1)
|
||||
// Uses a power curve: output = input^3 for more natural volume control
|
||||
applyCurve(linearVolume) {
|
||||
if (!this.isEnabled()) {
|
||||
return linearVolume;
|
||||
}
|
||||
// Exponential curve: cubed for much finer low-volume control
|
||||
// This creates a more dramatic difference that you'll actually notice
|
||||
return Math.pow(linearVolume, 3);
|
||||
},
|
||||
|
||||
// Convert from perceived volume back to linear for UI
|
||||
inverseCurve(perceivedVolume) {
|
||||
if (!this.isEnabled()) {
|
||||
return perceivedVolume;
|
||||
}
|
||||
return Math.cbrt(perceivedVolume);
|
||||
},
|
||||
};
|
||||
|
||||
export const sidebarSettings = {
|
||||
STORAGE_KEY: 'monochrome-sidebar-collapsed',
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue