No description
  • TypeScript 100%
Find a file
2026-05-08 03:16:22 +02:00
src Initial commit: headless equalizer plugin for NoMercy Video Player 2026-05-08 03:11:34 +02:00
.gitignore Initial commit: headless equalizer plugin for NoMercy Video Player 2026-05-08 03:11:34 +02:00
package-lock.json Initial commit: headless equalizer plugin for NoMercy Video Player 2026-05-08 03:11:34 +02:00
package.json Initial commit: headless equalizer plugin for NoMercy Video Player 2026-05-08 03:11:34 +02:00
README.md Add README with installation, API reference, and audio-chain docs 2026-05-08 03:16:22 +02:00
tsconfig.json Initial commit: headless equalizer plugin for NoMercy Video Player 2026-05-08 03:11:34 +02:00

nmplayer-equalizer-plugin

A headless 10-band parametric equalizer plugin for the NoMercy Video Player.

The plugin splices a preGain → peaking-filter chain → stereoPanner pipeline between the player's existing gainNode and the AudioContext destination, then exposes a small API for adjusting bands, pan, and presets. It emits typed events on the player's event bus so consumers can wire any UI of their choice — there is no built-in UI.

Features

  • 10 peaking-filter bands at 70 / 180 / 320 / 600 / 1 000 / 3 000 / 6 000 / 12 000 / 14 000 / 16 000 Hz, plus a pre-gain pseudo-band.
  • Stereo panner with sticky-zero snapping (±0.05 → 0).
  • 19 built-in presets (Classical, Club, Dance, Flat, Pop, Rock, Soft, Live, Techno, …) and support for ad-hoc presets via JSON.
  • Persists state through player.storage (the player's namespaced localStorage wrapper).
  • Idempotent lifecycle: safe to dispose() and re-use(); teardown restores the player's original gainNode → destination wiring.
  • Strict TypeScript with declaration merging (player.plugin('equalizer') is fully typed).

Installation

npm install nmplayer-equalizer-plugin
# peer-dep
npm install @nomercy-entertainment/nomercy-video-player

Quick start

import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { EqualizerPlugin } from 'nmplayer-equalizer-plugin';

const player = nmplayer('myPlayer');

player.setup({
    playlist: [/* … */],
    // Optional: provide config inline via the merged PlayerConfig key.
    equalizer: {
        storageKey: 'my-app-equalizer',
        autoLoad: true,
    },
});

player.registerPlugin('equalizer', new EqualizerPlugin());
player.usePlugin('equalizer');

const eq = player.plugin('equalizer');
eq?.setPreset('Rock');
eq?.setFilter({ frequency: 1000, gain: 3 });
eq?.setPanner(-0.3);

player.on('equalizer:change', ({ bands, pan, selectedPreset }) => {
    // drive your UI here
});

Configuration

Options can be passed either to the plugin constructor or via the player's config object (equalizer key). Constructor options take precedence.

new EqualizerPlugin({
    storageKey: 'equalizer-settings', // default
    autoLoad: true,                   // default — load persisted settings on use()
    autoSave: true,                   // default — persist on every change
    bands: undefined,                 // override default band layout
    presets: undefined,               // override built-in presets
    sliderValues: undefined,          // override slider ranges
});
Option Type Default Description
storageKey string 'equalizer-settings' Key under the player's nmplayer- storage prefix.
autoLoad boolean true Read persisted state and apply it after the audio chain is connected.
autoSave boolean true Save state on every setPreGain, setFilter, setPanner, setPreset, reset.
bands EQBand[] (built-in 10-band set) Initial band layout. Index 0 must be { frequency: 'Pre', gain }.
presets EqualizerPreset[] (19 built-in presets) Replaces the built-in preset list.
sliderValues EQSliderValues (sensible defaults) Min/max/step ranges for pan, pre-gain, and band sliders.

API

Lifecycle (inherited from the player's Plugin base)

Method When Notes
initialize(player) On registerPlugin Store the player reference. No DOM or audio work.
use() On usePlugin Subscribes to 'ready' / 'play'; if the player has already fired 'ready', sets up the chain immediately.
dispose() On player teardown Removes listeners, disconnects all audio nodes, restores original gainNode → destination.

Setters

eq.setPreGain(gain: number | string): void
eq.setPanner(pan: number | string): void
eq.setFilter(band: { frequency: number | 'Pre'; gain: number }): void
eq.setPreset(preset: EqualizerPreset | string): void
eq.reset(): void
  • setPreGain and setPanner snap to 0 when the absolute value is ≤ 0.05.
  • setPreGain(0) is unity gain — the AudioParam is value + 1 internally, mirroring the original reference implementation.
  • setPreset accepts a preset name, an EqualizerPreset object, or a JSON string of one. Unknown names return silently.
  • Manual changes (setPreGain, setFilter, setPanner) clear the selected preset name.

Getters

eq.getBands(): EQBand[]                           // includes 'Pre' at index 0
eq.getPan(): number                               // [-1, 1]
eq.getPreGain(): number                           // raw slider value (no +1 offset)
eq.getSelectedPresetName(): string | undefined
eq.getPresets(): EqualizerPreset[]
eq.getSliderValues(): EQSliderValues

Slider helpers

For UI components that render bands as sliders:

eq.getBandSliderMin(frequency)                    // min for that band's slider
eq.getBandSliderMax(frequency)                    // max for that band's slider
eq.getBandSliderStep(frequency)                   // step granularity
eq.getBandSliderValue(frequency)                  // current gain normalized to 0100

Events

The plugin emits two custom events on the player's event bus.

Event Payload When
equalizer:ready undefined After the audio chain has been connected and (optional) persisted state applied.
equalizer:change { bands: EQBand[]; pan: number; selectedPreset?: string } After every state-changing call (setPreGain, setFilter, setPanner, setPreset, reset, and the initial load).
player.on('equalizer:ready', () => console.log('eq online'));
player.on('equalizer:change', data => updateUI(data));

Audio chain

                    ┌──────────────── plugin owns ────────────────┐
HTMLVideoElement ─► MediaElementSource ─► gainNode ─► preGain ─► f1 ─► f2 ─► … ─► fN ─► stereoPanner ─► destination
                                          ^^^^^^^^                                                       ^^^^^^^^^^^
                                          player.gainNode                                                AudioContext.destination

gainNode is the player's existing volume-boost node (created by addGainNode()). The plugin disconnects it from destination, splices in preGain → filters → panner, and re-terminates at destination. The plugin never calls createMediaElementSource() itself, because it can only be called once per <video> element.

If addGainNode() has not yet been called by the time the plugin starts, the plugin will call it. If you have your own audio graph that runs in parallel with the player's, set it up before activating this plugin.

Persistence

State is stored as JSON under the configured storageKey via player.storage, which transparently prefixes keys with nmplayer- and defaults to localStorage. The persisted shape:

interface EqualizerSettings {
    bands: EQBand[];
    pan: number;
    selectedPreset?: string;
}

Applications that don't want any persistence can pass autoLoad: false and autoSave: false.

Built-in presets

Custom, Classical, Club, Dance, Flat, Laptop speakers/headphones, Large hall, Party, Pop, Reggae, Rock, Soft, Ska, Full Bass, Soft Rock, Full Treble, Full Bass & Treble, Live, Techno.

import { equalizerPresets } from 'nmplayer-equalizer-plugin';

const allNames = equalizerPresets.map(p => p.name);

TypeScript

The plugin uses declaration merging to register itself with the player's type system, so both the registry lookup and the config key are fully typed:

const eq = player.plugin('equalizer');     // EqualizerPlugin | undefined
player.setup({ equalizer: { storageKey: 'x' } });  // typed

All public types (EQBand, EQSliderValues, EqualizerPreset, EqualizerSettings, EqualizerPluginOptions, EqualizerChangeData, EqualizerEventMap, SliderRange) are re-exported from the package root.

Development

npm install        # install peer + dev deps
npm run build      # tsc → dist/
npx vitest         # run the test suite (18 specs)
npm run watch      # incremental type-check + emit

Compatibility

  • Peer dependency: @nomercy-entertainment/nomercy-video-player ^1.2.0
  • Browsers: Any browser with Web Audio (AudioContext, BiquadFilterNode, StereoPannerNode). All modern evergreen browsers qualify.
  • Module format: ESM (Node ≥ 18). The package emits dist/index.js and dist/index.d.ts.

License

MIT.