Skip to content
eqapo-format-expert logo

EqualizerAPO Format Expert

eqapo-format-expert

Expert in EqualizerAPO configuration file format, parsing, and generation. Use when implementing EAPO config import/export, adding support for new filter types, or debugging config file issues.

SKILL.md

Full skill instructions

EqualizerAPO Format Expert

Specialized agent for working with EqualizerAPO configuration files, ensuring correct parsing and generation of .txt config files.

EqualizerAPO Overview

EqualizerAPO is a parametric equalizer for Windows that processes system audio via APO (Audio Processing Objects) framework.

  • Config Location: C:\Program Files\EqualizerAPO\config\config.txt
  • Format: Plain text with line-based commands
  • Real-time: Changes apply immediately when file is saved
  • Channels: Supports per-channel processing (L, R, C, SUB, etc.)

Config File Format

Basic Structure

# Comment lines start with #

Preamp: -5.0 dB
Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41
Filter: ON LS Fc 80 Hz Gain -2.5 dB Q 0.71
Filter: ON HS Fc 10000 Hz Gain 4.0 dB Q 0.71

Filter Types Supported by EQAPO GUI

TypeEAPO CodeDescriptionParameters
PeakingPKBell curve EQFc, Gain, Q
Low ShelfLSBass adjustmentFc, Gain, Q
High ShelfHSTreble adjustmentFc, Gain, Q

Additional Filter Types (Not Yet Implemented)

TypeEAPO CodeDescription
Low PassLPCuts high frequencies
High PassHPCuts low frequencies
Band PassBPPasses only a frequency range
NotchNOCuts a specific frequency
All PassAPAffects phase, not magnitude

Preamp Syntax

Preamp: <value> dB

Examples:

Preamp: -5.0 dB
Preamp: 3 dB
Preamp: 0 dB

Rules:

  • Must be on its own line
  • Value can be integer or float
  • Unit "dB" required
  • Negative values reduce volume (prevent clipping)
  • Typical range: -20 to +20 dB

Filter Syntax

Filter: <ON|OFF> <TYPE> Fc <frequency> Hz Gain <gain> dB Q <q_factor>

Examples:

Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41
Filter: ON LS Fc 80 Hz Gain -2.5 dB Q 0.71
Filter: OFF HS Fc 10000 Hz Gain 4.0 dB Q 0.71

Rules:

  • ON or OFF state (case-insensitive)
  • Filter type: PK, LS, HS, etc.
  • Frequency: Fc <value> Hz (20-20000 typical)
  • Gain: Gain <value> dB (can be negative)
  • Q factor: Q <value> (0.1-30 typical)

Channel-Specific Filters

Channel: L
Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41

Channel: R
Filter: ON PK Fc 1000 Hz Gain 2.0 dB Q 1.41

Channel: ALL

Not yet supported in EQAPO GUI - applies filters to all channels globally.

Parsing EqualizerAPO Files

Parser Implementation (TypeScript)

export interface ParsedEapoConfig {
  preamp: number;
  bands: ParametricBand[];
}

export function parseEapoConfig(content: string): ParsedEapoConfig {
  const lines = content.split('\n').map((line) => line.trim());

  let preamp = 0;
  const bands: ParametricBand[] = [];

  for (const line of lines) {
    // Skip comments and empty lines
    if (line.startsWith('#') || line === '') continue;

    // Parse preamp
    if (line.startsWith('Preamp:')) {
      const match = line.match(/​Preamp:\s*([-+]?\d+\.?\d*)\s*dB/​i);
      if (match) {
        preamp = parseFloat(match[1]);
      }
      continue;
    }

    // Parse filter
    if (line.startsWith('Filter:')) {
      const band = parseFilterLine(line);
      if (band) {
        bands.push(band);
      }
    }
  }

  return { preamp, bands };
}

function parseFilterLine(line: string): ParametricBand | null {
  // Extract state (ON/​OFF)
  const stateMatch = line.match(/​Filter:\s*(ON|OFF)/​i);
  if (!stateMatch || stateMatch[1].toUpperCase() === 'OFF') {
    return null; // Skip disabled filters
  }

  // Extract filter type
  const typeMatch = line.match(/(PK|LS|HS|LP|HP|BP|NO|AP)/​i);
  if (!typeMatch) return null;

  const filterType = normalizeFilterType(typeMatch[1].toUpperCase());

  // Extract frequency
  const freqMatch = line.match(/​Fc\s+([\d.]+)\s*Hz/​i);
  if (!freqMatch) return null;
  const frequency = parseFloat(freqMatch[1]);

  // Extract gain
  const gainMatch = line.match(/​Gain\s+([-+]?[\d.]+)\s*dB/​i);
  if (!gainMatch) return null;
  const gain = parseFloat(gainMatch[1]);

  // Extract Q factor
  const qMatch = line.match(/​Q\s+([\d.]+)/​i);
  if (!qMatch) return null;
  const qFactor = parseFloat(qMatch[1]);

  // Validate
  if (!isValidBand(frequency, gain, qFactor)) {
    return null;
  }

  return { filterType, frequency, gain, qFactor };
}

function normalizeFilterType(type: string): FilterType {
  switch (type) {
    case 'PK':
    case 'PEAKING':
      return 'Peaking';
    case 'LS':
    case 'LOWSHELF':
      return 'LowShelf';
    case 'HS':
    case 'HIGHSHELF':
      return 'HighShelf';
    default:
      throw new Error(`Unsupported filter type: ${type}`);
  }
}

function isValidBand(frequency: number, gain: number, qFactor: number): boolean {
  return (
    frequency >= 20 &&
    frequency <= 20000 &&
    gain >= -30 &&
    gain <= 30 &&
    qFactor >= 0.01 &&
    qFactor <= 100
  );
}

Edge Cases in Parsing

  1. Case Insensitivity

    filter: on pk fc 1000 hz gain 3.0 db q 1.41  ✓
    FILTER: ON PK FC 1000 HZ GAIN 3.0 DB Q 1.41  ✓
    Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41  ✓
    
  2. Extra Whitespace

    Filter:  ON   PK  Fc  1000  Hz  Gain  3.0  dB  Q  1.41  ✓
    
  3. Integer vs Float

    Filter: ON PK Fc 1000 Hz Gain 3 dB Q 1.41     ✓
    Filter: ON PK Fc 1000.0 Hz Gain 3.0 dB Q 1.41 ✓
    
  4. Negative Gains

    Filter: ON PK Fc 1000 Hz Gain -3.0 dB Q 1.41  ✓
    Filter: ON LS Fc 80 Hz Gain -6 dB Q 0.71      ✓
    
  5. Comments Mid-Line (Not standard, but seen in wild)

    Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41 # Boost presence
    

Generating EqualizerAPO Files

Writer Implementation (Rust)

pub fn write_eapo_config(
    path: &Path,
    bands: &[ParametricBand],
    preamp: f32,
) -> Result<(), std::io::Error> {
    let mut content = String::new();

    // Header comment
    content.push_str("# Generated by EQAPO GUI\n");
    content.push_str(&format!("# Generated: {}\n\n", chrono::Local::now().format("%Y-%m-%d %H:%M:%S")));

    // Preamp
    content.push_str(&format!("Preamp: {:.1} dB\n", preamp));

    // Filters
    for band in bands {
        let filter_line = format!(
            "Filter: ON {} Fc {} Hz Gain {:.1} dB Q {:.2}\n",
            filter_type_to_code(&band.filter_type),
            band.frequency as u32,
            band.gain,
            band.q_factor
        );
        content.push_str(&filter_line);
    }

    // Write to file
    std::fs::write(path, content)?;

    Ok(())
}

fn filter_type_to_code(filter_type: &FilterType) -> &'static str {
    match filter_type {
        FilterType::Peaking => "PK",
        FilterType::LowShelf => "LS",
        FilterType::HighShelf => "HS",
    }
}

Output Format Example

# Generated by EQAPO GUI
# Generated: 2026-01-04 15:30:00

Preamp: -3.5 dB
Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41
Filter: ON LS Fc 80 Hz Gain -2.5 dB Q 0.71
Filter: ON HS Fc 10000 Hz Gain 4.0 dB Q 0.71

Formatting Rules:

  • Frequency: Integer (no decimal places)
  • Gain: 1 decimal place
  • Q factor: 2 decimal places
  • Consistent spacing
  • One filter per line

Advanced EqualizerAPO Features

Include Directive

Include: subwoofer_eq.txt
Include: headphone_compensation.txt

Loads another config file at that position.

Copy Filter

Copy: L=L+0.5*R R=R+0.5*L

Mixes channels (crossfeed for headphones).

Delay

Delay: L=0 R=2.5

Delays right channel by 2.5ms (speaker positioning).

Convolution (Impulse Response)

Convolution: room_correction.wav

Applies FIR filter from WAV file (room correction).

None of these are supported in EQAPO GUI yet - future features.

File Permissions

Windows UAC Challenges

EqualizerAPO's default config location requires admin rights:

C:\Program Files\EqualizerAPO\config\config.txt

Solutions:

  1. Live Config (Recommended)

    C:\Users\<Username>\Documents\EQAPO GUI\live_config.txt
    

    Then use EqualizerAPO's Include: directive in main config:

    Include: C:\Users\<Username>\Documents\EQAPO GUI\live_config.txt
    
  2. Run as Admin (Not recommended)

    • Tauri app requests elevation
    • Security risk
    • UAC prompt every time

Permission Check (Rust)

pub fn can_write_to_eapo_config(path: &Path) -> bool {
    // Try to open file for writing
    std::fs::OpenOptions::new()
        .write(true)
        .create(false)
        .open(path)
        .is_ok()
}

pub fn get_recommended_config_path() -> PathBuf {
    if can_write_to_eapo_config(&get_default_config_path()) {
        get_default_config_path()
    } else {
        get_live_config_path()
    }
}

Validation

Pre-Write Validation

function validateEapoConfig(bands: ParametricBand[], preamp: number): string[] {
  const errors: string[] = [];

  // Check preamp
  if (preamp < -20 || preamp > 20) {
    errors.push(`Preamp ${preamp} dB exceeds typical range (-20 to +20 dB)`);
  }

  // Check band count
  if (bands.length > 32) {
    errors.push(`Too many bands (${bands.length}). EqualizerAPO supports max 32.`);
  }

  // Check each band
  bands.forEach((band, i) => {
    if (band.frequency < 20 || band.frequency > 20000) {
      errors.push(`Band ${i + 1}: Frequency ${band.frequency} Hz out of range (20-20000 Hz)`);
    }

    if (band.gain < -30 || band.gain > 30) {
      errors.push(`Band ${i + 1}: Gain ${band.gain} dB exceeds typical range (-30 to +30 dB)`);
    }

    if (band.qFactor < 0.1 || band.qFactor > 30) {
      errors.push(`Band ${i + 1}: Q factor ${band.qFactor} out of range (0.1-30)`);
    }
  });

  return errors;
}

Testing

Parser Test Cases

describe('EAPO Parser', () => {
  it('should parse basic config', () => {
    const config = `
      Preamp: -5.0 dB
      Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41
    `;

    const result = parseEapoConfig(config);

    expect(result.preamp).toBe(-5.0);
    expect(result.bands).toHaveLength(1);
    expect(result.bands[0].frequency).toBe(1000);
  });

  it('should skip disabled filters', () => {
    const config = `
      Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41
      Filter: OFF PK Fc 2000 Hz Gain 6.0 dB Q 1.41
    `;

    const result = parseEapoConfig(config);
    expect(result.bands).toHaveLength(1);
  });

  it('should handle case insensitivity', () => {
    const config = `FILTER: on pk fc 1000 hz gain 3.0 db q 1.41`;
    const result = parseEapoConfig(config);

    expect(result.bands[0].filterType).toBe('Peaking');
  });
});

Common Issues

  1. ❌ Missing "dB" Unit

    Preamp: -5     # WRONG: Missing unit
    Preamp: -5 dB  # CORRECT
    
  2. ❌ Wrong Filter Code

    Filter: ON Peaking Fc 1000 Hz ...  # WRONG: Use "PK"
    Filter: ON PK Fc 1000 Hz ...       # CORRECT
    
  3. ❌ Missing Fc Keyword

    Filter: ON PK 1000 Hz ...      # WRONG
    Filter: ON PK Fc 1000 Hz ...   # CORRECT
    
  4. ❌ Comma as Decimal Separator

    Filter: ON PK Fc 1000 Hz Gain 3,0 dB Q 1,41  # WRONG (European notation)
    Filter: ON PK Fc 1000 Hz Gain 3.0 dB Q 1.41  # CORRECT
    

Reference Materials

  • references/​eapo_spec.md - Full EqualizerAPO specification
  • references/​filter_types.md - All supported filter types
  • references/​examples.md - Real-world config file examples

More Other skills

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View

Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.

179.7K 100.1K
View

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

179.7K 89.5K
View

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

179.7K 76.1K
View

Fundamental design principles for writing maintainable, testable Python code.

40.2K 21.9K
View

Modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first strategies.

40.2K 20K
View

Generate Playwright tests from scenarios using interactive browser exploration and validation.

39.7K 18.2K
View

Modern React state management with Redux Toolkit, Zustand, Jotai, and React Query for every state category.

40.2K 14.7K
View

GDPR-compliant data handling with consent management, data subject rights, and privacy controls.

40.2K 14.3K
View

Python error handling patterns including input validation, exception hierarchies, and partial failure handling. Use when implementing validation logic, designing exception strategies, handling batch processing failures, or building robust APIs.

40.2K 13.5K
View

Detailed multi-file refactor planning with safety checks and rollback guidance.

39.7K 13K
View