# Copyright 2025 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. """Pydantic models for reverb DSP Stages.""" from typing import Literal from pydantic import BaseModel, Field, field_validator from audio_dsp.models.stage import ( StageConfig, StageModel, StageParameters, MonoPlacement, StereoPlacement, NodePlacement, ) class ReverbBaseParameters(StageParameters): """Parameters for all Reverb Stages.""" predelay: float = Field( default=15, ge=0, le=30, description="Set the predelay in milliseconds." ) pregain: float = Field( default=0.015, ge=0, le=1, description="It is not advised to increase this value above the " "default 0.015, as it can result in saturation inside " "the reverb delay lines.", ) wet_dry_mix: float = Field( default=0.5, ge=0, le=1, description=( "The mix between the wet and dry signal. When the mix is 0, the output signal is fully dry, " "when 1, the output signal is fully wet." ), ) class ReverbStereoBaseParameters(ReverbBaseParameters): """Parameters for all stereo Reverb Stages.""" width: float = Field( default=1.0, ge=0, le=1, description=( "How much stereo separation there is between the left and " "right channels. Setting width to 0 will yield a mono signal, " "whilst setting width to 1 will yield the most stereo " "separation." ), ) class ReverbBaseConfig(StageConfig): """Compile time configuration for a ReverbRoom Stage.""" max_predelay: float = Field( default=30, description="Set the maximum predelay in milliseconds." ) class _ReverbBaseModel[Placement: NodePlacement](StageModel[Placement]): """ The base class for reverb stages, containing pre delays, and wet/dry mixes and pregain. """ # op_type: is not defined as this Stage cannot be pipelined class ReverbRoomConfig(ReverbBaseConfig): """Compile time configuration for a ReverbRoom Stage.""" max_room_size: float = Field( default=1.0, gt=0, le=4, description=( "Sets the maximum room size for this reverb. The" " ``room_size`` parameter sets the fraction of this value actually used at any given time." " For optimal memory usage, max_room_size should be set so that the longest reverb tail" " occurs when ``room_size=1.0``." ), ) class ReverbRoomParameters(ReverbBaseParameters): """Parameters for a ReverbRoom Stage.""" damping: float = Field( default=0.4, ge=0, le=1, description="This controls how much high frequency attenuation " "is in the room. Higher values yield shorter " "reverberation times at high frequencies. Range: 0 to 1", ) decay: float = Field( default=0.5, ge=0, le=1, description="This sets how reverberant the room is. Higher " "values will give a longer reverberation time for " "a given room size. Range: 0 to 1", ) room_size: float = Field( default=1.0, ge=0, le=1, description="This sets how reverberant the room is. Higher " "values will give a longer reverberation time for " "a given room size. Range: 0 to 1", ) class ReverbRoomStereoConfig(ReverbRoomConfig): """Compile time configuration for a ReverbRoomStereo Stage.""" pass class ReverbRoomStereoParameters(ReverbStereoBaseParameters, ReverbRoomParameters): """Parameters for a ReverbRoomStereo Stage.""" pass class ReverbPlateStereoConfig(ReverbBaseConfig): """Compile time configuration for a ReverbPlateStereo Stage.""" pass class ReverbPlateStereoParameters(ReverbStereoBaseParameters): """Parameters for a ReverbPlateStereo Stage.""" pregain: float = Field( default=0.5, ge=0, le=1, description="It is not advised to increase this value above the " "default 0.5, as it can result in saturation inside the reverb delay lines.", ) damping: float = Field( default=0.75, ge=0, le=1, description="This controls how much high frequency attenuation is in the room. Higher " "values yield shorter reverberation times at high frequencies. Range: 0 to 1", ) decay: float = Field( default=0.4, ge=0, le=1, description="This sets how reverberant the room is. Higher " "values will give a longer reverberation time for " "a given room size. Range: 0 to 1", ) early_diffusion: float = Field( default=0.75, ge=0, le=1, description="Sets how much diffusion is present in the first part of the reverberation. Range: 0 to 1", ) late_diffusion: float = Field( default=0.7, ge=0, le=1, description="Sets how much diffusion is present in the latter part of the reverberation. Range: 0 to 1", ) bandwidth: float = Field( default=8000, ge=0, le=24000, description="Sets the low pass cutoff frequency of the reverb input.", ) class ReverbRoom(_ReverbBaseModel[MonoPlacement]): """Mono Reverb room model.""" op_type: Literal["ReverbRoom"] = "ReverbRoom" parameters: ReverbRoomParameters = Field(default_factory=ReverbRoomParameters) config: ReverbRoomConfig = Field(default_factory=ReverbRoomConfig) class ReverbRoomStereo(_ReverbBaseModel[StereoPlacement]): """Stereo Reverb room model.""" op_type: Literal["ReverbRoomStereo"] = "ReverbRoomStereo" parameters: ReverbRoomStereoParameters = Field(default_factory=ReverbRoomStereoParameters) config: ReverbRoomStereoConfig = Field(default_factory=ReverbRoomStereoConfig) class ReverbPlateStereo(_ReverbBaseModel[StereoPlacement]): """ The stereo room plate stage. This is based on Dattorro's 1997 paper. This reverb consists of 4 allpass filters for input diffusion, followed by a figure of 8 reverb tank of allpasses, low-pass filters, and delays. The output is taken from multiple taps in the delay lines to get a desirable echo density. """ op_type: Literal["ReverbPlateStereo"] = "ReverbPlateStereo" parameters: ReverbPlateStereoParameters = Field(default_factory=ReverbPlateStereoParameters) config: ReverbPlateStereoConfig = Field(default_factory=ReverbPlateStereoConfig)