diff --git a/src/components/QualityDetailsBtn.vue b/src/components/QualityDetailsBtn.vue index e0cff21f..a777e9bd 100644 --- a/src/components/QualityDetailsBtn.vue +++ b/src/components/QualityDetailsBtn.vue @@ -59,7 +59,7 @@
- {{ streamDetails.target_loudness }} dB + {{ loudness }}
@@ -85,12 +85,44 @@ import { computed } from 'vue'; import ProviderIcon from '@/components/ProviderIcon.vue'; import api from '@/plugins/api'; import { store } from '@/plugins/store'; -import { ContentType } from '@/plugins/api/interfaces'; +import { ContentType, VolumeNormalizationMode } from '@/plugins/api/interfaces'; +import { $t } from '@/plugins/i18n'; // computed properties const streamDetails = computed(() => { return store.activePlayerQueue?.current_item?.streamdetails; }); +const loudness = computed(() => { + let sd = streamDetails.value; + if (!sd) return null; + + if ( + (sd.volume_normalization_mode == VolumeNormalizationMode.MEASUREMENT_ONLY || + sd.volume_normalization_mode == + VolumeNormalizationMode.FALLBACK_FIXED_GAIN || + sd.volume_normalization_mode == + VolumeNormalizationMode.FALLBACK_DYNAMIC) && + sd.loudness !== null + ) { + if (sd.prefer_album_loudness && sd.loudness_album !== null) { + return $t('loudness_measurement_album', [sd.loudness_album?.toFixed(2)]); + } else { + return $t('loudness_measurement', [sd.loudness?.toFixed(2)]); + } + } else if ( + sd.volume_normalization_mode == VolumeNormalizationMode.DYNAMIC || + sd.volume_normalization_mode == VolumeNormalizationMode.FALLBACK_DYNAMIC + ) { + return $t('loudness_dynamic'); + } else if ( + sd.volume_normalization_mode == VolumeNormalizationMode.FIXED_GAIN || + sd.volume_normalization_mode == VolumeNormalizationMode.FALLBACK_FIXED_GAIN + ) { + return $t('loudness_fixed'); + } else { + return null; + } +}); const getContentTypeIcon = function (contentType: ContentType) { if (contentType == ContentType.AAC) return iconAac; if (contentType == ContentType.FLAC) return iconFlac; diff --git a/src/plugins/api/interfaces.ts b/src/plugins/api/interfaces.ts index f79e5e99..955be6fd 100644 --- a/src/plugins/api/interfaces.ts +++ b/src/plugins/api/interfaces.ts @@ -190,6 +190,15 @@ export enum ConfigEntryType { ALERT = 'alert', } +export enum VolumeNormalizationMode { + DISABLED = 'disabled', + DYNAMIC = 'dynamic', // Force dynamic + MEASUREMENT_ONLY = 'measurement_only', // Measurement only (no fallback) + FALLBACK_FIXED_GAIN = 'fallback_fixed_gain', // Fallback to gain correction + FIXED_GAIN = 'fixed_gain', // Fixed gain correction + FALLBACK_DYNAMIC = 'fallback_dynamic', // Fallback to dynamic +} + //// api export interface CommandMessage { @@ -479,14 +488,6 @@ export interface AudioFormat { bit_rate: number; } -export interface LoudnessMeasurement { - integrated: number; - true_peak: number; - lra: number; - threshold: number; - target_offset: number; -} - export interface StreamDetails { provider: string; item_id: string; @@ -494,10 +495,13 @@ export interface StreamDetails { media_type: MediaType; stream_title?: string; duration?: number; + loudness?: number; + loudness_album?: number; + prefer_album_loudness?: boolean; + volume_normalization_mode?: VolumeNormalizationMode; + target_loudness?: number; queue_id?: string; - loudness?: LoudnessMeasurement; - target_loudness?: number; } // queue_item diff --git a/src/translations/en.json b/src/translations/en.json index b694e08a..d667f31e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -525,5 +525,9 @@ "image_make_primary": "Make primary", "update_metadata": "Update metadata", "cancel": "Cancel", - "transfer_queue": "Transfer queue to another player" + "transfer_queue": "Transfer queue to another player", + "loudness_measurement": "{0} LUFS", + "loudness_measurement_album": "{0} LUFS (album)", + "loudness_dynamic": "Dynamic volume normalization", + "loudness_fixed": "Fixed gain correction" }