---
title: Gate
description: "A gate as a device you can plug in: a threshold, a floor, an attack, a hold, a release and a look-ahead as a state, a panel that draws its transfer curve with a handle on the threshold, a Web Audio engine and the tools an agent drives it with."
component: true
base: base
---

<ComponentPreview styleName="base-nova" name="block-gate" />

Cleans up between sounds: above the threshold the signal passes, below it it is turned down to the floor. Drag the handle across to set the threshold. It is a device like the [compressor](/docs/components/compressor): a state, a panel that draws it, an engine that plays it and tools an agent calls, each its own file.

## Installation

<CodeTabs>

<TabsList>
  <TabsTrigger value="cli">CLI</TabsTrigger>
  <TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>

<TabsContent value="cli">

```bash component
npx shadcn@latest add @audio-ui/block-gate
```

</TabsContent>

<TabsContent value="manual">

<Steps>

<Step>Install the packages:</Step>

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

<Step>Add the pieces you want. All of them, or only the state and the panel if your engine is elsewhere:</Step>

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

<Step>Copy and paste the demo that wires them, if you want it.</Step>

<ComponentSource
  styleName="base-nova"
  name="block-gate"
  title="components/examples/block-gate.tsx"
/>

</Steps>

</TabsContent>

</CodeTabs>

## Usage

```tsx
import { GatePanel } from "@/components/audio-ui/devices/gate/panel";
import { gateDevice } from "@/components/audio-ui/devices/gate/device";

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

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

The state is a plain object keyed by parameter id, so a host stores it, saves it with its project and sends it where it likes. `gateCurve(state)` is the curve the panel draws and `gateSettings(state)` the numbers the engine puts on its nodes.

## The engine

```ts
import { createGateEngine } from "@/components/audio-ui/devices/gate/engine";

const engine = createGateEngine(ctx, state);
source.connect(engine.input);
engine.output.connect(ctx.destination);
engine.update(nextState); // parameters ramp: no click
engine.dispose();
```

The browser has no gate node, so the engine measures the level with an `AudioWorklet` loaded from a blob, which writes the gain to apply. The level is a peak follower, the gate is open while it is over the threshold and for the **Hold** after, and the gain moves toward 1 or the floor with the **Attack** or the **Release** as a time constant. A delay in front of the gain is the **Look-ahead**: the detector reads the signal before it, so the gate is open when a transient arrives, and the device reports the delay as its latency. `engine.ready` resolves once the detector is in the graph; until then the gate stays open, and a context with no worklets never resolves it to `true`.

## The key

The gate takes a second signal, a key, besides the one it processes. Switch **Key** on and its level is the one of the signal connected to `engine.sidechain`: a kick can open a held chord, so the chord pumps on the beat. The key is only listened to, never heard, and it is not a parameter: the state holds the switch, the host routes the signal.

```ts
const engine = createGateEngine(ctx, { ...state, external: true });
chord.connect(engine.input);
kick.connect(engine.sidechain); // listened to, not heard
engine.output.connect(ctx.destination);
```

The device says it takes one: `gateDevice.sidechain` is `true`, and so is `describe().sidechain`, so a host knows to route something to it and an agent can be told. With the key on, what the gate does to the signal depends on the other signal, so the panel does not draw the transfer curve; the threshold is a level of the key. The block starts keyed: a held chord opened by the kick of the loop. Raise the look-ahead when the key arrives with the signal, so the start of its attack is not cut.

## The tools

```ts
import { deviceTools } from "@audio-ui/core/device";
import { gateDevice } from "@/components/audio-ui/devices/gate/device";

const [set, reset] = deviceTools(gateDevice);
```

`set` and `reset` change the state, with the ranges the device enforces: a value out of range is brought in and reported, a wrong one is refused by name, and a call never throws.

## Accessibility

Every control is a native input: the knobs are sliders named after their parameter, with the value and unit as the text value, the switches are toggle buttons, and everything takes the keyboard.
