# Graphic EQ

> A graphic EQ device: ten bands an octave apart on faders and an output level, a panel that draws the curve, a Web Audio engine and tools for agents.

```tsx
"use client";

import { useState } from "react";
import {
  type GraphicEqState,
  graphicEqDevice,
} from "@/components/audio-ui/devices/graphic-eq/device";
import { createGraphicEqEngine } from "@/components/audio-ui/devices/graphic-eq/engine";
import { GraphicEqPanel } from "@/components/audio-ui/devices/graphic-eq/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";

const MASTER_VOLUME = 0.7;

/**
 * A graphic EQ you can plug in: its state, a panel that draws the curve over a
 * fader per band and an engine that plays it, each its own file and none
 * knowing the others. Play the loop and pull the faders.
 */
export function BlockGraphicEq() {
  const [state, setState] = useState<GraphicEqState>(() =>
    graphicEqDevice.defaults()
  );
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createGraphicEqEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <GraphicEqPanel onValueChange={setState} value={state} />
    </div>
  );
}
```

Shapes the tone with ten bands an octave apart, from 31 Hz to 16 kHz, each on a fader of its own, as a graphic equalizer has them. For bands you place and widen yourself, use the [equalizer](/docs/components/base/equalizer). It is a [device](/docs/devices): a state, a panel, an engine and tools, each its own file.

## Installation

**CLI**

```bash
npx shadcn@latest add @audio-ui/graphic-eq
```

It installs the device's state, its engine and its panel to `components/audio-ui/devices/graphic-eq/`. The demo above, which wires them to a loop, is `@audio-ui/block-graphic-eq`.

**Manual**

**1. Install the packages:**

```bash
npm install @audio-ui/react @audio-ui/core
```

**2. Add the pieces you want. All of them, or only the state and the panel if your engine is elsewhere:**

```bash
npx shadcn@latest add @audio-ui/graphic-eq-device @audio-ui/graphic-eq-panel @audio-ui/graphic-eq-engine
```

**3. Copy and paste the demo that wires them, if you want it.**

```tsx title="components/examples/block-graphic-eq.tsx"
"use client";

import { useState } from "react";
import {
  type GraphicEqState,
  graphicEqDevice,
} from "@/components/audio-ui/devices/graphic-eq/device";
import { createGraphicEqEngine } from "@/components/audio-ui/devices/graphic-eq/engine";
import { GraphicEqPanel } from "@/components/audio-ui/devices/graphic-eq/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";

const MASTER_VOLUME = 0.7;

/**
 * A graphic EQ you can plug in: its state, a panel that draws the curve over a
 * fader per band and an engine that plays it, each its own file and none
 * knowing the others. Play the loop and pull the faders.
 */
export function BlockGraphicEq() {
  const [state, setState] = useState<GraphicEqState>(() =>
    graphicEqDevice.defaults()
  );
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createGraphicEqEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <GraphicEqPanel onValueChange={setState} value={state} />
    </div>
  );
}
```

**Agent**

Give your agent the skill, and it picks the component, installs it and wires it to your audio:

```bash
npx skills add ouestlabs/audio-ui
```

Then ask it:

```text
Add the graphic eq from audio/ui to my project and wire it to my audio code.
```

To let the agent read the docs live, connect the [MCP server](/docs/mcp). More in [Agent Skill](/docs/agents).

## Controls

| Control | Range | Default | What it does |
| --- | --- | --- | --- |
| On | On or off | On | Turns the device on. Off, the signal passes through unchanged. |
| 31 Hz | -15 dB to 15 dB | 0 dB | The lowest octave: the weight under a kick and a bass. |
| 63 Hz | -15 dB to 15 dB | 0 dB | The body of a kick and a bass. |
| 125 Hz | -15 dB to 15 dB | 0 dB | The warmth of most instruments, or their mud. |
| 250 Hz | -15 dB to 15 dB | 0 dB | The fullness of voices and guitars. |
| 500 Hz | -15 dB to 15 dB | 0 dB | The body of the middle, or its boxiness. |
| 1 kHz | -15 dB to 15 dB | 0 dB | Where most sounds speak: a voice's nose, a snare's crack. |
| 2 kHz | -15 dB to 15 dB | 0 dB | Presence: how near a voice or a guitar sounds. |
| 4 kHz | -15 dB to 15 dB | 0 dB | Edge and attack, or harshness. |
| 8 kHz | -15 dB to 15 dB | 0 dB | Brilliance and the sibilance of voices. |
| 16 kHz | -15 dB to 15 dB | 0 dB | Air, at the top of hearing. |
| Output | -12 dB to 12 dB | 0 dB | The level of the output, to make up for what the bands add or take. |

Each band boosts or cuts 15 dB. A band at 0 dB leaves its octave as it is.

## Panel

The panel draws the curve the bands play together over a fader for each, as on a graphic equalizer, with the output knob beside them. `graphicEqCurve(state)` is the curve it draws, and `graphicEqBands(state)` the filters a state is.

```tsx
import { GraphicEqPanel } from "@/components/audio-ui/devices/graphic-eq/panel";
import { graphicEqDevice } from "@/components/audio-ui/devices/graphic-eq/device";

const [state, setState] = useState(() => graphicEqDevice.defaults());

<GraphicEqPanel onValueChange={setState} value={state} />;
```

## Engine

Create it, connect it and update it as for any device: see [The engine](/docs/devices#the-engine).

The bands are those of `@audio/eq-graphic`: a bell at each octave centre of ISO 266, all as wide (a Q of 1.4), so they meet without a gap or a hump. Its bells are the Audio EQ Cookbook's, which a `BiquadFilterNode` of type `peaking` computes, so the engine is ten of those in series, then an output level. Off, every band goes flat and the level to 0 dB.
