# The Library

> How an app adds sounds, MIDI and other files to the person's Library, and how a page reads it.

The Library is where a musician keeps their sounds, on their own computer. Mixel stores each item's file in its own folder and remembers which app made it. An app can add to the Library. With a separate permission the person allows, its page can also show the sounds already there, so they can pick one. It can't change or remove anything.

## Add from an action

Return what you made. Each `ox.sound`, `ox.midi` or `ox.file` is copied into the Library when the action finishes, or when the person presses Stop:

```python title="app.py"
import numpy as np

import ox1audio as ox


@ox.action("Make a click track")
def click(bpm: ox.Slider(60, 200, 1, label="Tempo (BPM)") = 120, bars: ox.Number(1, 64, 1) = 4):
    rate = 44100
    beat = int(rate * 60 / bpm)
    samples = np.zeros((beat * 4 * bars, 1), dtype=np.float32)
    tick = np.sin(np.linspace(0, 2 * np.pi * 40, rate // 50, dtype=np.float32)) * 0.5
    for start in range(0, len(samples), beat):
        samples[start : start + len(tick), 0] += tick[: len(samples) - start]
    out = ox.audio.write(samples, rate, "wav", name=f"Click {bpm} BPM")
    return ox.sound(out, title=f"Click {bpm} BPM", bpm=bpm)
```

| Kind | Use it for |
| --- | --- |
| `ox.sound(path, title, **metadata)` | Audio |
| `ox.midi(path, title, **metadata)` | MIDI files |
| `ox.file(path, title, **metadata)` | Anything else, like a text file of lyrics |

Metadata goes after the title. Mixel keeps `bpm`, `key`, `duration`, `rate` and `channels` as columns the person can sort and filter by. The length of a sound is measured for you.

The item shows which app made it, and the badge stays after the app is uninstalled. This needs the `library` permission; `mixel check --fix` adds it when your code returns sounds.

If an action needs to add something before it returns, use `ox.library.add(kind, path, title, **metadata)`, where kind is `"sound"`, `"midi"` or `"other"`.

## Read from a page

A page can list the Library, so the person can pick a sound they already have. This is its own permission, `library-read`, apart from adding: ask for it in `app.json` with a sentence that says why, and it stays off until the person allows it.

```json
"permissions": {
  "files": "Open the recording you choose and save the dry copy next to it.",
  "library": "Add the dry copy to your Library.",
  "library-read": "Show the recordings in your Library, so you can choose one to dry."
}
```

```ts
import { ox } from "@ox1audio/sdk/page"

const sounds = await ox.library.list({ kind: "sound" })
const path = await ox.library.file(sounds[0].id)
const stop = ox.library.onChange(() => refresh())
```

Each item has `id`, `kind`, `title`, `filename`, `duration`, `bpm`, `musicalKey`, `appName` and `created`. There are no paths in the list, and nothing about where the person keeps their files. `ox.library.add(paths)` needs only `library`. It adds sounds and MIDI the person chose for your app (picked, dropped, or inside a folder they chose), results your actions saved, and files in your app's own data. A file that merely sits in the same folder as a chosen one is refused. If the Library already has the same audio as someone else's sound, you get back only `{ imported: "already" }` for it, with no id or name.

`ox.library.file(id)` gives you a path your actions can open. It needs `library-read` and `files`, and Mixel hands over one sound at a time:

- A sound your app added is yours to open, with no question asked.
- For any other sound, Mixel asks the person first, naming every sound, so call it only for what they chose in your page. One question covers at most 20 sounds; calls past that fail. If they say no, the call throws.
- Mixel asks for `library-read` the first time your page uses it, not when the app opens. If the person says no, the rest of your app keeps working, so show the Library as unavailable rather than failing.
- The sound's `url` plays once the person has picked it, or straight away when your app added it.

`library-read` needs Mixel 0.1.23 and `mixel` 0.3.5 or later; an older `mixel check` reports it as `permission_unknown`.

An app with `library` alone can't list the Library or open a sound it didn't make.

The drawn form has a **From Library** button on every `ox.Files` control. It follows the same rule: it lists the Library only for an app that asks for `library-read`.
