Chore: Simplify volume normalization a bit
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 14 Jan 2025 20:48:07 +0000 (21:48 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 14 Jan 2025 20:48:54 +0000 (21:48 +0100)
music_assistant/controllers/streams.py
music_assistant/helpers/audio.py

index 5087401ffa1bea69abac9eec5291ed9c61f9bad0..e3eba3511636fcf827c7167ee2c8329628996944 100644 (file)
@@ -914,35 +914,24 @@ class StreamsController(CoreController):
         filter_params = []
         extra_input_args = streamdetails.extra_input_args or []
         # handle volume normalization
-        enable_volume_normalization = (
-            streamdetails.target_loudness is not None
-            and streamdetails.volume_normalization_mode != VolumeNormalizationMode.DISABLED
-        )
-        dynamic_volume_normalization = (
-            streamdetails.volume_normalization_mode == VolumeNormalizationMode.DYNAMIC
-            and enable_volume_normalization
-        )
-        if dynamic_volume_normalization:
+        if streamdetails.volume_normalization_mode == VolumeNormalizationMode.DYNAMIC:
             # volume normalization using loudnorm filter (in dynamic mode)
             # which also collects the measurement on the fly during playback
             # more info: https://k.ylo.ph/2016/04/04/loudnorm.html
             filter_rule = f"loudnorm=I={streamdetails.target_loudness}:TP=-2.0:LRA=10.0:offset=0.0"
             filter_rule += ":print_format=json"
             filter_params.append(filter_rule)
-        elif (
-            enable_volume_normalization
-            and streamdetails.volume_normalization_mode == VolumeNormalizationMode.FIXED_GAIN
-        ):
+        elif streamdetails.volume_normalization_mode == VolumeNormalizationMode.FIXED_GAIN:
             # apply used defined fixed volume/gain correction
             gain_correct: float = await self.mass.config.get_core_config_value(
                 self.domain,
-                CONF_VOLUME_NORMALIZATION_FIXED_GAIN_RADIO
-                if streamdetails.media_type == MediaType.RADIO
-                else CONF_VOLUME_NORMALIZATION_FIXED_GAIN_TRACKS,
+                CONF_VOLUME_NORMALIZATION_FIXED_GAIN_TRACKS
+                if streamdetails.media_type == MediaType.TRACK
+                else CONF_VOLUME_NORMALIZATION_FIXED_GAIN_RADIO,
             )
             gain_correct = round(gain_correct, 2)
             filter_params.append(f"volume={gain_correct}dB")
-        elif enable_volume_normalization and streamdetails.loudness is not None:
+        elif streamdetails.volume_normalization_mode == VolumeNormalizationMode.MEASUREMENT_ONLY:
             # volume normalization with known loudness measurement
             # apply volume/gain correction
             gain_correct = streamdetails.target_loudness - streamdetails.loudness
@@ -987,7 +976,11 @@ class StreamsController(CoreController):
             # pad some silence before the radio stream starts to create some headroom
             # for radio stations that do not provide any look ahead buffer
             # without this, some radio streams jitter a lot, especially with dynamic normalization
-            pad_seconds = 5 if dynamic_volume_normalization else 2
+            pad_seconds = (
+                5
+                if streamdetails.volume_normalization_mode == VolumeNormalizationMode.DYNAMIC
+                else 2
+            )
             async for chunk in get_silence(pad_seconds, pcm_format):
                 yield chunk
 
index 3d82d92d0475e3726ccc28b813bea4bfca4ea4e8..47e9ec704d25d6f8f95fbb60b6251e6c995c457a 100644 (file)
@@ -264,10 +264,10 @@ async def get_stream_details(
     streamdetails.prefer_album_loudness = prefer_album_loudness
     player_settings = await mass.config.get_player_config(streamdetails.queue_id)
     core_config = await mass.config.get_core_config("streams")
+    streamdetails.target_loudness = player_settings.get_value(CONF_VOLUME_NORMALIZATION_TARGET)
     streamdetails.volume_normalization_mode = _get_normalization_mode(
         core_config, player_settings, streamdetails
     )
-    streamdetails.target_loudness = player_settings.get_value(CONF_VOLUME_NORMALIZATION_TARGET)
 
     process_time = int((time.time() - time_start) * 1000)
     LOGGER.debug(
@@ -311,7 +311,7 @@ async def get_media_stream(
         await ffmpeg_proc.start()
         logger.debug(
             "Started media stream for %s"
-            " - using streamtype: %s "
+            " - using streamtype: %s"
             " - volume normalization: %s"
             " - pcm format: %s"
             " - ffmpeg PID: %s",
@@ -993,6 +993,9 @@ def _get_normalization_mode(
     if not player_config.get_value(CONF_VOLUME_NORMALIZATION):
         # disabled for this player
         return VolumeNormalizationMode.DISABLED
+    if streamdetails.target_loudness is None:
+        # no target loudness set, disable normalization
+        return VolumeNormalizationMode.DISABLED
     # work out preference for track or radio
     preference = VolumeNormalizationMode(
         core_config.get_value(
@@ -1014,5 +1017,12 @@ def _get_normalization_mode(
     if streamdetails.loudness is None and preference == VolumeNormalizationMode.FALLBACK_FIXED_GAIN:
         return VolumeNormalizationMode.FIXED_GAIN
 
+    # handle measurement available - chosen mode is measurement
+    if streamdetails.loudness and preference not in (
+        VolumeNormalizationMode.DISABLED,
+        VolumeNormalizationMode.FIXED_GAIN,
+    ):
+        return VolumeNormalizationMode.MEASUREMENT_ONLY
+
     # simply return the preference
     return preference