Source code for pylav.players.filters.equalizer

from __future__ import annotations

import collections
from typing import Any, Final

from deepdiff import DeepDiff  # type: ignore

from pylav.players.filters.misc import FilterMixin

_SUPPORTED_BANDS: Final = 15  # 1 Indexed


[docs] class Equalizer(FilterMixin): """Class representing a usable equalizer. Parameters ------------ levels: List[Tuple[int, float]] A list of tuple pairs containing a band int and gain float. name: str An Optional string to name this Equalizer. Defaults to 'CustomEqualizer' """ __slots__ = ("_eq", "_name", "_default") def __init__(self, *, levels: list[dict[str, int | float | None]], name: str = "CustomEqualizer") -> None: super().__init__() self._eq = self._factory(levels) self._name = name
[docs] def to_dict(self) -> dict[str, list[dict[str, int | float | None]] | str | bool]: """Returns a dictionary representation of the Equalizer""" return {"equalizer": self._eq, "name": self._name}
[docs] @classmethod def from_dict(cls, data: dict[str, list[dict[str, int | float | None]] | str | bool]) -> Equalizer: """Creates an Equalizer from a dictionary""" return cls(levels=data["equalizer"], name=data["name"])
def __str__(self) -> str: return self._name def __repr__(self) -> str: return f"<Equalizer: name={self._name}, eq={self._eq}>" @property def index(self) -> dict[int, float]: d: dict[Any, float] = collections.defaultdict(float) d |= {d["band"]: d["gain"] for d in self._eq} return d
[docs] def __eq__(self, other: Any) -> bool: """Overrides the default implementation""" if isinstance(other, Equalizer): return bool( DeepDiff( self._eq, other._eq, ignore_order=True, max_passes=1, cache_size=100, exclude_paths=["root['name']"] ) ) return NotImplemented
@property def name(self) -> str: """The Equalizers friendly name""" return self._name @staticmethod def _factory(levels: list[dict[str, int | float]]) -> list[dict[str, int | float]]: if not levels: return [] if not isinstance(levels[0], dict): raise TypeError("Equalizer levels should be a list of dictionaries") _dict: dict[str, float] = collections.defaultdict(float) for level in levels: _dict[str(level["band"])] = level["gain"] return [{"band": i, "gain": _dict[str(i)]} for i in range(_SUPPORTED_BANDS) if _dict[str(i)]]
[docs] @classmethod def build(cls, *, levels: list[dict[str, int | float]], name: str = "CustomEqualizer") -> Equalizer: """Build a custom Equalizer class with the provided levels. Parameters ------------ levels: list[dict[str, int | float]] A list of dictionaries containing the band and gain for each band. name: str An Optional string to name this Equalizer. Defaults to 'CustomEqualizer' """ return cls(levels=levels, name=name)
[docs] @classmethod def flat(cls) -> Equalizer: """Flat Equalizer. Resets your EQ to Flat. """ return cls( levels=[], name="Default", )
[docs] @classmethod def default(cls) -> Equalizer: return cls.flat()
[docs] def get(self) -> list[dict[str, int | float]]: return [] if self.off else self._eq
[docs] def reset(self) -> None: eq = Equalizer.flat() self._eq = eq._eq self._name = eq._name
[docs] def set_gain(self, band: int, gain: float) -> None: if band < 0 or band >= _SUPPORTED_BANDS: raise IndexError(f"Band {band} does not exist!") band = next((index for (index, d) in enumerate(self._eq) if d["band"] == band), -1) if band == -1: raise IndexError(f"Band {band} does not exist!") gain = float(min(max(gain, -0.25), 1.0)) self._eq[band]["gain"] = gain if gain == 0.0: # Discard any redundant 0.0 gains self._eq[band].pop("gain", 0.0)
[docs] def get_gain(self, band: int) -> float: if band < 0 or band >= _SUPPORTED_BANDS: raise IndexError(f"Band {band} does not exist!") return self.index[band]
[docs] def visualise(self) -> str: block = "" bands = [str(band + 1).zfill(2) for band in range(_SUPPORTED_BANDS)] bottom = (" " * 8) + " ".join(bands) gains = [x * 0.01 for x in range(-25, 105, 5)] gains.reverse() for gain in gains: prefix = "" if gain > 0: prefix = "+" elif gain == 0: prefix = " " block += f"{prefix}{gain:.2f} | " for value in self._eq: cur_gain = value.get("gain", 0.0) block += "[] " if cur_gain >= gain else " " block += "\n" block += bottom return block