CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-wavelink

A robust and powerful, fully asynchronous Lavalink wrapper built for discord.py in Python.

Overview
Eval results
Files

audio-filters.mddocs/

Audio Filters

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.

Capabilities

Filter Container

The main Filters class that manages all individual filter types and applies them to players.

class Filters:
    def __init__(self, *, data: dict | None = None):
        """
        Initialize a new Filters container.
        
        Parameters:
        - data: Optional filter data to initialize from
        """
    
    @property
    def volume(self) -> float | None:
        """
        Player volume multiplier (0.0-5.0, where 1.0 is 100%).
        Values >1.0 may cause clipping.
        """
    
    @volume.setter
    def volume(self, value: float) -> None:
        """Set the volume multiplier."""
    
    @property
    def equalizer(self) -> Equalizer:
        """15-band equalizer filter."""
    
    @property
    def karaoke(self) -> Karaoke:
        """Karaoke filter for vocal elimination."""
    
    @property
    def timescale(self) -> Timescale:
        """Timescale filter for speed/pitch/rate adjustment."""
    
    @property
    def tremolo(self) -> Tremolo:
        """Tremolo filter for volume oscillation."""
    
    @property
    def vibrato(self) -> Vibrato:
        """Vibrato filter for pitch oscillation."""
    
    @property
    def rotation(self) -> Rotation:
        """Rotation filter for audio panning effects."""
    
    @property
    def distortion(self) -> Distortion:
        """Distortion filter for audio distortion effects."""
    
    @property
    def channel_mix(self) -> ChannelMix:
        """Channel mix filter for stereo channel manipulation."""
    
    @property
    def low_pass(self) -> LowPass:
        """Low pass filter for high frequency suppression."""
    
    @property
    def plugin_filters(self) -> PluginFilters:
        """Custom plugin filters for Lavalink plugins."""
    
    def set_filters(self, **filters) -> None:
        """
        Set multiple filters at once.
        
        Parameters:
        - volume: float - Volume multiplier
        - equalizer: Equalizer - Equalizer filter
        - karaoke: Karaoke - Karaoke filter
        - timescale: Timescale - Timescale filter
        - tremolo: Tremolo - Tremolo filter
        - vibrato: Vibrato - Vibrato filter
        - rotation: Rotation - Rotation filter
        - distortion: Distortion - Distortion filter
        - channel_mix: ChannelMix - Channel mix filter
        - low_pass: LowPass - Low pass filter
        - plugin_filters: PluginFilters - Plugin filters
        - reset: bool - Whether to reset unspecified filters
        """
    
    def reset(self) -> None:
        """Reset all filters to their default states."""
    
    @classmethod
    def from_filters(cls, **filters) -> Self:
        """
        Create a new Filters instance with specified filters.
        
        Parameters:
        - **filters: Filter parameters (same as set_filters)
        
        Returns:
        Filters: New Filters instance
        """
    
    def __call__(self) -> dict:
        """
        Get the raw filter payload for Lavalink.
        
        Returns:
        dict: Filter payload data
        """

Equalizer Filter

15-band equalizer for frequency-specific volume adjustment.

class Equalizer:
    def __init__(self, payload: list[dict] | None = None):
        """
        Initialize equalizer with optional band data.
        
        Parameters:
        - payload: List of band configurations
        """
    
    def set(self, *, bands: list[dict] | None = None) -> Self:
        """
        Set equalizer bands.
        
        Parameters:
        - bands: List of dicts with 'band' (0-14) and 'gain' (-0.25 to 1.0) keys
        
        Returns:
        Self: This equalizer instance for chaining
        
        Note:
        - Band 0-14 represent different frequency ranges
        - Gain -0.25 = muted, 0.0 = unchanged, 1.0 = doubled
        - This method resets ALL bands, use payload property for selective changes
        """
    
    def reset(self) -> Self:
        """
        Reset all bands to 0.0 gain.
        
        Returns:
        Self: This equalizer instance for chaining
        """
    
    @property
    def payload(self) -> dict[int, dict]:
        """
        Raw equalizer band data (copy).
        
        Returns:
        dict: Band data keyed by band number (0-14)
        """

Karaoke Filter

Vocal elimination filter using equalization techniques.

class Karaoke:
    def __init__(self, payload: dict):
        """
        Initialize karaoke filter.
        
        Parameters:
        - payload: Karaoke configuration data
        """
    
    def set(
        self,
        *,
        level: float | None = None,
        mono_level: float | None = None,
        filter_band: float | None = None,
        filter_width: float | None = None
    ) -> Self:
        """
        Configure karaoke filter parameters.
        
        Parameters:
        - level: Effect level (0.0-1.0)
        - mono_level: Mono level (0.0-1.0) 
        - filter_band: Filter band frequency in Hz
        - filter_width: Filter width
        
        Returns:
        Self: This karaoke instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset karaoke filter to defaults.
        
        Returns:
        Self: This karaoke instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw karaoke filter data (copy)."""

Timescale Filter

Speed, pitch, and rate modification filter.

class Timescale:
    def __init__(self, payload: dict):
        """
        Initialize timescale filter.
        
        Parameters:
        - payload: Timescale configuration data
        """
    
    def set(
        self,
        *,
        speed: float | None = None,
        pitch: float | None = None,
        rate: float | None = None
    ) -> Self:
        """
        Configure timescale parameters.
        
        Parameters:
        - speed: Playback speed multiplier
        - pitch: Pitch adjustment multiplier
        - rate: Rate adjustment multiplier
        
        Returns:
        Self: This timescale instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset timescale filter to defaults.
        
        Returns:
        Self: This timescale instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw timescale filter data (copy)."""

Tremolo Filter

Volume oscillation effect filter.

class Tremolo:
    def __init__(self, payload: dict):
        """
        Initialize tremolo filter.
        
        Parameters:
        - payload: Tremolo configuration data
        """
    
    def set(
        self,
        *,
        frequency: float | None = None,
        depth: float | None = None
    ) -> Self:
        """
        Configure tremolo parameters.
        
        Parameters:
        - frequency: Oscillation frequency in Hz
        - depth: Effect depth (0.0-1.0)
        
        Returns:
        Self: This tremolo instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset tremolo filter to defaults.
        
        Returns:
        Self: This tremolo instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw tremolo filter data (copy)."""

Vibrato Filter

Pitch oscillation effect filter.

class Vibrato:
    def __init__(self, payload: dict):
        """
        Initialize vibrato filter.
        
        Parameters:
        - payload: Vibrato configuration data
        """
    
    def set(
        self,
        *,
        frequency: float | None = None,
        depth: float | None = None
    ) -> Self:
        """
        Configure vibrato parameters.
        
        Parameters:
        - frequency: Oscillation frequency in Hz
        - depth: Effect depth (0.0-1.0)
        
        Returns:
        Self: This vibrato instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset vibrato filter to defaults.
        
        Returns:
        Self: This vibrato instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw vibrato filter data (copy)."""

Rotation Filter

Audio panning and stereo rotation effects.

class Rotation:
    def __init__(self, payload: dict):
        """
        Initialize rotation filter.
        
        Parameters:
        - payload: Rotation configuration data
        """
    
    def set(self, *, rotation_hz: float | None = None) -> Self:
        """
        Configure rotation frequency.
        
        Parameters:
        - rotation_hz: Rotation frequency in Hz (0.2 is similar to example effects)
        
        Returns:
        Self: This rotation instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset rotation filter to defaults.
        
        Returns:
        Self: This rotation instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw rotation filter data (copy)."""

Distortion Filter

Audio distortion effects filter.

class Distortion:
    def __init__(self, payload: dict):
        """
        Initialize distortion filter.
        
        Parameters:
        - payload: Distortion configuration data
        """
    
    def set(
        self,
        *,
        sin_offset: float | None = None,
        sin_scale: float | None = None,
        cos_offset: float | None = None,
        cos_scale: float | None = None,
        tan_offset: float | None = None,
        tan_scale: float | None = None,
        offset: float | None = None,
        scale: float | None = None
    ) -> Self:
        """
        Configure distortion parameters.
        
        Parameters:
        - sin_offset: Sine offset value
        - sin_scale: Sine scale multiplier
        - cos_offset: Cosine offset value
        - cos_scale: Cosine scale multiplier
        - tan_offset: Tangent offset value
        - tan_scale: Tangent scale multiplier
        - offset: General offset value
        - scale: General scale multiplier
        
        Returns:
        Self: This distortion instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset distortion filter to defaults.
        
        Returns:
        Self: This distortion instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw distortion filter data (copy)."""

Channel Mix Filter

Left/right channel mixing and manipulation.

class ChannelMix:
    def __init__(self, payload: dict):
        """
        Initialize channel mix filter.
        
        Parameters:
        - payload: Channel mix configuration data
        """
    
    def set(
        self,
        *,
        left_to_left: float | None = None,
        left_to_right: float | None = None,
        right_to_left: float | None = None,
        right_to_right: float | None = None
    ) -> Self:
        """
        Configure channel mixing factors.
        
        Parameters:
        - left_to_left: Left channel to left output (0.0-1.0)
        - left_to_right: Left channel to right output (0.0-1.0)
        - right_to_left: Right channel to left output (0.0-1.0)
        - right_to_right: Right channel to right output (0.0-1.0)
        
        Returns:
        Self: This channel mix instance for chaining
        
        Note:
        - Default values keep channels independent
        - Setting all to 0.5 creates mono output
        """
    
    def reset(self) -> Self:
        """
        Reset channel mix filter to defaults.
        
        Returns:
        Self: This channel mix instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw channel mix filter data (copy)."""

Low Pass Filter

High frequency suppression filter.

class LowPass:
    def __init__(self, payload: dict):
        """
        Initialize low pass filter.
        
        Parameters:
        - payload: Low pass configuration data
        """
    
    def set(self, *, smoothing: float | None = None) -> Self:
        """
        Configure low pass smoothing.
        
        Parameters:
        - smoothing: Smoothing factor (>1.0 to enable, <=1.0 disables)
        
        Returns:
        Self: This low pass instance for chaining
        """
    
    def reset(self) -> Self:
        """
        Reset low pass filter to defaults.
        
        Returns:
        Self: This low pass instance for chaining
        """
    
    @property
    def payload(self) -> dict:
        """Raw low pass filter data (copy)."""

Plugin Filters

Custom filters for Lavalink plugins.

class PluginFilters:
    def __init__(self, payload: dict[str, Any]):
        """
        Initialize plugin filters.
        
        Parameters:
        - payload: Plugin filter configuration data
        """
    
    def set(self, **options: dict[str, Any]) -> Self:
        """
        Set plugin-specific filter values.
        
        Parameters:
        - **options: Plugin filter options in format:
          pluginName={"filterKey": "filterValue", ...}
        
        Returns:
        Self: This plugin filters instance for chaining
        
        Example:
        plugin_filters.set(pluginName={"filterKey": "filterValue"})
        """
    
    def reset(self) -> Self:
        """
        Reset all plugin filters to defaults.
        
        Returns:
        Self: This plugin filters instance for chaining
        """
    
    @property
    def payload(self) -> dict[str, Any]:
        """Raw plugin filter data (copy)."""

Usage Examples

Basic Filter Application

import wavelink

@bot.command()
async def bass_boost(ctx, level: int = 3):
    """Apply bass boost using equalizer."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    # Get current filters
    filters = player.filters
    
    # Configure bass boost (boost low frequencies)
    bass_bands = [
        {"band": 0, "gain": level * 0.05},   # 25Hz
        {"band": 1, "gain": level * 0.04},   # 40Hz  
        {"band": 2, "gain": level * 0.03},   # 63Hz
        {"band": 3, "gain": level * 0.02},   # 100Hz
        {"band": 4, "gain": level * 0.01},   # 160Hz
    ]
    
    filters.equalizer.set(bands=bass_bands)
    await player.set_filters(filters)
    
    await ctx.send(f"Applied bass boost level {level}")

@bot.command()
async def nightcore(ctx):
    """Apply nightcore effect (higher pitch and speed)."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    # Get current filters
    filters = player.filters
    
    # Configure nightcore timescale
    filters.timescale.set(speed=1.3, pitch=1.3, rate=1.0)
    
    await player.set_filters(filters)
    await ctx.send("Applied nightcore effect!")

@bot.command()
async def vaporwave(ctx):
    """Apply vaporwave effect (lower pitch and speed)."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    filters = player.filters
    
    # Configure vaporwave timescale
    filters.timescale.set(speed=0.8, pitch=0.8, rate=1.0)
    
    await player.set_filters(filters)
    await ctx.send("Applied vaporwave effect!")

Advanced Filter Combinations

@bot.command()
async def party_mode(ctx):
    """Apply multiple filters for party effect."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    filters = player.filters
    
    # Bass boost with equalizer
    bass_bands = [
        {"band": 0, "gain": 0.15},
        {"band": 1, "gain": 0.12},
        {"band": 2, "gain": 0.09},
        {"band": 3, "gain": 0.06},
    ]
    filters.equalizer.set(bands=bass_bands)
    
    # Add tremolo for volume oscillation
    filters.tremolo.set(frequency=2.0, depth=0.3)
    
    # Add rotation for stereo effects
    filters.rotation.set(rotation_hz=0.1)
    
    # Slight volume boost
    filters.volume = 1.2
    
    await player.set_filters(filters)
    await ctx.send("🎉 Party mode activated!")

@bot.command()
async def robot_voice(ctx):
    """Apply robot voice effect."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    filters = player.filters
    
    # Distortion for robotic sound
    filters.distortion.set(
        sin_offset=0.0,
        sin_scale=1.0,
        cos_offset=0.0,
        cos_scale=1.0,
        tan_offset=0.0,
        tan_scale=1.0,
        offset=0.0,
        scale=1.0
    )
    
    # Channel mix for stereo effect
    filters.channel_mix.set(
        left_to_left=0.8,
        left_to_right=0.2,
        right_to_left=0.2,
        right_to_right=0.8
    )
    
    await player.set_filters(filters)
    await ctx.send("🤖 Robot voice effect applied!")

Filter Management Commands

@bot.command()
async def filters(ctx):
    """Show current filter status."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    filters = player.filters
    embed = discord.Embed(title="Current Filters", color=discord.Color.blue())
    
    # Volume
    if filters.volume is not None:
        embed.add_field(name="Volume", value=f"{filters.volume:.2f}x", inline=True)
    
    # Check each filter type
    filter_info = []
    
    # Equalizer
    eq_active = any(band["gain"] != 0.0 for band in filters.equalizer.payload.values())
    if eq_active:
        filter_info.append("Equalizer")
    
    # Timescale
    ts_payload = filters.timescale.payload
    if ts_payload.get("speed") or ts_payload.get("pitch") or ts_payload.get("rate"):
        speed = ts_payload.get("speed", 1.0)
        pitch = ts_payload.get("pitch", 1.0)
        filter_info.append(f"Timescale (Speed: {speed:.2f}, Pitch: {pitch:.2f})")
    
    # Other filters
    if filters.karaoke.payload:
        filter_info.append("Karaoke")
    if filters.tremolo.payload:
        filter_info.append("Tremolo")
    if filters.vibrato.payload:
        filter_info.append("Vibrato")
    if filters.rotation.payload:
        filter_info.append("Rotation")
    if filters.distortion.payload:
        filter_info.append("Distortion")
    if filters.channel_mix.payload:
        filter_info.append("Channel Mix")
    if filters.low_pass.payload:
        filter_info.append("Low Pass")
    if filters.plugin_filters.payload:
        filter_info.append("Plugin Filters")
    
    if filter_info:
        embed.add_field(
            name="Active Filters",
            value="\n".join(filter_info),
            inline=False
        )
    else:
        embed.add_field(name="Status", value="No filters active", inline=False)
    
    await ctx.send(embed=embed)

@bot.command()
async def reset_filters(ctx):
    """Reset all filters to default."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    # Reset all filters
    await player.set_filters()  # Passing None resets all filters
    await ctx.send("✅ All filters reset to default!")

@bot.command()
async def save_filters(ctx, name: str):
    """Save current filter preset."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    # In a real bot, you'd save this to a database
    # This is a simple example using a dict
    if not hasattr(bot, 'filter_presets'):
        bot.filter_presets = {}
    
    # Get current filter payload
    filter_data = player.filters()
    bot.filter_presets[name.lower()] = filter_data
    
    await ctx.send(f"💾 Saved current filters as preset '{name}'")

@bot.command()
async def load_filters(ctx, name: str):
    """Load a saved filter preset."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    if not hasattr(bot, 'filter_presets'):
        return await ctx.send("No filter presets saved!")
    
    preset_name = name.lower()
    if preset_name not in bot.filter_presets:
        available = ", ".join(bot.filter_presets.keys())
        return await ctx.send(f"Preset '{name}' not found! Available: {available}")
    
    # Create filters from saved data
    filter_data = bot.filter_presets[preset_name]
    filters = wavelink.Filters(data=filter_data)
    
    await player.set_filters(filters)
    await ctx.send(f"📂 Loaded filter preset '{name}'")

Custom Equalizer Presets

# Predefined EQ presets
EQ_PRESETS = {
    'flat': [],  # No changes
    'bass_boost': [
        {"band": 0, "gain": 0.2},
        {"band": 1, "gain": 0.15},
        {"band": 2, "gain": 0.1},
        {"band": 3, "gain": 0.05},
    ],
    'treble_boost': [
        {"band": 11, "gain": 0.1},
        {"band": 12, "gain": 0.15},
        {"band": 13, "gain": 0.2},
        {"band": 14, "gain": 0.25},
    ],
    'vocal_boost': [
        {"band": 6, "gain": 0.1},
        {"band": 7, "gain": 0.15},
        {"band": 8, "gain": 0.2},
        {"band": 9, "gain": 0.15},
        {"band": 10, "gain": 0.1},
    ],
    'pop': [
        {"band": 0, "gain": 0.1},
        {"band": 1, "gain": 0.05},
        {"band": 7, "gain": 0.1},
        {"band": 8, "gain": 0.15},
        {"band": 9, "gain": 0.1},
        {"band": 13, "gain": 0.1},
        {"band": 14, "gain": 0.15},
    ]
}

@bot.command()
async def eq_preset(ctx, preset: str = None):
    """Apply or list equalizer presets."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    if preset is None:
        available = ", ".join(EQ_PRESETS.keys())
        return await ctx.send(f"Available EQ presets: {available}")
    
    preset_name = preset.lower()
    if preset_name not in EQ_PRESETS:
        available = ", ".join(EQ_PRESETS.keys())
        return await ctx.send(f"Unknown preset! Available: {available}")
    
    filters = player.filters
    filters.equalizer.set(bands=EQ_PRESETS[preset_name])
    
    await player.set_filters(filters)
    await ctx.send(f"🎵 Applied '{preset}' EQ preset")

@bot.command()
async def custom_eq(ctx, *band_gains):
    """Set custom equalizer bands. Usage: !custom_eq 0.1 0.2 0.0 ..."""
    player = ctx.voice_client
    if not player:
        return await ctx.send("Not connected to a voice channel!")
    
    if len(band_gains) > 15:
        return await ctx.send("Maximum 15 bands (0-14)!")
    
    try:
        # Parse gain values
        gains = [float(gain) for gain in band_gains]
        
        # Validate gain range
        for gain in gains:
            if not -0.25 <= gain <= 1.0:
                return await ctx.send("Gain values must be between -0.25 and 1.0!")
        
        # Create band configuration
        bands = [{"band": i, "gain": gain} for i, gain in enumerate(gains)]
        
        filters = player.filters
        filters.equalizer.set(bands=bands)
        await player.set_filters(filters)
        
        await ctx.send(f"🎛️ Applied custom EQ with {len(bands)} bands")
        
    except ValueError:
        await ctx.send("Invalid gain values! Use numbers between -0.25 and 1.0")

Install with Tessl CLI

npx tessl i tessl/pypi-wavelink

docs

audio-filters.md

events-exceptions.md

index.md

node-management.md

player-control.md

queue-system.md

track-search.md

tile.json