Metadata-Version: 2.4
Name: shipwright-audio
Version: 0.1.0
Summary: A code-first audio studio: write -> render -> listen -> adjust.
Project-URL: Homepage, https://github.com/dinger086/shipwright-audio
Project-URL: Repository, https://github.com/dinger086/shipwright-audio
Project-URL: Issues, https://github.com/dinger086/shipwright-audio/issues
Project-URL: Changelog, https://github.com/dinger086/shipwright-audio/blob/main/CHANGELOG.md
Author: Robert Braun
License-Expression: MIT
License-File: LICENSE
Keywords: audio,dawdreamer,faust,music,sfx,synthesis
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Sound/Audio
Requires-Python: <3.13,>=3.10
Requires-Dist: dawdreamer
Requires-Dist: numpy
Requires-Dist: scipy<1.15,>=1.11
Requires-Dist: soundfile
Provides-Extra: dev
Requires-Dist: pytest; extra == 'dev'
Provides-Extra: midi
Requires-Dist: pretty-midi; extra == 'midi'
Provides-Extra: soundfont
Requires-Dist: pyfluidsynth; extra == 'soundfont'
Provides-Extra: theory
Requires-Dist: music21; extra == 'theory'
Description-Content-Type: text/markdown

# shipwright-audio

A code-first audio studio: describe a sound or a few bars of music in a
small Python function, run one command, get a `.wav`.

Requires Python 3.10 through 3.12.

## The shape

Four layers, cleanly separated:

| Layer | File | Job |
| --- | --- | --- |
| **Composition** (above) | `shipwright/compose.py` | chord symbols / pitch lists → `Note`s |
| **Sound sources** (below) | `shipwright/instruments.py` | Faust synths the engine plays |
| **SFX synthesis** | `shipwright/dsp.py` | numpy oscillators / noise / envelopes / filters |
| **The spine** | `shipwright/engine.py` | DawDreamer: graph → mix → bus FX → offline render |

You author in a `sounds/` directory in your project (create it yourself —
the tool reads `./sounds` from wherever you run it). Each file is one sound.
A build-function returns either a **`Buffer`** (raw numpy samples → SFX) or a
**`RenderSpec`** (tracks of MIDI played by instruments → music). The harness
routes by type. Copy-paste starting points live in [`examples/`](examples/).

## Install

As a tool (gets you the `shipwright` command anywhere):

```bash
uv tool install shipwright-audio      # or: pipx install shipwright-audio
```

Or from a checkout for development:

```bash
uv sync                               # create .venv + install deps
```

## Use

`shipwright` loads sounds from `./sounds` and writes to `./output` relative
to the directory you run it in (override with `SHIPWRIGHT_SOUNDS` /
`SHIPWRIGHT_OUTPUT`).

```bash
shipwright                       # list sounds
shipwright sea_bed               # render one  -> output/sea_bed.wav
shipwright all --ogg             # render all, also write .ogg
shipwright --watch sea_bed       # re-render on every save (tight loop)
```

From a checkout without installing, `uv run shipwright ...` or
`python render.py ...` both work.

## Develop

```bash
uv run --extra dev pytest
env SHIPWRIGHT_SOUNDS=examples uv run shipwright ui_blip
env SHIPWRIGHT_SOUNDS=examples uv run shipwright sea_bed
```

## Add a sound

Create `sounds/my_thing.py`:

```python
from shipwright import sound, Buffer, dsp

@sound("zap")
def zap():
    s = dsp.ad_env(dsp.saw(220, 0.25), attack=0.001, release=0.2)
    s = dsp.lowpass(s, 1200)
    return Buffer(dsp.to_stereo(dsp.normalize(s, 0.9)))
```

…then `shipwright zap`. Music works the same way but returns a
`RenderSpec` of `Track`s — see [`examples/music_sea_bed.py`](examples/music_sea_bed.py).

## Why DawDreamer is the spine but not the whole thing

DawDreamer mixes, automates (sample-accurate, via numpy arrays), hosts
plugins, and renders deterministically offline. It does **not** compose and
ships **no instruments** — so composition lives above it (`compose.py`) and
sound sources below it (`instruments.py`, here as Faust). That's the whole
architecture.

## Nicer instruments (upgrade path)

The built-in Faust synths need zero files. When you want more "produced"
sound, swap a `Track`'s instrument for either:

- **SoundFont**: drop an `.sf2` in `soundfonts/`, render its MIDI with
  `pyfluidsynth`, feed the audio into the DawDreamer graph as a track.
- **VST/AU**: `engine.make_plugin_processor("name", "/path/to/plugin.vst3")`,
  then `add_midi_note(...)` exactly like the Faust instruments.

## License

`shipwright-audio` is MIT licensed. Its DawDreamer dependency is GPLv3; review
that license before redistributing bundled applications or generated tooling.
