mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #4318 from TelepathicWalrus/audio-normalization
This commit is contained in:
commit
2a016a6d5f
8 changed files with 74 additions and 2 deletions
|
@ -59,6 +59,7 @@
|
|||
- [Vankerkom](https://github.com/vankerkom)
|
||||
- [edvwib](https://github.com/edvwib)
|
||||
- [Rob Farraher](https://github.com/farraherbg)
|
||||
- [TelepathicWalrus](https://github.com/TelepathicWalrus)
|
||||
- [Pier-Luc Ducharme](https://github.com/pl-ducharme)
|
||||
- [Anantharaju S](https://github.com/Anantharajus)
|
||||
- [Merlin Sievers](https://github.com/dann-merlin)
|
||||
|
|
|
@ -416,6 +416,8 @@ export function setContentType(parent, contentType) {
|
|||
}
|
||||
}
|
||||
|
||||
parent.querySelector('.chkEnableLUFSScan').classList.toggle('hide', contentType !== 'music');
|
||||
|
||||
if (contentType === 'tvshows') {
|
||||
parent.querySelector('.chkEnableEmbeddedEpisodeInfosContainer').classList.remove('hide');
|
||||
} else {
|
||||
|
@ -512,6 +514,7 @@ export function getLibraryOptions(parent) {
|
|||
EnableArchiveMediaFiles: false,
|
||||
EnablePhotos: parent.querySelector('.chkEnablePhotos').checked,
|
||||
EnableRealtimeMonitor: parent.querySelector('.chkEnableRealtimeMonitor').checked,
|
||||
EnableLUFSScan: parent.querySelector('.chkEnableLUFSScan').checked,
|
||||
ExtractChapterImagesDuringLibraryScan: parent.querySelector('.chkExtractChaptersDuringLibraryScan').checked,
|
||||
EnableChapterImageExtraction: parent.querySelector('.chkExtractChapterImages').checked,
|
||||
EnableInternetProviders: true,
|
||||
|
@ -573,6 +576,7 @@ export function setLibraryOptions(parent, options) {
|
|||
parent.querySelector('#txtSeasonZeroName').value = options.SeasonZeroDisplayName || 'Specials';
|
||||
parent.querySelector('.chkEnablePhotos').checked = options.EnablePhotos;
|
||||
parent.querySelector('.chkEnableRealtimeMonitor').checked = options.EnableRealtimeMonitor;
|
||||
parent.querySelector('.chkEnableLUFSScan').checked = options.EnableLUFSScan;
|
||||
parent.querySelector('.chkExtractChaptersDuringLibraryScan').checked = options.ExtractChapterImagesDuringLibraryScan;
|
||||
parent.querySelector('.chkExtractChapterImages').checked = options.EnableChapterImageExtraction;
|
||||
parent.querySelector('#chkSaveLocal').checked = options.SaveLocalMetadata;
|
||||
|
|
|
@ -55,6 +55,14 @@
|
|||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableRealtimeMonitorHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription advanced">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkEnableLUFSScan" checked />
|
||||
<span>${LabelEnableLUFSScan}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableLUFSScanHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription chkAutomaticallyAddToCollectionContainer hide advanced">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="chkAutomaticallyAddToCollection" />
|
||||
|
|
|
@ -173,6 +173,7 @@ function loadForm(context, user, userSettings, apiClient) {
|
|||
context.querySelector('.chkPlayDefaultAudioTrack').checked = user.Configuration.PlayDefaultAudioTrack || false;
|
||||
context.querySelector('.chkPreferFmp4HlsContainer').checked = userSettings.preferFmp4HlsContainer();
|
||||
context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode();
|
||||
context.querySelector('.chkEnableAudioNormalization').checked = userSettings.enableAudioNormalization();
|
||||
context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay();
|
||||
context.querySelector('.chkRememberAudioSelections').checked = user.Configuration.RememberAudioSelections || false;
|
||||
context.querySelector('.chkRememberSubtitleSelections').checked = user.Configuration.RememberSubtitleSelections || false;
|
||||
|
@ -217,7 +218,7 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
|
|||
user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector('.chkEpisodeAutoPlay').checked;
|
||||
userSettingsInstance.preferFmp4HlsContainer(context.querySelector('.chkPreferFmp4HlsContainer').checked);
|
||||
userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked);
|
||||
|
||||
userSettingsInstance.enableAudioNormalization(context.querySelector('.chkEnableAudioNormalization').checked);
|
||||
userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked);
|
||||
user.Configuration.RememberAudioSelections = context.querySelector('.chkRememberAudioSelections').checked;
|
||||
user.Configuration.RememberSubtitleSelections = context.querySelector('.chkRememberSubtitleSelections').checked;
|
||||
|
|
|
@ -72,6 +72,14 @@
|
|||
${TabAdvanced}
|
||||
</h2>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkEnableAudioNormalization" />
|
||||
<span>${EnableAudioNormalization}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableAudioNormalizationHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkPreferFmp4HlsContainer" />
|
||||
|
|
|
@ -101,6 +101,7 @@ class HtmlAudioPlayer {
|
|||
self._currentTime = null;
|
||||
|
||||
const elem = createMediaElement();
|
||||
|
||||
return setCurrentSrc(elem, options);
|
||||
};
|
||||
|
||||
|
@ -110,6 +111,17 @@ class HtmlAudioPlayer {
|
|||
|
||||
let val = options.url;
|
||||
console.debug('playing url: ' + val);
|
||||
import('../../scripts/settings/userSettings').then((userSettings) => {
|
||||
if (userSettings.enableAudioNormalization() && options.item.LUFS != null) {
|
||||
const dbGain = -18 - options.item.LUFS;
|
||||
self.gainNode.gain.value = Math.pow(10, (dbGain / 20));
|
||||
} else {
|
||||
self.gainNode.gain.value = 1;
|
||||
}
|
||||
console.debug('gain:' + self.gainNode.gain.value);
|
||||
}).catch((err) => {
|
||||
console.error('Failed to add/change gainNode', err);
|
||||
});
|
||||
|
||||
// Convert to seconds
|
||||
const seconds = (options.playerStartPositionTicks || 0) / 10000000;
|
||||
|
@ -245,9 +257,29 @@ class HtmlAudioPlayer {
|
|||
|
||||
self._mediaElement = elem;
|
||||
|
||||
addGainElement(elem);
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function addGainElement(elem) {
|
||||
try {
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext; /* eslint-disable-line compat/compat */
|
||||
|
||||
const audioCtx = new AudioContext();
|
||||
const source = audioCtx.createMediaElementSource(elem);
|
||||
|
||||
const gainNode = audioCtx.createGain();
|
||||
|
||||
source.connect(gainNode);
|
||||
gainNode.connect(audioCtx.destination);
|
||||
|
||||
self.gainNode = gainNode;
|
||||
} catch (e) {
|
||||
console.error('Web Audio API is not supported in this browser', e);
|
||||
}
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
htmlMediaHelper.onEndedInternal(self, this, onError);
|
||||
}
|
||||
|
|
|
@ -156,6 +156,19 @@ export class UserSettings {
|
|||
return toBoolean(this.get('enableCinemaMode', false), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Enable Audio Normalization' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Enable Audio Normalization' or undefined.
|
||||
* @return {boolean} 'Enable Audio Normalization' state.
|
||||
*/
|
||||
enableAudioNormalization(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableAudioNormalization', val.toString(), false);
|
||||
}
|
||||
|
||||
return toBoolean(this.get('enableAudioNormalization', false), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Next Video Info Overlay' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Next Video Info Overlay' or undefined.
|
||||
|
@ -592,6 +605,7 @@ export const serverConfig = currentSettings.serverConfig.bind(currentSettings);
|
|||
export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(currentSettings);
|
||||
export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings);
|
||||
export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings);
|
||||
export const enableAudioNormalization = currentSettings.enableAudioNormalization.bind(currentSettings);
|
||||
export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings);
|
||||
export const enableVideoRemainingTime = currentSettings.enableVideoRemainingTime.bind(currentSettings);
|
||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
"ChannelNumber": "Channel number",
|
||||
"Channels": "Channels",
|
||||
"CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
|
||||
"EnableAudioNormalizationHelp": "Audio normalization will add a constant gain to keep the average at a desired level (-18dB).",
|
||||
"ClearQueue": "Clear queue",
|
||||
"ClientSettings": "Client Settings",
|
||||
"Collections": "Collections",
|
||||
|
@ -221,6 +222,7 @@
|
|||
"EnableBlurHash": "Enable blurred placeholders for images",
|
||||
"EnableBlurHashHelp": "Images that are still being loaded will be displayed with a unique placeholder.",
|
||||
"EnableCinemaMode": "Cinema mode",
|
||||
"EnableAudioNormalization": "Audio Normalization",
|
||||
"EnableColorCodedBackgrounds": "Color coded backgrounds",
|
||||
"EnableDecodingColorDepth10Hevc": "Enable 10-bit hardware decoding for HEVC",
|
||||
"EnableDecodingColorDepth10Vp9": "Enable 10-bit hardware decoding for VP9",
|
||||
|
@ -659,6 +661,8 @@
|
|||
"LabelEnableIP4Help": "Enable IPv4 functionality.",
|
||||
"LabelEnableIP6": "Enable IPv6",
|
||||
"LabelEnableIP6Help": "Enable IPv6 functionality.",
|
||||
"LabelEnableLUFSScan": "Enable LUFS scan",
|
||||
"LabelEnableLUFSScanHelp": "Enable LUFS scan for music (This will take longer and more resources).",
|
||||
"LabelEnableRealtimeMonitor": "Enable real time monitoring",
|
||||
"LabelEnableRealtimeMonitorHelp": "Changes to files will be processed immediately on supported file systems.",
|
||||
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue