# piano

> The piano's controller from @audio-ui/core: which keys sound, played by pointer, glide or keyboard, one note per pointer, and where each key sits on a keyboard or a piano roll's rows.

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

```ts
import { createPianoController, KEYBOARD_VELOCITY, MIN_VELOCITY, BLACK_KEY_DEPTH, keyAt, /* … */ } from "@audio-ui/core/piano";
```

- Adapters: `@audio-ui/react/piano`, `@audio-ui/elements/piano`

| Export | Kind | What it is |
| --- | --- | --- |
| `createPianoController` | function | A keyboard's behavior with no view attached: which keys sound, by pointer, glide or keyboard, how hard, and where the keyboard's one tab stop is. |
| `KEYBOARD_VELOCITY` | const | What a key played from the keyboard sounds at. |
| `MIN_VELOCITY` | const | The softest a pointer press plays: the very top of a key, not silence. |
| `PianoController` | interface | What `createPianoController` returns: the snapshot to draw from, and the presses, keys and focus moves of the keyboard. |
| `PianoNoteOffEventDetails` | type | What `onNoteOff` receives when a key stops: the reason (`"press"`, `"glide"` or `"keyboard"`) and the event. |
| `PianoNoteOnEventDetails` | type | What `onNoteOn` receives when a key sounds: its `velocity`, from 0 to 1, the reason (`"press"`, `"glide"` or `"keyboard"`), the event, and `cancel()` to refuse it. |
| `PianoOptions` | interface | The options of `createPianoController`: the pitches, their layout and orientation, the notes lit from elsewhere, and the callbacks. |
| `PianoSnapshot` | interface | What a view draws the keyboard from: the pitches and where each key sits, the ones sounding, and the tab stop. |
| `BLACK_KEY_DEPTH` | const | How far across the keyboard a black key reaches; past it, a press lands on a white key. |
| `KeyLayout` | type | How the keys share the keyboard's length: `"keyboard"` like a piano, white keys side by side with the black ones between them, or `"even"`, one equal share each, the way a piano roll's rows are. |
| `KeyPlacement` | interface | Where a key sits along the keyboard, how much of it it takes, and whether it is black. |
| `keyAt` | function | The key under a point, given as shares of the keyboard: `along` its length from the low end, `across` its depth from the back, where black keys are. |
| `placeKeys` | function | Where each of `pitches` (lowest first) sits along the keyboard. |

## Usage

The controller follows the [contract](/docs/core/controllers) every controller shares, with notes in place of a value:

```ts
import { createPianoController } from "@audio-ui/core/piano";

const piano = createPianoController({
  layout: "keyboard",
  minPitch: 48,
  maxPitch: 72,
  orientation: "horizontal",
  onNoteOn: (pitch) => synth.noteOn(pitch),
  onNoteOff: (pitch) => synth.noteOff(pitch),
});
```

The piano reports a note on when a key is pressed and a note off when it is released, one per pointer, so two fingers can hold two keys. `keyOn(pitch, event)` and `keyOff(pitch, event)` do the same for the keyboard, and `navigate(pitch, event)` moves focus between keys with the arrows. `getSnapshot()` gives each key's `placements` and the `active` set, which an element draws.

A pointer press sounds harder toward the near end of a key, from `MIN_VELOCITY` at its very top; a key played from the keyboard sounds at `KEYBOARD_VELOCITY`.

## Layout

`placeKeys(pitches, layout)` says where each key sits along the keyboard, from 0 to 1: `"keyboard"` lays white keys side by side with the black ones between them, as on a piano, and `"even"` gives each key an equal share, as a piano roll's rows are. `keyAt(placements, along, across, layout)` is the key under a point: past `BLACK_KEY_DEPTH` across the keyboard, a press lands on a white key.

**In React**

The [Piano](/docs/components/base/piano) draws this controller in React.

**In Vue, Svelte and Web**

[`<audio-ui-piano>`](/docs/elements/piano) draws this controller in your framework.

