# How to Configure Volume Normalization and DSP Settings in Music Assistant

> Learn to configure volume normalization and DSP settings in Music Assistant. Optimize your audio with easy-to-follow steps using mass.config and ffmpeg arguments for superior sound.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: how-to-guide
- Published: 2026-06-14

---

**Music Assistant applies per-player volume normalization and DSP effects through configuration entries stored in `mass.config`, using the `VolumeNormalizationMode` enum to control loudness and the `DSPConfig` model to manage filter chains that are translated into ffmpeg arguments.**

Music Assistant is an open-source music server that provides advanced audio processing capabilities including automatic loudness normalization and customizable digital signal processing (DSP). These features are controlled through specific configuration keys and data models defined in the server codebase at `music-assistant/server`. This guide explains how to configure volume normalization and DSP settings using the internal Python API and configuration controllers.

## Understanding Volume Normalization Architecture

Volume normalization in Music Assistant operates on a per-player basis through a decision tree implemented in the audio pipeline.

### The Normalization Mode Decision Tree

The system determines how to apply gain using the **`get_normalization_mode`** function in [`music_assistant/helpers/audio.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/audio.py) (lines 92-108). This function evaluates the following criteria in order:

1. **Player-level toggle** – If `CONF_VOLUME_NORMALIZATION` is disabled for the player, the mode returns `DISABLED`.
2. **Live source bypass** – Audio-source streams (`MediaType.AUDIO_SOURCE`) skip normalization because the upstream handles loudness.
3. **Target loudness check** – If `CONF_VOLUME_NORMALIZATION_TARGET` is unset, normalization is disabled.
4. **Preference selection** – The core settings `CONF_VOLUME_NORMALIZATION_RADIO` or `CONF_VOLUME_NORMALIZATION_TRACKS` determine the preferred `VolumeNormalizationMode`.
5. **Fallback handling** – When loudness measurement is unavailable (`streamdetails.loudness is None`), the system falls back to `DYNAMIC` or `FIXED_GAIN` if the preference is `FALLBACK_DYNAMIC` or `FALLBACK_FIXED_GAIN`.

The **`VolumeNormalizationMode`** enum defines six possible behaviors:
- `DISABLED` – No gain applied
- `MEASUREMENT_ONLY` – Uses measured loudness without fallback
- `DYNAMIC` – Continuous loudness adjustment
- `FIXED_GAIN` – Static gain value
- `FALLBACK_DYNAMIC` – Falls back to dynamic processing when measurement is missing
- `FALLBACK_FIXED_GAIN` – Falls back to fixed gain when measurement is missing

### Core Configuration Keys

Normalization settings are stored in `mass.config` using constants defined in [`music_assistant/constants.py`](https://github.com/music-assistant/server/blob/main/music_assistant/constants.py):

- **`CONF_VOLUME_NORMALIZATION`** – Boolean toggle per player
- **`CONF_VOLUME_NORMALIZATION_TARGET`** – Target loudness in LUFS (default -17.0)
- **`CONF_VOLUME_NORMALIZATION_TRACKS`** – Mode preference for track playback
- **`CONF_VOLUME_NORMALIZATION_RADIO`** – Mode preference for radio streams

The measured loudness data flows through **`StreamDetails`** objects ([`music_assistant_models/streamdetails.py`](https://github.com/music-assistant/server/blob/main/music_assistant_models/streamdetails.py)), which carry `volume_normalization_mode`, `target_loudness`, and `loudness` values for each playback session.

## Understanding DSP Architecture

Digital Signal Processing in Music Assistant uses a filter-chain model that converts human-readable configuration into ffmpeg filtergraph arguments.

### The DSPConfig Model

The **`DSPConfig`** class in [`music_assistant/models/dsp.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/dsp.py) stores the complete processing chain as a JSON-serializable model containing:
- `enabled` – Boolean master switch
- `input_gain` – Pre-processing gain in dB
- `output_gain` – Post-processing gain in dB
- `filters` – Ordered list of filter objects (`ParametricEQFilter`, `ToneControlFilter`)

Each filter is translated to ffmpeg arguments by **`filter_to_ffmpeg_params`** in [`music_assistant/helpers/dsp.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/dsp.py) (lines 17-53).

### Runtime Integration

When you modify DSP settings, the following chain executes:

1. **`mass.config.save_dsp_config`** persists the configuration in [`music_assistant/controllers/config.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/config.py) (lines 935-950)
2. **`on_player_dsp_change`** in [`music_assistant/controllers/players/controller.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/players/controller.py) (lines 2484-2490) detects the change
3. The player restarts its ffmpeg pipeline with the new filtergraph

DSP configurations are accessed via HTTP API endpoints: `config/dsp/get`, `config/dsp/save`, and `config/dsp_presets/*`.

## Configuration Examples

### Enabling Volume Normalization

Enable normalization for a specific player and set the target loudness:

```python
from music_assistant.constants import (
    CONF_VOLUME_NORMALIZATION,
    CONF_VOLUME_NORMALIZATION_TARGET,
    CONF_VOLUME_NORMALIZATION_TRACKS
)
from music_assistant_models.enums import VolumeNormalizationMode

# Enable per-player normalization

await mass.config.set_player_config_value(
    player_id="sonos_kitchen",
    key=CONF_VOLUME_NORMALIZATION,
    value=True
)

# Set global target loudness (-17 LUFS is default)

await mass.config.set_core_config_value(
    CONF_VOLUME_NORMALIZATION_TARGET,
    -16.0
)

# Configure fallback behavior for tracks

await mass.config.set_core_config_value(
    CONF_VOLUME_NORMALIZATION_TRACKS,
    VolumeNormalizationMode.FALLBACK_DYNAMIC.value
)

```

### Configuring a Parametric EQ

Create and apply a custom EQ filter to a player:

```python
from music_assistant.models.dsp import DSPConfig, ParametricEQFilter, EQBand

# Retrieve existing config

dsp_cfg = await mass.config.get_player_dsp_config("chromecast_livingroom")

# Create 3-band parametric EQ

eq_filter = ParametricEQFilter(
    enabled=True,
    preamp=0,
    bands=[
        EQBand(frequency=100, gain=4.0, q=1.0),   # Boost bass

        EQBand(frequency=1000, gain=-2.0, q=1.0), # Cut mids

        EQBand(frequency=8000, gain=3.0, q=1.0),  # Boost treble

    ]
)

# Update configuration

dsp_cfg.enabled = True
dsp_cfg.input_gain = 0.0
dsp_cfg.output_gain = -2.0
dsp_cfg.filters.append(eq_filter)

# Persist changes - triggers pipeline restart

await mass.config.save_dsp_config("chromecast_livingroom", dsp_cfg)

```

### Setting Radio-Specific Normalization

Apply different normalization strategies for radio versus track playback:

```python

# Strict measurement-only for radio streams

await mass.config.set_core_config_value(
    CONF_VOLUME_NORMALIZATION_RADIO,
    VolumeNormalizationMode.MEASUREMENT_ONLY.value
)

# Dynamic fallback for tracks (adjusts in real-time)

await mass.config.set_core_config_value(
    CONF_VOLUME_NORMALIZATION_TRACKS,
    VolumeNormalizationMode.FALLBACK_DYNAMIC.value
)

```

## Summary

- **Volume normalization** is controlled per-player via `CONF_VOLUME_NORMALIZATION` and uses the `get_normalization_mode` function in [`music_assistant/helpers/audio.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/audio.py) to determine whether to apply `loudnorm` filters, static gain, or no processing.
- The normalization decision tree considers player toggles, media type, target LUFS settings (`CONF_VOLUME_NORMALIZATION_TARGET`), and fallback preferences for tracks versus radio.
- **DSP configuration** uses the `DSPConfig` model in [`music_assistant/models/dsp.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/dsp.py) to store filter chains, which are converted to ffmpeg arguments by `filter_to_ffmpeg_params` in [`music_assistant/helpers/dsp.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/dsp.py).
- Changes to DSP settings trigger immediate pipeline rebuilds via `on_player_dsp_change` in [`music_assistant/controllers/players/controller.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/players/controller.py).
- Both features are accessible programmatically through `mass.config` methods and via HTTP API endpoints for external integrations.

## Frequently Asked Questions

### What is the default target loudness for normalization?

The default target loudness is **-17 LUFS**, defined in the core configuration under `CONF_VOLUME_NORMALIZATION_TARGET`. You can adjust this value through `mass.config.set_core_config_value()`, but values closer to 0 dB increase the risk of clipping.

### Can I use DSP on grouped players?

**Multi-device DSP is not supported** for grouped players. When players are grouped, the system disables individual DSP processing to maintain synchronization across the group. The `is_grouping_preventing_dsp` helper in the audio module returns `True` for grouped configurations, causing the pipeline to skip DSP processing.

### What happens when I change DSP settings during playback?

When you call `save_dsp_config()`, the `on_player_dsp_change` handler in [`music_assistant/controllers/players/controller.py`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/players/controller.py) immediately triggers a pipeline restart. For single players, this rebuilds the ffmpeg filtergraph. For groups, it rebuilds the per-member DSP chain if applicable, ensuring new EQ or gain settings take effect without requiring a manual restart.

### How does fallback dynamic mode work?

**Fallback dynamic mode** (`FALLBACK_DYNAMIC`) uses the `DYNAMIC` normalization algorithm when loudness metadata is unavailable for a track. Normally, if a stream lacks loudness measurement (`streamdetails.loudness is None`), normalization would be disabled. With fallback modes enabled, the system degrades gracefully to real-time loudness analysis or fixed gain rather than disabling normalization entirely.