0
# Audio Filters
1
2
Comprehensive audio filter system including equalizer, distortion, karaoke, timescale, and plugin filters for advanced audio processing and effects. The filter system allows real-time audio manipulation to enhance playback quality and create creative audio effects.
3
4
## Capabilities
5
6
### Filter Container
7
8
The main Filters class that manages all individual filter types and applies them to players.
9
10
```python { .api }
11
class Filters:
12
def __init__(self, *, data: dict | None = None):
13
"""
14
Initialize a new Filters container.
15
16
Parameters:
17
- data: Optional filter data to initialize from
18
"""
19
20
@property
21
def volume(self) -> float | None:
22
"""
23
Player volume multiplier (0.0-5.0, where 1.0 is 100%).
24
Values >1.0 may cause clipping.
25
"""
26
27
@volume.setter
28
def volume(self, value: float) -> None:
29
"""Set the volume multiplier."""
30
31
@property
32
def equalizer(self) -> Equalizer:
33
"""15-band equalizer filter."""
34
35
@property
36
def karaoke(self) -> Karaoke:
37
"""Karaoke filter for vocal elimination."""
38
39
@property
40
def timescale(self) -> Timescale:
41
"""Timescale filter for speed/pitch/rate adjustment."""
42
43
@property
44
def tremolo(self) -> Tremolo:
45
"""Tremolo filter for volume oscillation."""
46
47
@property
48
def vibrato(self) -> Vibrato:
49
"""Vibrato filter for pitch oscillation."""
50
51
@property
52
def rotation(self) -> Rotation:
53
"""Rotation filter for audio panning effects."""
54
55
@property
56
def distortion(self) -> Distortion:
57
"""Distortion filter for audio distortion effects."""
58
59
@property
60
def channel_mix(self) -> ChannelMix:
61
"""Channel mix filter for stereo channel manipulation."""
62
63
@property
64
def low_pass(self) -> LowPass:
65
"""Low pass filter for high frequency suppression."""
66
67
@property
68
def plugin_filters(self) -> PluginFilters:
69
"""Custom plugin filters for Lavalink plugins."""
70
71
def set_filters(self, **filters) -> None:
72
"""
73
Set multiple filters at once.
74
75
Parameters:
76
- volume: float - Volume multiplier
77
- equalizer: Equalizer - Equalizer filter
78
- karaoke: Karaoke - Karaoke filter
79
- timescale: Timescale - Timescale filter
80
- tremolo: Tremolo - Tremolo filter
81
- vibrato: Vibrato - Vibrato filter
82
- rotation: Rotation - Rotation filter
83
- distortion: Distortion - Distortion filter
84
- channel_mix: ChannelMix - Channel mix filter
85
- low_pass: LowPass - Low pass filter
86
- plugin_filters: PluginFilters - Plugin filters
87
- reset: bool - Whether to reset unspecified filters
88
"""
89
90
def reset(self) -> None:
91
"""Reset all filters to their default states."""
92
93
@classmethod
94
def from_filters(cls, **filters) -> Self:
95
"""
96
Create a new Filters instance with specified filters.
97
98
Parameters:
99
- **filters: Filter parameters (same as set_filters)
100
101
Returns:
102
Filters: New Filters instance
103
"""
104
105
def __call__(self) -> dict:
106
"""
107
Get the raw filter payload for Lavalink.
108
109
Returns:
110
dict: Filter payload data
111
"""
112
```
113
114
### Equalizer Filter
115
116
15-band equalizer for frequency-specific volume adjustment.
117
118
```python { .api }
119
class Equalizer:
120
def __init__(self, payload: list[dict] | None = None):
121
"""
122
Initialize equalizer with optional band data.
123
124
Parameters:
125
- payload: List of band configurations
126
"""
127
128
def set(self, *, bands: list[dict] | None = None) -> Self:
129
"""
130
Set equalizer bands.
131
132
Parameters:
133
- bands: List of dicts with 'band' (0-14) and 'gain' (-0.25 to 1.0) keys
134
135
Returns:
136
Self: This equalizer instance for chaining
137
138
Note:
139
- Band 0-14 represent different frequency ranges
140
- Gain -0.25 = muted, 0.0 = unchanged, 1.0 = doubled
141
- This method resets ALL bands, use payload property for selective changes
142
"""
143
144
def reset(self) -> Self:
145
"""
146
Reset all bands to 0.0 gain.
147
148
Returns:
149
Self: This equalizer instance for chaining
150
"""
151
152
@property
153
def payload(self) -> dict[int, dict]:
154
"""
155
Raw equalizer band data (copy).
156
157
Returns:
158
dict: Band data keyed by band number (0-14)
159
"""
160
```
161
162
### Karaoke Filter
163
164
Vocal elimination filter using equalization techniques.
165
166
```python { .api }
167
class Karaoke:
168
def __init__(self, payload: dict):
169
"""
170
Initialize karaoke filter.
171
172
Parameters:
173
- payload: Karaoke configuration data
174
"""
175
176
def set(
177
self,
178
*,
179
level: float | None = None,
180
mono_level: float | None = None,
181
filter_band: float | None = None,
182
filter_width: float | None = None
183
) -> Self:
184
"""
185
Configure karaoke filter parameters.
186
187
Parameters:
188
- level: Effect level (0.0-1.0)
189
- mono_level: Mono level (0.0-1.0)
190
- filter_band: Filter band frequency in Hz
191
- filter_width: Filter width
192
193
Returns:
194
Self: This karaoke instance for chaining
195
"""
196
197
def reset(self) -> Self:
198
"""
199
Reset karaoke filter to defaults.
200
201
Returns:
202
Self: This karaoke instance for chaining
203
"""
204
205
@property
206
def payload(self) -> dict:
207
"""Raw karaoke filter data (copy)."""
208
```
209
210
### Timescale Filter
211
212
Speed, pitch, and rate modification filter.
213
214
```python { .api }
215
class Timescale:
216
def __init__(self, payload: dict):
217
"""
218
Initialize timescale filter.
219
220
Parameters:
221
- payload: Timescale configuration data
222
"""
223
224
def set(
225
self,
226
*,
227
speed: float | None = None,
228
pitch: float | None = None,
229
rate: float | None = None
230
) -> Self:
231
"""
232
Configure timescale parameters.
233
234
Parameters:
235
- speed: Playback speed multiplier
236
- pitch: Pitch adjustment multiplier
237
- rate: Rate adjustment multiplier
238
239
Returns:
240
Self: This timescale instance for chaining
241
"""
242
243
def reset(self) -> Self:
244
"""
245
Reset timescale filter to defaults.
246
247
Returns:
248
Self: This timescale instance for chaining
249
"""
250
251
@property
252
def payload(self) -> dict:
253
"""Raw timescale filter data (copy)."""
254
```
255
256
### Tremolo Filter
257
258
Volume oscillation effect filter.
259
260
```python { .api }
261
class Tremolo:
262
def __init__(self, payload: dict):
263
"""
264
Initialize tremolo filter.
265
266
Parameters:
267
- payload: Tremolo configuration data
268
"""
269
270
def set(
271
self,
272
*,
273
frequency: float | None = None,
274
depth: float | None = None
275
) -> Self:
276
"""
277
Configure tremolo parameters.
278
279
Parameters:
280
- frequency: Oscillation frequency in Hz
281
- depth: Effect depth (0.0-1.0)
282
283
Returns:
284
Self: This tremolo instance for chaining
285
"""
286
287
def reset(self) -> Self:
288
"""
289
Reset tremolo filter to defaults.
290
291
Returns:
292
Self: This tremolo instance for chaining
293
"""
294
295
@property
296
def payload(self) -> dict:
297
"""Raw tremolo filter data (copy)."""
298
```
299
300
### Vibrato Filter
301
302
Pitch oscillation effect filter.
303
304
```python { .api }
305
class Vibrato:
306
def __init__(self, payload: dict):
307
"""
308
Initialize vibrato filter.
309
310
Parameters:
311
- payload: Vibrato configuration data
312
"""
313
314
def set(
315
self,
316
*,
317
frequency: float | None = None,
318
depth: float | None = None
319
) -> Self:
320
"""
321
Configure vibrato parameters.
322
323
Parameters:
324
- frequency: Oscillation frequency in Hz
325
- depth: Effect depth (0.0-1.0)
326
327
Returns:
328
Self: This vibrato instance for chaining
329
"""
330
331
def reset(self) -> Self:
332
"""
333
Reset vibrato filter to defaults.
334
335
Returns:
336
Self: This vibrato instance for chaining
337
"""
338
339
@property
340
def payload(self) -> dict:
341
"""Raw vibrato filter data (copy)."""
342
```
343
344
### Rotation Filter
345
346
Audio panning and stereo rotation effects.
347
348
```python { .api }
349
class Rotation:
350
def __init__(self, payload: dict):
351
"""
352
Initialize rotation filter.
353
354
Parameters:
355
- payload: Rotation configuration data
356
"""
357
358
def set(self, *, rotation_hz: float | None = None) -> Self:
359
"""
360
Configure rotation frequency.
361
362
Parameters:
363
- rotation_hz: Rotation frequency in Hz (0.2 is similar to example effects)
364
365
Returns:
366
Self: This rotation instance for chaining
367
"""
368
369
def reset(self) -> Self:
370
"""
371
Reset rotation filter to defaults.
372
373
Returns:
374
Self: This rotation instance for chaining
375
"""
376
377
@property
378
def payload(self) -> dict:
379
"""Raw rotation filter data (copy)."""
380
```
381
382
### Distortion Filter
383
384
Audio distortion effects filter.
385
386
```python { .api }
387
class Distortion:
388
def __init__(self, payload: dict):
389
"""
390
Initialize distortion filter.
391
392
Parameters:
393
- payload: Distortion configuration data
394
"""
395
396
def set(
397
self,
398
*,
399
sin_offset: float | None = None,
400
sin_scale: float | None = None,
401
cos_offset: float | None = None,
402
cos_scale: float | None = None,
403
tan_offset: float | None = None,
404
tan_scale: float | None = None,
405
offset: float | None = None,
406
scale: float | None = None
407
) -> Self:
408
"""
409
Configure distortion parameters.
410
411
Parameters:
412
- sin_offset: Sine offset value
413
- sin_scale: Sine scale multiplier
414
- cos_offset: Cosine offset value
415
- cos_scale: Cosine scale multiplier
416
- tan_offset: Tangent offset value
417
- tan_scale: Tangent scale multiplier
418
- offset: General offset value
419
- scale: General scale multiplier
420
421
Returns:
422
Self: This distortion instance for chaining
423
"""
424
425
def reset(self) -> Self:
426
"""
427
Reset distortion filter to defaults.
428
429
Returns:
430
Self: This distortion instance for chaining
431
"""
432
433
@property
434
def payload(self) -> dict:
435
"""Raw distortion filter data (copy)."""
436
```
437
438
### Channel Mix Filter
439
440
Left/right channel mixing and manipulation.
441
442
```python { .api }
443
class ChannelMix:
444
def __init__(self, payload: dict):
445
"""
446
Initialize channel mix filter.
447
448
Parameters:
449
- payload: Channel mix configuration data
450
"""
451
452
def set(
453
self,
454
*,
455
left_to_left: float | None = None,
456
left_to_right: float | None = None,
457
right_to_left: float | None = None,
458
right_to_right: float | None = None
459
) -> Self:
460
"""
461
Configure channel mixing factors.
462
463
Parameters:
464
- left_to_left: Left channel to left output (0.0-1.0)
465
- left_to_right: Left channel to right output (0.0-1.0)
466
- right_to_left: Right channel to left output (0.0-1.0)
467
- right_to_right: Right channel to right output (0.0-1.0)
468
469
Returns:
470
Self: This channel mix instance for chaining
471
472
Note:
473
- Default values keep channels independent
474
- Setting all to 0.5 creates mono output
475
"""
476
477
def reset(self) -> Self:
478
"""
479
Reset channel mix filter to defaults.
480
481
Returns:
482
Self: This channel mix instance for chaining
483
"""
484
485
@property
486
def payload(self) -> dict:
487
"""Raw channel mix filter data (copy)."""
488
```
489
490
### Low Pass Filter
491
492
High frequency suppression filter.
493
494
```python { .api }
495
class LowPass:
496
def __init__(self, payload: dict):
497
"""
498
Initialize low pass filter.
499
500
Parameters:
501
- payload: Low pass configuration data
502
"""
503
504
def set(self, *, smoothing: float | None = None) -> Self:
505
"""
506
Configure low pass smoothing.
507
508
Parameters:
509
- smoothing: Smoothing factor (>1.0 to enable, <=1.0 disables)
510
511
Returns:
512
Self: This low pass instance for chaining
513
"""
514
515
def reset(self) -> Self:
516
"""
517
Reset low pass filter to defaults.
518
519
Returns:
520
Self: This low pass instance for chaining
521
"""
522
523
@property
524
def payload(self) -> dict:
525
"""Raw low pass filter data (copy)."""
526
```
527
528
### Plugin Filters
529
530
Custom filters for Lavalink plugins.
531
532
```python { .api }
533
class PluginFilters:
534
def __init__(self, payload: dict[str, Any]):
535
"""
536
Initialize plugin filters.
537
538
Parameters:
539
- payload: Plugin filter configuration data
540
"""
541
542
def set(self, **options: dict[str, Any]) -> Self:
543
"""
544
Set plugin-specific filter values.
545
546
Parameters:
547
- **options: Plugin filter options in format:
548
pluginName={"filterKey": "filterValue", ...}
549
550
Returns:
551
Self: This plugin filters instance for chaining
552
553
Example:
554
plugin_filters.set(pluginName={"filterKey": "filterValue"})
555
"""
556
557
def reset(self) -> Self:
558
"""
559
Reset all plugin filters to defaults.
560
561
Returns:
562
Self: This plugin filters instance for chaining
563
"""
564
565
@property
566
def payload(self) -> dict[str, Any]:
567
"""Raw plugin filter data (copy)."""
568
```
569
570
## Usage Examples
571
572
### Basic Filter Application
573
574
```python
575
import wavelink
576
577
@bot.command()
578
async def bass_boost(ctx, level: int = 3):
579
"""Apply bass boost using equalizer."""
580
player = ctx.voice_client
581
if not player:
582
return await ctx.send("Not connected to a voice channel!")
583
584
# Get current filters
585
filters = player.filters
586
587
# Configure bass boost (boost low frequencies)
588
bass_bands = [
589
{"band": 0, "gain": level * 0.05}, # 25Hz
590
{"band": 1, "gain": level * 0.04}, # 40Hz
591
{"band": 2, "gain": level * 0.03}, # 63Hz
592
{"band": 3, "gain": level * 0.02}, # 100Hz
593
{"band": 4, "gain": level * 0.01}, # 160Hz
594
]
595
596
filters.equalizer.set(bands=bass_bands)
597
await player.set_filters(filters)
598
599
await ctx.send(f"Applied bass boost level {level}")
600
601
@bot.command()
602
async def nightcore(ctx):
603
"""Apply nightcore effect (higher pitch and speed)."""
604
player = ctx.voice_client
605
if not player:
606
return await ctx.send("Not connected to a voice channel!")
607
608
# Get current filters
609
filters = player.filters
610
611
# Configure nightcore timescale
612
filters.timescale.set(speed=1.3, pitch=1.3, rate=1.0)
613
614
await player.set_filters(filters)
615
await ctx.send("Applied nightcore effect!")
616
617
@bot.command()
618
async def vaporwave(ctx):
619
"""Apply vaporwave effect (lower pitch and speed)."""
620
player = ctx.voice_client
621
if not player:
622
return await ctx.send("Not connected to a voice channel!")
623
624
filters = player.filters
625
626
# Configure vaporwave timescale
627
filters.timescale.set(speed=0.8, pitch=0.8, rate=1.0)
628
629
await player.set_filters(filters)
630
await ctx.send("Applied vaporwave effect!")
631
```
632
633
### Advanced Filter Combinations
634
635
```python
636
@bot.command()
637
async def party_mode(ctx):
638
"""Apply multiple filters for party effect."""
639
player = ctx.voice_client
640
if not player:
641
return await ctx.send("Not connected to a voice channel!")
642
643
filters = player.filters
644
645
# Bass boost with equalizer
646
bass_bands = [
647
{"band": 0, "gain": 0.15},
648
{"band": 1, "gain": 0.12},
649
{"band": 2, "gain": 0.09},
650
{"band": 3, "gain": 0.06},
651
]
652
filters.equalizer.set(bands=bass_bands)
653
654
# Add tremolo for volume oscillation
655
filters.tremolo.set(frequency=2.0, depth=0.3)
656
657
# Add rotation for stereo effects
658
filters.rotation.set(rotation_hz=0.1)
659
660
# Slight volume boost
661
filters.volume = 1.2
662
663
await player.set_filters(filters)
664
await ctx.send("π Party mode activated!")
665
666
@bot.command()
667
async def robot_voice(ctx):
668
"""Apply robot voice effect."""
669
player = ctx.voice_client
670
if not player:
671
return await ctx.send("Not connected to a voice channel!")
672
673
filters = player.filters
674
675
# Distortion for robotic sound
676
filters.distortion.set(
677
sin_offset=0.0,
678
sin_scale=1.0,
679
cos_offset=0.0,
680
cos_scale=1.0,
681
tan_offset=0.0,
682
tan_scale=1.0,
683
offset=0.0,
684
scale=1.0
685
)
686
687
# Channel mix for stereo effect
688
filters.channel_mix.set(
689
left_to_left=0.8,
690
left_to_right=0.2,
691
right_to_left=0.2,
692
right_to_right=0.8
693
)
694
695
await player.set_filters(filters)
696
await ctx.send("π€ Robot voice effect applied!")
697
```
698
699
### Filter Management Commands
700
701
```python
702
@bot.command()
703
async def filters(ctx):
704
"""Show current filter status."""
705
player = ctx.voice_client
706
if not player:
707
return await ctx.send("Not connected to a voice channel!")
708
709
filters = player.filters
710
embed = discord.Embed(title="Current Filters", color=discord.Color.blue())
711
712
# Volume
713
if filters.volume is not None:
714
embed.add_field(name="Volume", value=f"{filters.volume:.2f}x", inline=True)
715
716
# Check each filter type
717
filter_info = []
718
719
# Equalizer
720
eq_active = any(band["gain"] != 0.0 for band in filters.equalizer.payload.values())
721
if eq_active:
722
filter_info.append("Equalizer")
723
724
# Timescale
725
ts_payload = filters.timescale.payload
726
if ts_payload.get("speed") or ts_payload.get("pitch") or ts_payload.get("rate"):
727
speed = ts_payload.get("speed", 1.0)
728
pitch = ts_payload.get("pitch", 1.0)
729
filter_info.append(f"Timescale (Speed: {speed:.2f}, Pitch: {pitch:.2f})")
730
731
# Other filters
732
if filters.karaoke.payload:
733
filter_info.append("Karaoke")
734
if filters.tremolo.payload:
735
filter_info.append("Tremolo")
736
if filters.vibrato.payload:
737
filter_info.append("Vibrato")
738
if filters.rotation.payload:
739
filter_info.append("Rotation")
740
if filters.distortion.payload:
741
filter_info.append("Distortion")
742
if filters.channel_mix.payload:
743
filter_info.append("Channel Mix")
744
if filters.low_pass.payload:
745
filter_info.append("Low Pass")
746
if filters.plugin_filters.payload:
747
filter_info.append("Plugin Filters")
748
749
if filter_info:
750
embed.add_field(
751
name="Active Filters",
752
value="\n".join(filter_info),
753
inline=False
754
)
755
else:
756
embed.add_field(name="Status", value="No filters active", inline=False)
757
758
await ctx.send(embed=embed)
759
760
@bot.command()
761
async def reset_filters(ctx):
762
"""Reset all filters to default."""
763
player = ctx.voice_client
764
if not player:
765
return await ctx.send("Not connected to a voice channel!")
766
767
# Reset all filters
768
await player.set_filters() # Passing None resets all filters
769
await ctx.send("β All filters reset to default!")
770
771
@bot.command()
772
async def save_filters(ctx, name: str):
773
"""Save current filter preset."""
774
player = ctx.voice_client
775
if not player:
776
return await ctx.send("Not connected to a voice channel!")
777
778
# In a real bot, you'd save this to a database
779
# This is a simple example using a dict
780
if not hasattr(bot, 'filter_presets'):
781
bot.filter_presets = {}
782
783
# Get current filter payload
784
filter_data = player.filters()
785
bot.filter_presets[name.lower()] = filter_data
786
787
await ctx.send(f"πΎ Saved current filters as preset '{name}'")
788
789
@bot.command()
790
async def load_filters(ctx, name: str):
791
"""Load a saved filter preset."""
792
player = ctx.voice_client
793
if not player:
794
return await ctx.send("Not connected to a voice channel!")
795
796
if not hasattr(bot, 'filter_presets'):
797
return await ctx.send("No filter presets saved!")
798
799
preset_name = name.lower()
800
if preset_name not in bot.filter_presets:
801
available = ", ".join(bot.filter_presets.keys())
802
return await ctx.send(f"Preset '{name}' not found! Available: {available}")
803
804
# Create filters from saved data
805
filter_data = bot.filter_presets[preset_name]
806
filters = wavelink.Filters(data=filter_data)
807
808
await player.set_filters(filters)
809
await ctx.send(f"π Loaded filter preset '{name}'")
810
```
811
812
### Custom Equalizer Presets
813
814
```python
815
# Predefined EQ presets
816
EQ_PRESETS = {
817
'flat': [], # No changes
818
'bass_boost': [
819
{"band": 0, "gain": 0.2},
820
{"band": 1, "gain": 0.15},
821
{"band": 2, "gain": 0.1},
822
{"band": 3, "gain": 0.05},
823
],
824
'treble_boost': [
825
{"band": 11, "gain": 0.1},
826
{"band": 12, "gain": 0.15},
827
{"band": 13, "gain": 0.2},
828
{"band": 14, "gain": 0.25},
829
],
830
'vocal_boost': [
831
{"band": 6, "gain": 0.1},
832
{"band": 7, "gain": 0.15},
833
{"band": 8, "gain": 0.2},
834
{"band": 9, "gain": 0.15},
835
{"band": 10, "gain": 0.1},
836
],
837
'pop': [
838
{"band": 0, "gain": 0.1},
839
{"band": 1, "gain": 0.05},
840
{"band": 7, "gain": 0.1},
841
{"band": 8, "gain": 0.15},
842
{"band": 9, "gain": 0.1},
843
{"band": 13, "gain": 0.1},
844
{"band": 14, "gain": 0.15},
845
]
846
}
847
848
@bot.command()
849
async def eq_preset(ctx, preset: str = None):
850
"""Apply or list equalizer presets."""
851
player = ctx.voice_client
852
if not player:
853
return await ctx.send("Not connected to a voice channel!")
854
855
if preset is None:
856
available = ", ".join(EQ_PRESETS.keys())
857
return await ctx.send(f"Available EQ presets: {available}")
858
859
preset_name = preset.lower()
860
if preset_name not in EQ_PRESETS:
861
available = ", ".join(EQ_PRESETS.keys())
862
return await ctx.send(f"Unknown preset! Available: {available}")
863
864
filters = player.filters
865
filters.equalizer.set(bands=EQ_PRESETS[preset_name])
866
867
await player.set_filters(filters)
868
await ctx.send(f"π΅ Applied '{preset}' EQ preset")
869
870
@bot.command()
871
async def custom_eq(ctx, *band_gains):
872
"""Set custom equalizer bands. Usage: !custom_eq 0.1 0.2 0.0 ..."""
873
player = ctx.voice_client
874
if not player:
875
return await ctx.send("Not connected to a voice channel!")
876
877
if len(band_gains) > 15:
878
return await ctx.send("Maximum 15 bands (0-14)!")
879
880
try:
881
# Parse gain values
882
gains = [float(gain) for gain in band_gains]
883
884
# Validate gain range
885
for gain in gains:
886
if not -0.25 <= gain <= 1.0:
887
return await ctx.send("Gain values must be between -0.25 and 1.0!")
888
889
# Create band configuration
890
bands = [{"band": i, "gain": gain} for i, gain in enumerate(gains)]
891
892
filters = player.filters
893
filters.equalizer.set(bands=bands)
894
await player.set_filters(filters)
895
896
await ctx.send(f"ποΈ Applied custom EQ with {len(bands)} bands")
897
898
except ValueError:
899
await ctx.send("Invalid gain values! Use numbers between -0.25 and 1.0")
900
```