Skip to content

Commit

Permalink
Merge branch 'main' into fix/player-state
Browse files Browse the repository at this point in the history
  • Loading branch information
EvieePy authored Sep 30, 2024
2 parents e43fe1c + 4adb979 commit 512178e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 31 deletions.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ build-backend = "setuptools.build_meta"

[project]
name = "wavelink"

version = "3.5.0"

authors = [
{ name="PythonistaGuild, EvieePy", email="[email protected]" },
]
Expand Down
2 changes: 2 additions & 0 deletions wavelink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
__author__ = "PythonistaGuild, EvieePy"
__license__ = "MIT"
__copyright__ = "Copyright 2019-Present (c) PythonistaGuild, EvieePy"

__version__ = "3.5.0"



from .enums import *
from .exceptions import *
from .filters import *
Expand Down
87 changes: 56 additions & 31 deletions wavelink/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,27 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Any, TypedDict
from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar

from .types.filters import (
ChannelMix as ChannelMixPayload,
Distortion as DistortionPayload,
Equalizer as EqualizerPayload,
FilterPayload,
Karaoke as KaraokePayload,
LowPass as LowPassPayload,
Rotation as RotationPayload,
Timescale as TimescalePayload,
Tremolo as TremoloPayload,
Vibrato as VibratoPayload,
)


if TYPE_CHECKING:
from typing_extensions import Self, Unpack

from .types.filters import (
ChannelMix as ChannelMixPayload,
Distortion as DistortionPayload,
Equalizer as EqualizerPayload,
FilterPayload,
Karaoke as KaraokePayload,
LowPass as LowPassPayload,
Rotation as RotationPayload,
Timescale as TimescalePayload,
Tremolo as TremoloPayload,
Vibrato as VibratoPayload,
)

FT = TypeVar("FT")


__all__ = (
Expand Down Expand Up @@ -108,6 +111,19 @@ class ChannelMixOptions(TypedDict):
right_to_right: float | None


class _BaseFilter(Generic[FT]):
_payload: FT

def __init__(self, payload: FT) -> None:
self._payload = payload
self._remove_none()

def _remove_none(self) -> None:
# Lavalink doesn't allow nullable types in any filters, but they are still not required...
# Passing None makes it easier for the user to remove a field...
self._payload = {k: v for k, v in self._payload.items() if v is not None} # type: ignore


class Equalizer:
"""Equalizer Filter Class.
Expand Down Expand Up @@ -182,14 +198,14 @@ def __repr__(self) -> str:
return f"<Equalizer: {self._payload}>"


class Karaoke:
class Karaoke(_BaseFilter[KaraokePayload]):
"""Karaoke Filter class.
Uses equalization to eliminate part of a band, usually targeting vocals.
"""

def __init__(self, payload: KaraokePayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[KaraokeOptions]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -214,6 +230,7 @@ def set(self, **options: Unpack[KaraokeOptions]) -> Self:
"filterBand": options.get("filter_band", self._payload.get("filterBand")),
"filterWidth": options.get("filter_width", self._payload.get("filterWidth")),
}
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -236,14 +253,14 @@ def __repr__(self) -> str:
return f"<Karaoke: {self._payload}>"


class Timescale:
class Timescale(_BaseFilter[TimescalePayload]):
"""Timescale Filter class.
Changes the speed, pitch, and rate.
"""

def __init__(self, payload: TimescalePayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[TimescalePayload]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -261,6 +278,7 @@ def set(self, **options: Unpack[TimescalePayload]) -> Self:
The rate.
"""
self._payload.update(options)
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -283,15 +301,15 @@ def __repr__(self) -> str:
return f"<Timescale: {self._payload}>"


class Tremolo:
class Tremolo(_BaseFilter[TremoloPayload]):
"""The Tremolo Filter class.
Uses amplification to create a shuddering effect, where the volume quickly oscillates.
Demo: https://en.wikipedia.org/wiki/File:Fuse_Electronics_Tremolo_MK-III_Quick_Demo.ogv
"""

def __init__(self, payload: TremoloPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[TremoloPayload]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -307,6 +325,7 @@ def set(self, **options: Unpack[TremoloPayload]) -> Self:
The tremolo depth.
"""
self._payload.update(options)
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -329,14 +348,14 @@ def __repr__(self) -> str:
return f"<Tremolo: {self._payload}>"


class Vibrato:
class Vibrato(_BaseFilter[VibratoPayload]):
"""The Vibrato Filter class.
Similar to tremolo. While tremolo oscillates the volume, vibrato oscillates the pitch.
"""

def __init__(self, payload: VibratoPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[VibratoPayload]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -352,6 +371,7 @@ def set(self, **options: Unpack[VibratoPayload]) -> Self:
The vibrato depth.
"""
self._payload.update(options)
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -374,15 +394,15 @@ def __repr__(self) -> str:
return f"<Vibrato: {self._payload}>"


class Rotation:
class Rotation(_BaseFilter[RotationPayload]):
"""The Rotation Filter class.
Rotates the sound around the stereo channels/user headphones (aka Audio Panning).
It can produce an effect similar to https://youtu.be/QB9EB8mTKcc (without the reverb).
"""

def __init__(self, payload: RotationPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[RotationOptions]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -396,6 +416,7 @@ def set(self, **options: Unpack[RotationOptions]) -> Self:
The frequency of the audio rotating around the listener in Hz. ``0.2`` is similar to the example video.
"""
self._payload: RotationPayload = {"rotationHz": options.get("rotation_hz", self._payload.get("rotationHz"))}
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -418,14 +439,14 @@ def __repr__(self) -> str:
return f"<Rotation: {self._payload}>"


class Distortion:
class Distortion(_BaseFilter[DistortionPayload]):
"""The Distortion Filter class.
According to Lavalink "It can generate some pretty unique audio effects."
"""

def __init__(self, payload: DistortionPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[DistortionOptions]) -> Self:
"""Set the properties of the this filter.
Expand Down Expand Up @@ -462,6 +483,7 @@ def set(self, **options: Unpack[DistortionOptions]) -> Self:
"offset": options.get("offset", self._payload.get("offset")),
"scale": options.get("scale", self._payload.get("scale")),
}
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -484,7 +506,7 @@ def __repr__(self) -> str:
return f"<Distortion: {self._payload}>"


class ChannelMix:
class ChannelMix(_BaseFilter[ChannelMixPayload]):
"""The ChannelMix Filter class.
Mixes both channels (left and right), with a configurable factor on how much each channel affects the other.
Expand All @@ -494,7 +516,7 @@ class ChannelMix:
"""

def __init__(self, payload: ChannelMixPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[ChannelMixOptions]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -519,6 +541,7 @@ def set(self, **options: Unpack[ChannelMixOptions]) -> Self:
"rightToLeft": options.get("right_to_left", self._payload.get("rightToLeft")),
"rightToRight": options.get("right_to_right", self._payload.get("rightToRight")),
}
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -541,15 +564,15 @@ def __repr__(self) -> str:
return f"<ChannelMix: {self._payload}>"


class LowPass:
class LowPass(_BaseFilter[LowPassPayload]):
"""The LowPass Filter class.
Higher frequencies get suppressed, while lower frequencies pass through this filter, thus the name low pass.
Any smoothing values equal to or less than ``1.0`` will disable the filter.
"""

def __init__(self, payload: LowPassPayload) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: Unpack[LowPassPayload]) -> Self:
"""Set the properties of the this filter.
Expand All @@ -563,6 +586,7 @@ def set(self, **options: Unpack[LowPassPayload]) -> Self:
The smoothing factor.
"""
self._payload.update(options)
self._remove_none()
return self

def reset(self) -> Self:
Expand All @@ -585,7 +609,7 @@ def __repr__(self) -> str:
return f"<LowPass: {self._payload}>"


class PluginFilters:
class PluginFilters(_BaseFilter[dict[str, Any]]):
"""The PluginFilters class.
This class handles setting filters on plugins that support setting filter values.
Expand All @@ -604,7 +628,7 @@ class PluginFilters:
"""

def __init__(self, payload: dict[str, Any]) -> None:
self._payload = payload
super().__init__(payload=payload)

def set(self, **options: dict[str, Any]) -> Self:
"""Set the properties of this filter.
Expand All @@ -625,6 +649,7 @@ def set(self, **options: dict[str, Any]) -> Self:
plugin_filters.set(**{"pluginName": {"filterKey": "filterValue", ...}})
"""
self._payload.update(options)
self._remove_none()
return self

def reset(self) -> Self:
Expand Down

0 comments on commit 512178e

Please sign in to comment.