# sound-operations

> The operations that change a sound's samples, as data: Reverse, Repeat, Add silence, Normalize, Pan, Dither, Filter, Stretch, Pitch, Speed and Repair, with Delete, Crop, Paste and Gain; applySoundOperation runs one on plain channels, on all of them or a stretch, soundOperationName names it as a step of the history.

```bash
npx shadcn@latest add @audio-ui/sound-operations
```

```ts
import { REPAIR_NAMES, soundOperationName, SEAM, applySoundOperation, soundOperationTiming } from "@/lib/sound-operations";
```

- Files: `lib/sound-operations.ts`
- Depends on: nothing; npm: `@audio-ui/core`, `@audio-ui/engine`
- Used by: `block-audio-editor`, `clip-panel`, `process-menu`, `use-bake`

| Export | Kind | What it is |
| --- | --- | --- |
| `SoundSamples` | interface | A sound as plain samples: what an operation reads and writes. |
| `SoundRange` | type | A stretch of a sound, from where it starts to where it ends, in seconds. |
| `SoundOperation` | type | One change to a sound's samples. |
| `REPAIR_NAMES` | const | What each repair is called. |
| `soundOperationName` | function | What an operation is called, as a step of the history: "Repeat ×2", "Pitch -5 st". |
| `SEAM` | const | How long the seam between what an operation made and what it left is crossfaded, in seconds: no click at either end. |
| `applySoundOperation` | function | The sound an operation makes, at the same rate: of the whole sound, or of `range` alone, spliced back in with its seams crossfaded. |
| `soundOperationTiming` | function | How an operation moves the times in the stretch it changes: `"scaled"` by how much longer it makes it (Stretch, Speed), `"cropped"` to it alone (Crop), or `"spliced"`, where what it made starts where the stretch did and what follows moves by as much as it grew or shrank (Delete, Paste, Repeat, Add silence, and the rest, which keep its length). |

## Usage

An operation is data, `{ type: "stretch", factor: 1.5, method: "transient" }`, so a menu, a key or an agent's tool can pick one and the code that holds the sound runs it. The [Process menu](/docs/components/base/process-menu) lists the processes; Delete, Crop, Paste and Gain are an audio editor's edits.

```ts
import {
  applySoundOperation,
  soundOperationName,
  soundOperationTiming,
} from "@/lib/sound-operations";

const operation = { semitones: -2, method: "formant", type: "shift" } as const;
const sound = { channels, sampleRate: 48_000 };

// Plain channels in, plain channels out, at the same rate.
const next = applySoundOperation(sound, operation);

// On a stretch alone, 1 s to 2.5 s, spliced back with each seam crossfaded.
const edited = applySoundOperation(sound, { db: 3, type: "gain" }, [1, 2.5]);

// The edits: take a stretch out, keep it alone, or put copied samples in its place.
applySoundOperation(sound, { type: "delete" }, [1, 2.5]);
applySoundOperation(sound, { type: "crop" }, [1, 2.5]);
applySoundOperation(sound, { channels: copied, type: "paste" }, [4, 4]); // at a point: inserted there

soundOperationName(operation); // "Pitch -2 st"
soundOperationTiming(operation); // "spliced": what follows the stretch moves by as much as it grew
```

Each process is one of [`@audio-ui/engine/files`](/docs/engine/files) (`reverseChannels`, `repeatChannels`, `padChannels`, `normalizeChannels`, `panChannels`, `ditherChannels`, `filterChannels`, `stretchChannels`, `shiftChannels`, `speedChannels`, `gainChannels`) or `repairChannels` of [`@audio-ui/engine/repair`](/docs/engine/repair), whose methods the menu offers as a choice. Given a `range`, in seconds, the operation runs on that stretch alone, and each seam with the rest is crossfaded over `SEAM` (5 ms), so a cut, an insert or a stretch processed on its own makes no click. `soundOperationTiming` says how one moves the times in the stretch: `"scaled"` for Stretch and Speed, `"cropped"` for Crop, `"spliced"` for the rest; the clip panel's `processedSettings` reads it to keep a clip on what it played.
