24
24
25
25
from __future__ import annotations
26
26
27
- from typing import TYPE_CHECKING , Any , TypedDict
27
+ from typing import TYPE_CHECKING , Any , Generic , TypedDict , TypeVar
28
+
29
+ from .types .filters import (
30
+ ChannelMix as ChannelMixPayload ,
31
+ Distortion as DistortionPayload ,
32
+ Equalizer as EqualizerPayload ,
33
+ FilterPayload ,
34
+ Karaoke as KaraokePayload ,
35
+ LowPass as LowPassPayload ,
36
+ Rotation as RotationPayload ,
37
+ Timescale as TimescalePayload ,
38
+ Tremolo as TremoloPayload ,
39
+ Vibrato as VibratoPayload ,
40
+ )
28
41
29
42
30
43
if TYPE_CHECKING :
31
44
from typing_extensions import Self , Unpack
32
45
33
- from .types .filters import (
34
- ChannelMix as ChannelMixPayload ,
35
- Distortion as DistortionPayload ,
36
- Equalizer as EqualizerPayload ,
37
- FilterPayload ,
38
- Karaoke as KaraokePayload ,
39
- LowPass as LowPassPayload ,
40
- Rotation as RotationPayload ,
41
- Timescale as TimescalePayload ,
42
- Tremolo as TremoloPayload ,
43
- Vibrato as VibratoPayload ,
44
- )
46
+
47
+ FT = TypeVar ("FT" )
45
48
46
49
47
50
__all__ = (
@@ -108,6 +111,19 @@ class ChannelMixOptions(TypedDict):
108
111
right_to_right : float | None
109
112
110
113
114
+ class _BaseFilter (Generic [FT ]):
115
+ _payload : FT
116
+
117
+ def __init__ (self , payload : FT ) -> None :
118
+ self ._payload = payload
119
+ self ._remove_none ()
120
+
121
+ def _remove_none (self ) -> None :
122
+ # Lavalink doesn't allow nullable types in any filters, but they are still not required...
123
+ # Passing None makes it easier for the user to remove a field...
124
+ self ._payload = {k : v for k , v in self ._payload .items () if v is not None } # type: ignore
125
+
126
+
111
127
class Equalizer :
112
128
"""Equalizer Filter Class.
113
129
@@ -182,14 +198,14 @@ def __repr__(self) -> str:
182
198
return f"<Equalizer: { self ._payload } >"
183
199
184
200
185
- class Karaoke :
201
+ class Karaoke ( _BaseFilter [ KaraokePayload ]) :
186
202
"""Karaoke Filter class.
187
203
188
204
Uses equalization to eliminate part of a band, usually targeting vocals.
189
205
"""
190
206
191
207
def __init__ (self , payload : KaraokePayload ) -> None :
192
- self . _payload = payload
208
+ super (). __init__ ( payload = payload )
193
209
194
210
def set (self , ** options : Unpack [KaraokeOptions ]) -> Self :
195
211
"""Set the properties of the this filter.
@@ -214,6 +230,7 @@ def set(self, **options: Unpack[KaraokeOptions]) -> Self:
214
230
"filterBand" : options .get ("filter_band" , self ._payload .get ("filterBand" )),
215
231
"filterWidth" : options .get ("filter_width" , self ._payload .get ("filterWidth" )),
216
232
}
233
+ self ._remove_none ()
217
234
return self
218
235
219
236
def reset (self ) -> Self :
@@ -236,14 +253,14 @@ def __repr__(self) -> str:
236
253
return f"<Karaoke: { self ._payload } >"
237
254
238
255
239
- class Timescale :
256
+ class Timescale ( _BaseFilter [ TimescalePayload ]) :
240
257
"""Timescale Filter class.
241
258
242
259
Changes the speed, pitch, and rate.
243
260
"""
244
261
245
262
def __init__ (self , payload : TimescalePayload ) -> None :
246
- self . _payload = payload
263
+ super (). __init__ ( payload = payload )
247
264
248
265
def set (self , ** options : Unpack [TimescalePayload ]) -> Self :
249
266
"""Set the properties of the this filter.
@@ -261,6 +278,7 @@ def set(self, **options: Unpack[TimescalePayload]) -> Self:
261
278
The rate.
262
279
"""
263
280
self ._payload .update (options )
281
+ self ._remove_none ()
264
282
return self
265
283
266
284
def reset (self ) -> Self :
@@ -283,15 +301,15 @@ def __repr__(self) -> str:
283
301
return f"<Timescale: { self ._payload } >"
284
302
285
303
286
- class Tremolo :
304
+ class Tremolo ( _BaseFilter [ TremoloPayload ]) :
287
305
"""The Tremolo Filter class.
288
306
289
307
Uses amplification to create a shuddering effect, where the volume quickly oscillates.
290
308
Demo: https://en.wikipedia.org/wiki/File:Fuse_Electronics_Tremolo_MK-III_Quick_Demo.ogv
291
309
"""
292
310
293
311
def __init__ (self , payload : TremoloPayload ) -> None :
294
- self . _payload = payload
312
+ super (). __init__ ( payload = payload )
295
313
296
314
def set (self , ** options : Unpack [TremoloPayload ]) -> Self :
297
315
"""Set the properties of the this filter.
@@ -307,6 +325,7 @@ def set(self, **options: Unpack[TremoloPayload]) -> Self:
307
325
The tremolo depth.
308
326
"""
309
327
self ._payload .update (options )
328
+ self ._remove_none ()
310
329
return self
311
330
312
331
def reset (self ) -> Self :
@@ -329,14 +348,14 @@ def __repr__(self) -> str:
329
348
return f"<Tremolo: { self ._payload } >"
330
349
331
350
332
- class Vibrato :
351
+ class Vibrato ( _BaseFilter [ VibratoPayload ]) :
333
352
"""The Vibrato Filter class.
334
353
335
354
Similar to tremolo. While tremolo oscillates the volume, vibrato oscillates the pitch.
336
355
"""
337
356
338
357
def __init__ (self , payload : VibratoPayload ) -> None :
339
- self . _payload = payload
358
+ super (). __init__ ( payload = payload )
340
359
341
360
def set (self , ** options : Unpack [VibratoPayload ]) -> Self :
342
361
"""Set the properties of the this filter.
@@ -352,6 +371,7 @@ def set(self, **options: Unpack[VibratoPayload]) -> Self:
352
371
The vibrato depth.
353
372
"""
354
373
self ._payload .update (options )
374
+ self ._remove_none ()
355
375
return self
356
376
357
377
def reset (self ) -> Self :
@@ -374,15 +394,15 @@ def __repr__(self) -> str:
374
394
return f"<Vibrato: { self ._payload } >"
375
395
376
396
377
- class Rotation :
397
+ class Rotation ( _BaseFilter [ RotationPayload ]) :
378
398
"""The Rotation Filter class.
379
399
380
400
Rotates the sound around the stereo channels/user headphones (aka Audio Panning).
381
401
It can produce an effect similar to https://youtu.be/QB9EB8mTKcc (without the reverb).
382
402
"""
383
403
384
404
def __init__ (self , payload : RotationPayload ) -> None :
385
- self . _payload = payload
405
+ super (). __init__ ( payload = payload )
386
406
387
407
def set (self , ** options : Unpack [RotationOptions ]) -> Self :
388
408
"""Set the properties of the this filter.
@@ -396,6 +416,7 @@ def set(self, **options: Unpack[RotationOptions]) -> Self:
396
416
The frequency of the audio rotating around the listener in Hz. ``0.2`` is similar to the example video.
397
417
"""
398
418
self ._payload : RotationPayload = {"rotationHz" : options .get ("rotation_hz" , self ._payload .get ("rotationHz" ))}
419
+ self ._remove_none ()
399
420
return self
400
421
401
422
def reset (self ) -> Self :
@@ -418,14 +439,14 @@ def __repr__(self) -> str:
418
439
return f"<Rotation: { self ._payload } >"
419
440
420
441
421
- class Distortion :
442
+ class Distortion ( _BaseFilter [ DistortionPayload ]) :
422
443
"""The Distortion Filter class.
423
444
424
445
According to Lavalink "It can generate some pretty unique audio effects."
425
446
"""
426
447
427
448
def __init__ (self , payload : DistortionPayload ) -> None :
428
- self . _payload = payload
449
+ super (). __init__ ( payload = payload )
429
450
430
451
def set (self , ** options : Unpack [DistortionOptions ]) -> Self :
431
452
"""Set the properties of the this filter.
@@ -462,6 +483,7 @@ def set(self, **options: Unpack[DistortionOptions]) -> Self:
462
483
"offset" : options .get ("offset" , self ._payload .get ("offset" )),
463
484
"scale" : options .get ("scale" , self ._payload .get ("scale" )),
464
485
}
486
+ self ._remove_none ()
465
487
return self
466
488
467
489
def reset (self ) -> Self :
@@ -484,7 +506,7 @@ def __repr__(self) -> str:
484
506
return f"<Distortion: { self ._payload } >"
485
507
486
508
487
- class ChannelMix :
509
+ class ChannelMix ( _BaseFilter [ ChannelMixPayload ]) :
488
510
"""The ChannelMix Filter class.
489
511
490
512
Mixes both channels (left and right), with a configurable factor on how much each channel affects the other.
@@ -494,7 +516,7 @@ class ChannelMix:
494
516
"""
495
517
496
518
def __init__ (self , payload : ChannelMixPayload ) -> None :
497
- self . _payload = payload
519
+ super (). __init__ ( payload = payload )
498
520
499
521
def set (self , ** options : Unpack [ChannelMixOptions ]) -> Self :
500
522
"""Set the properties of the this filter.
@@ -519,6 +541,7 @@ def set(self, **options: Unpack[ChannelMixOptions]) -> Self:
519
541
"rightToLeft" : options .get ("right_to_left" , self ._payload .get ("rightToLeft" )),
520
542
"rightToRight" : options .get ("right_to_right" , self ._payload .get ("rightToRight" )),
521
543
}
544
+ self ._remove_none ()
522
545
return self
523
546
524
547
def reset (self ) -> Self :
@@ -541,15 +564,15 @@ def __repr__(self) -> str:
541
564
return f"<ChannelMix: { self ._payload } >"
542
565
543
566
544
- class LowPass :
567
+ class LowPass ( _BaseFilter [ LowPassPayload ]) :
545
568
"""The LowPass Filter class.
546
569
547
570
Higher frequencies get suppressed, while lower frequencies pass through this filter, thus the name low pass.
548
571
Any smoothing values equal to or less than ``1.0`` will disable the filter.
549
572
"""
550
573
551
574
def __init__ (self , payload : LowPassPayload ) -> None :
552
- self . _payload = payload
575
+ super (). __init__ ( payload = payload )
553
576
554
577
def set (self , ** options : Unpack [LowPassPayload ]) -> Self :
555
578
"""Set the properties of the this filter.
@@ -563,6 +586,7 @@ def set(self, **options: Unpack[LowPassPayload]) -> Self:
563
586
The smoothing factor.
564
587
"""
565
588
self ._payload .update (options )
589
+ self ._remove_none ()
566
590
return self
567
591
568
592
def reset (self ) -> Self :
@@ -585,7 +609,7 @@ def __repr__(self) -> str:
585
609
return f"<LowPass: { self ._payload } >"
586
610
587
611
588
- class PluginFilters :
612
+ class PluginFilters ( _BaseFilter [ dict [ str , Any ]]) :
589
613
"""The PluginFilters class.
590
614
591
615
This class handles setting filters on plugins that support setting filter values.
@@ -604,7 +628,7 @@ class PluginFilters:
604
628
"""
605
629
606
630
def __init__ (self , payload : dict [str , Any ]) -> None :
607
- self . _payload = payload
631
+ super (). __init__ ( payload = payload )
608
632
609
633
def set (self , ** options : dict [str , Any ]) -> Self :
610
634
"""Set the properties of this filter.
@@ -625,6 +649,7 @@ def set(self, **options: dict[str, Any]) -> Self:
625
649
plugin_filters.set(**{"pluginName": {"filterKey": "filterValue", ...}})
626
650
"""
627
651
self ._payload .update (options )
652
+ self ._remove_none ()
628
653
return self
629
654
630
655
def reset (self ) -> Self :
0 commit comments