Skip to main content

Overview

Discord Player provides precise volume control through real-time PCM (Pulse Code Modulation) transformation. Volume changes are applied instantly without interrupting playback or requiring stream recreation.

Basic Usage

Set Volume

// Set volume to 50%
queue.node.setVolume(50);

Get Current Volume

const volume = queue.node.volume;
console.log(`Current volume: ${volume}%`); // Current volume: 50%

Volume Transformer

The volume system uses a VolumeTransformer that operates on PCM audio data:
import { VolumeTransformer } from '@discord-player/equalizer';

const volumeTransformer = new VolumeTransformer({
  volume: 100  // Default 100%
});

Volume Properties

Volume

Integer percentage (0-200+)
queue.node.volume // 100

Volume Approx

Float value with decimals
queue.filters.volume?.volumeApprox // 100.5

Volume Range

0 - 100%Normal listening range
queue.node.setVolume(75);  // 75% volume

Default Volume

Set default volume when creating a queue:
const queue = player.queues.create(guild, {
  volume: 80  // Default to 80%
});

console.log(queue.node.volume); // 80

Volume Methods

Set Volume

// Returns boolean indicating success
const success = queue.node.setVolume(60);

if (success) {
  console.log('Volume updated to 60%');
}

Access Volume Transformer

const volumeFilter = queue.filters.volume;

if (volumeFilter) {
  // Get exact volume with decimals
  console.log(volumeFilter.volumeApprox);
  
  // Get rounded volume
  console.log(volumeFilter.volume);
  
  // Set volume directly on transformer
  volumeFilter.setVolume(75);
  
  // Or use property setter
  volumeFilter.volume = 75;
}

Volume Validation

The volume transformer includes automatic validation:
// Negative values clamped to 0
queue.node.setVolume(-10);  // Sets to 0

// Infinite values clamped to 100
queue.node.setVolume(Infinity);  // Sets to 100

// NaN rejected with error
try {
  queue.node.setVolume(NaN);
} catch (error) {
  console.error('Invalid volume value');
}

Disable Volume Control

You can disable volume transformation at queue creation:
const queue = player.queues.create(guild, {
  disableVolume: true  // Disable volume control
});

// Volume control will not be available
queue.node.setVolume(50);  // Returns false

Advanced Usage

Volume with Stream Config

player.events.on('willPlayTrack', (queue, track, config, resolve) => {
  // Modify volume in stream config
  config.dispatcherConfig.volume = 85;
  
  resolve();
});

Dynamic Volume Based on Track

player.events.on('audioTrackAdd', (queue, track) => {
  // Set different volume for different sources
  if (track.source === 'spotify') {
    queue.node.setVolume(90);
  } else if (track.source === 'youtube') {
    queue.node.setVolume(75);
  }
});

Volume Fade Effects

// Fade out over 3 seconds
async function fadeOut(queue: GuildQueue, duration = 3000) {
  const startVolume = queue.node.volume;
  const steps = 30;
  const stepDuration = duration / steps;
  const stepSize = startVolume / steps;
  
  for (let i = 0; i < steps; i++) {
    const newVolume = startVolume - (stepSize * (i + 1));
    queue.node.setVolume(Math.max(0, newVolume));
    await new Promise(resolve => setTimeout(resolve, stepDuration));
  }
}

// Fade in over 3 seconds
async function fadeIn(queue: GuildQueue, targetVolume = 100, duration = 3000) {
  const steps = 30;
  const stepDuration = duration / steps;
  const stepSize = targetVolume / steps;
  
  for (let i = 0; i < steps; i++) {
    const newVolume = stepSize * (i + 1);
    queue.node.setVolume(Math.min(targetVolume, newVolume));
    await new Promise(resolve => setTimeout(resolve, stepDuration));
  }
}

// Usage
await fadeOut(queue);
queue.node.skip();
await fadeIn(queue, 80);

Volume Normalization

player.events.on('playerStart', (queue, track) => {
  // Normalize volume based on track metadata
  const replayGain = track.raw?.replayGain || 0;
  const normalizedVolume = Math.max(0, Math.min(200, 100 + replayGain));
  
  queue.node.setVolume(normalizedVolume);
});

Volume Events

queue.on('volume', (volume) => {
  console.log(`Volume changed to ${volume}%`);
});

Volume State Management

Save and Restore Volume

const volumeState = new Map<string, number>();

// Save volume for guild
volumeState.set(guild.id, queue.node.volume);

// Restore volume
const savedVolume = volumeState.get(guild.id);
if (savedVolume !== undefined) {
  queue.node.setVolume(savedVolume);
}

Volume Persistence

import { writeFile, readFile } from 'fs/promises';

interface VolumeSettings {
  [guildId: string]: number;
}

// Save volume settings
async function saveVolumeSettings(settings: VolumeSettings) {
  await writeFile(
    'volume-settings.json',
    JSON.stringify(settings, null, 2)
  );
}

// Load volume settings
async function loadVolumeSettings(): Promise<VolumeSettings> {
  try {
    const data = await readFile('volume-settings.json', 'utf-8');
    return JSON.parse(data);
  } catch {
    return {};
  }
}

// Usage
const settings = await loadVolumeSettings();
const queue = player.queues.get(guild);

if (queue && settings[guild.id]) {
  queue.node.setVolume(settings[guild.id]);
}

Volume with Equalizer

import { EqualizerConfigurationPreset } from 'discord-player';

// Apply EQ preset
await queue.filters.equalizer?.setEQ(
  EqualizerConfigurationPreset.FullBass
);

// Reduce volume to prevent clipping
queue.node.setVolume(70);

Volume Graph

Get volume state from filter graph:
const graph = queue.filters.graph.dump();
console.log('Current volume:', graph.volume); // 100

// Access volume transformer directly
const volumeTransformer = queue.filters.graph.volume;
console.log('Volume:', volumeTransformer?.volume);

Volume Cache

Volume state is cached in the filters system:
// Access cached volume
const cachedVolume = queue.filters._lastFiltersCache.volume;
console.log('Cached volume:', cachedVolume);

// Volume persists across track changes
queue.node.skip();
// New track plays at same volume

Command Examples

Volume Command

import { SlashCommandBuilder } from 'discord.js';

export const command = new SlashCommandBuilder()
  .setName('volume')
  .setDescription('Set playback volume')
  .addIntegerOption(option =>
    option
      .setName('level')
      .setDescription('Volume level (0-200)')
      .setMinValue(0)
      .setMaxValue(200)
      .setRequired(true)
  );

export async function execute(interaction: ChatInputCommandInteraction) {
  const queue = useQueue(interaction.guild!);
  
  if (!queue) {
    return interaction.reply('No music playing!');
  }
  
  const volume = interaction.options.getInteger('level', true);
  const success = queue.node.setVolume(volume);
  
  if (success) {
    return interaction.reply(`🔊 Volume set to ${volume}%`);
  } else {
    return interaction.reply('Failed to set volume');
  }
}

Volume Up/Down Commands

// Volume up
export async function volumeUp(interaction: ChatInputCommandInteraction) {
  const queue = useQueue(interaction.guild!);
  if (!queue) return;
  
  const currentVolume = queue.node.volume;
  const newVolume = Math.min(200, currentVolume + 10);
  
  queue.node.setVolume(newVolume);
  await interaction.reply(`🔊 Volume: ${newVolume}%`);
}

// Volume down
export async function volumeDown(interaction: ChatInputCommandInteraction) {
  const queue = useQueue(interaction.guild!);
  if (!queue) return;
  
  const currentVolume = queue.node.volume;
  const newVolume = Math.max(0, currentVolume - 10);
  
  queue.node.setVolume(newVolume);
  await interaction.reply(`🔉 Volume: ${newVolume}%`);
}

Best Practices

Audio Clipping
  • Volumes above 100% may cause distortion
  • Use equalizer and filters carefully with high volume
  • Monitor for clipping when combining volume boost with bass boost
Recommendations
  • Keep default volume between 80-100%
  • Use volume fade for smooth transitions
  • Save user volume preferences per guild
  • Normalize volume across different audio sources
  • Consider loudness normalization for playlist playback
Technical Details
  • Volume transformation happens on PCM audio data
  • No quality loss at any volume level
  • Real-time processing with no latency
  • Volume stored as multiplier internally (100% = 1.0)

Audio Filters

FFmpeg audio filters and effects

Equalizer

15-band equalizer configuration

Stream Config

Configure audio stream processing

Build docs developers (and LLMs) love