# Bass Enhancer

> A bass enhancer device: a frequency, a drive, an amount and the sub it keeps, a panel that draws its two bands, a Web Audio engine and tools for agents.

```tsx
"use client";

import { useState } from "react";
import {
  type BassEnhancerState,
  bassEnhancerDevice,
} from "@/components/audio-ui/devices/bass-enhancer/device";
import { createBassEnhancerEngine } from "@/components/audio-ui/devices/bass-enhancer/engine";
import { BassEnhancerPanel } from "@/components/audio-ui/devices/bass-enhancer/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";

const MASTER_VOLUME = 0.7;

/**
 * A bass enhancer you can plug in: its state, a panel that draws the sub it
 * takes and where its harmonics go, and an engine that plays it, each its own
 * file and none knowing the others. Play the loop on small speakers and raise
 * the amount: the bass comes through.
 */
export function BlockBassEnhancer() {
  const [state, setState] = useState<BassEnhancerState>(() =>
    bassEnhancerDevice.defaults()
  );
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createBassEnhancerEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <BassEnhancerPanel onValueChange={setState} value={state} />
    </div>
  );
}
```

Lets a bass be heard on small speakers. A phone or a laptop cannot play the lowest notes, but the ear hears a note from its harmonics alone. The device takes the lows under a frequency, shapes them into their harmonics, which those speakers can play, and adds them to the sound. 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/bass-enhancer
```

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

**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/bass-enhancer-device @audio-ui/bass-enhancer-panel @audio-ui/bass-enhancer-engine
```

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

```tsx title="components/examples/block-bass-enhancer.tsx"
"use client";

import { useState } from "react";
import {
  type BassEnhancerState,
  bassEnhancerDevice,
} from "@/components/audio-ui/devices/bass-enhancer/device";
import { createBassEnhancerEngine } from "@/components/audio-ui/devices/bass-enhancer/engine";
import { BassEnhancerPanel } from "@/components/audio-ui/devices/bass-enhancer/panel";
import { useDeviceLoop } from "@/hooks/use-device-loop";
import { useMasterBus } from "@/hooks/use-master-bus";

const MASTER_VOLUME = 0.7;

/**
 * A bass enhancer you can plug in: its state, a panel that draws the sub it
 * takes and where its harmonics go, and an engine that plays it, each its own
 * file and none knowing the others. Play the loop on small speakers and raise
 * the amount: the bass comes through.
 */
export function BlockBassEnhancer() {
  const [state, setState] = useState<BassEnhancerState>(() =>
    bassEnhancerDevice.defaults()
  );
  const master = useMasterBus(MASTER_VOLUME);
  useDeviceLoop({
    create: createBassEnhancerEngine,
    destination: master,
    state,
  });
  return (
    <div className="rounded-xl h-full w-full min-w-0">
      <BassEnhancerPanel 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 bass enhancer 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. |
| Frequency | 30 Hz to 200 Hz | 80 Hz | The top of the lows it takes: the bass under it is what it makes harmonics from. |
| Drive | 0 % to 100 % | 50 % | How hard the lows are shaped: more makes more harmonics. |
| Amount | 0 % to 100 % | 50 % | How much of the harmonics is added. At 0 the sound is as it was. |
| Sub | 0 % to 100 % | 100 % | How much of the sub itself stays. Lower thins the lows under the frequency, for speakers that would only waste power on them, but never takes them out whole: at 0, with the frequency at 80 Hz, a note at 30 Hz is 6 dB down and one at the frequency 2 dB up, since the low-pass the kernel takes away is shifted in phase. |

## Panel

The panel draws the sub it takes, dashed, and the band its harmonics go to, two and a half times higher. `bassEnhancerBands(state)` is what it draws.

```tsx
import { BassEnhancerPanel } from "@/components/audio-ui/devices/bass-enhancer/panel";
import { bassEnhancerDevice } from "@/components/audio-ui/devices/bass-enhancer/device";

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

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

## Engine

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

The bass enhancer runs on the audio thread: the bass enhancer of `@audio/effect-subbass` in an `AudioWorklet` loaded from a blob (`BASS_ENHANCER_WORKLET` is its source), 128 frames at a time: a low-pass takes the sub, a waveshaper makes its even and odd harmonics, and a band-pass keeps them between two and five times the frequency, where small speakers play. A worklet cannot import, so the device carries the kernel as published (`BASS_ENHANCER_KERNELS`, in its `kernels.ts`). Until it is ready, and in a context with no worklets, the sound passes clean: `ready` resolves once it is in the graph.
