Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/clean-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
# The DSP nodes' real gate: every interpreter must render them
# identically, which needs two interpreters, which is why it lives here
# and not in test-cpython.yml. There is no stored digest to match - the
# comparison IS the gate (docs/correctness-standard.md) - and verify_dsp
# comparison IS the gate (docs/how-it-works/correctness-standard.md) - and verify_dsp
# refuses a run with fewer than two interpreters rather than passing one
# that cannot fail.
#
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-cpython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ jobs:
# The DSP nodes' real gate is cross-interpreter agreement and it needs
# two interpreters, so it lives in clean-build.yml where a MicroPython
# binary is built. A one-interpreter run cannot fail and verify_dsp now
# refuses one (docs/correctness-standard.md).
# refuses one (docs/how-it-works/correctness-standard.md).
#
# What this matrix can say is worth having and is not a comparison: every
# probe RUNS, on four operating systems and five Pythons. That catches an
Expand Down Expand Up @@ -132,7 +132,7 @@ jobs:
# runner. This job is currently the ONLY thing that builds an ARM wheel:
# the org release matrix (reusable-build-native-and-wasm-wheels.yml, at
# publishing-v8) runs ubuntu-latest, windows-latest and macos-latest, so
# releases still ship no aarch64 wheel. See docs/building-wheels.md for
# releases still ship no aarch64 wheel. See docs/how-it-works/wheels-and-platforms.md for
# what closing that gap costs. Proving the build here first means the org
# change, when it comes, is a matrix line rather than a discovery.
linux-arm-wheels:
Expand Down
18 changes: 9 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ for source compatibility; only this repo's own name differs.
offline rendering — numpy, desktop-only, never frozen) and
`lib/audiodsp_util/` (`float32`, the round trip that makes a setting derived
in Python the same number on a board as on a desktop — see
[docs/correctness-standard.md](docs/correctness-standard.md)). Both ship
[docs/how-it-works/correctness-standard.md](docs/how-it-works/correctness-standard.md)). Both ship
inside the `omnipython-audiodsp` wheel. The instrument and effect libraries that
used to sit beside it — `audioinstruments` (55 `synthio` instruments) and
`audioeffects` (45 effect classes, racks included) — live in
Expand All @@ -49,10 +49,10 @@ for source compatibility; only this repo's own name differs.
here rather than the other way round.
- `docs/porting-plan.md` — the full phased porting history, architecture,
and target layout
- `docs/upstream-sync.md` — when and how to resync the CircuitPython-derived
- `docs/how-it-works/upstream-sync.md` — when and how to resync the CircuitPython-derived
modules with upstream, what the last resync took, and the list of every
deliberate difference (the pump, `deinit`, the recorded deviations)
- `docs/upstream-diff.md` — the reasons and measurements behind each
- `docs/how-it-works/upstream-diff.md` — the reasons and measurements behind each
deviation from upstream CircuitPython (verbatim-kept quirks vs. genuine port
bugs found and fixed)
- `tests/parity/` — oracle-diff scripts, run unchanged against both this
Expand All @@ -63,7 +63,7 @@ for source compatibility; only this repo's own name differs.
`audiovorbis` wraps, BSD-3-Clause, vendored (see its `ORIGIN.txt`). Never
listed in a build on its own: `src/shared/audiodsp_vorbis.c` includes it
into one translation unit with every symbol renamed. See
[docs/vorbis.md](docs/vorbis.md).
[docs/reference/vorbis.md](docs/reference/vorbis.md).

## Sibling dependencies (cloned, not vendored)

Expand All @@ -82,9 +82,9 @@ of this repository in the parent workspace, same pattern as
- Oracle diffing is the core discipline: every parity script under
`tests/parity/` runs unchanged against this port and `bin/circuitpython`,
rendering PCM and diffing byte-for-byte (or documenting the exact,
bounded exception in `docs/upstream-diff.md`).
bounded exception in `docs/how-it-works/upstream-diff.md`).
- The nine modules that are **ours** have no oracle, by decision
([docs/correctness-standard.md](docs/correctness-standard.md), 2026-09-09).
([docs/how-it-works/correctness-standard.md](docs/how-it-works/correctness-standard.md), 2026-09-09).
Upstream CircuitPython has no counterpart to them, so they are held to two
things: every target renders them identically, and their numeric traits hold.
`.venv/bin/python tests/parity/verify_dsp.py --micropython ../micropython/ports/unix/build-pydevices/micropython`
Expand Down Expand Up @@ -198,10 +198,10 @@ parity golden is measured against. The rule, for any agent working here:
every CP-shared gate and re-pins the binary's hash with the reason written
down. **Every pin move is a resync**: take every audio fix and every
addition (a new property, argument or class) upstream made since the old
pin, following `docs/upstream-sync.md`, and update its record of what was
pin, following `docs/how-it-works/upstream-sync.md`, and update its record of what was
taken and what differs on purpose. The oracle is built at the same version and the same ceiling this port
ships — an oracle at a different configuration cannot answer the only question
worth asking. See `docs/correctness-standard.md` and
worth asking. See `docs/how-it-works/correctness-standard.md` and
`tests/test_voice_ceiling_consistency.py`.
- **Extending CircuitPython is fine and is the designed path**: new modules
live in this repo under `src/circuitpython_spike/` and build, with
Expand All @@ -211,7 +211,7 @@ parity golden is measured against. The rule, for any agent working here:
because the oracle is built with it, so a behavioral change would leak
*into* the oracle.
- Fixes to bugs that also exist upstream go in **this repo's targets only**
(MicroPython/CPython/`src/shared/`), recorded in `docs/upstream-diff.md`
(MicroPython/CPython/`src/shared/`), recorded in `docs/how-it-works/upstream-diff.md`
— never into the CP tree. Approved deviations from the oracle are
enumerated there; **ask before adding one**.
- Quick self-check after any CP-adjacent work: `circuitpython.mk` compiles
Expand Down
4 changes: 2 additions & 2 deletions CIRCUITPYTHON_ORACLE
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# 2026-10-22, from 10.3.0 on 2026-10-08 with audiodsp#201, from 10.2.1 to
# 10.3.0 on 2026-09-09).
# Moving it is a re-port, not a bump: every move is a resync with upstream
# (docs/upstream-sync.md; the one before this was audiodsp#220). See also
# AGENTS.md "The CircuitPython oracle" and docs/upstream-diff.md. The 64-voice oracle binary built from
# (docs/how-it-works/upstream-sync.md; the one before this was audiodsp#220). See also
# AGENTS.md "The CircuitPython oracle" and docs/how-it-works/upstream-diff.md. The 64-voice oracle binary built from
# it lives at bin/circuitpython-oracle-11.0.0-alpha.2 (build_interpreters.sh
# cp-oracle); tests/test_voice_ceiling_consistency.py pins its sha256.
11.0.0-alpha.2 d53b2277cfad71589028e5da77c984c045db990d
124 changes: 124 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Contributing

Bugs, and things you need that don't work yet, go to
[issues](https://github.com/PyDevices/audiodsp/issues). Planned work is in
[ROADMAP.md](ROADMAP.md). A documentation correction, a focused CPython
fixture or a well-bounded module change is a good first pull request.

[How it works](docs/how-it-works/index.md) maps the repository: what each
directory holds, how one graph runs on three targets, and where the
boundaries are.

## Build from source

For CPython, build and install the wheel from a checkout:

```sh
python -m pip install build numpy
python -m build
python -m pip install dist/*.whl
```

For MicroPython and CircuitPython, build the way
[Install](docs/get-started/install.md) describes, with your checkout in place
of a clone. The `mp3` decoder that `audiomp3` wraps is fetched, not
vendored:

```sh
scripts/fetch_deps.sh
```

It puts the decoder under `.deps/` at the commit [DEPENDENCIES.lock](DEPENDENCIES.lock)
pins.

## Test

CI runs the CPython fixture tests and the parity gates whose goldens live in
this repository:

```sh
python -m unittest discover -s tests -p "test_*.py"
python tests/parity/verify_acceptance.py
python tests/parity/verify_effects.py
python tests/parity/verify_streaming.py
python tests/parity/verify_biquad.py
python tests/parity/verify_mixdown_knee.py
python -m flake8
```

Run the tests for the module you changed rather than the whole suite: the
full run is long. The deeper parity checks need built interpreters and the
pinned CircuitPython oracle beside this checkout, so CI doesn't run them and
you don't need them for a first contribution.
[The correctness standard](docs/how-it-works/correctness-standard.md) says
what each module is held to.

## Rules that keep the port honest

- **Don't modify the CircuitPython oracle.** The tag in `CIRCUITPYTHON_ORACLE`
is what every parity golden is measured against. Edit CircuitPython's own
sources for it and parity quietly means something else. Moving the pin is a
resync with upstream, done deliberately: see
[Keeping in step with upstream](docs/how-it-works/upstream-sync.md).
- **Extend CircuitPython, don't change it.** New modules live in `src/` and
build into CircuitPython as a user C module through `circuitpython.mk`. They
never shadow or rewrite one of CircuitPython's.
- **Don't re-capture a parity golden casually.** A fix that is right can still
change one; say what independent evidence shows it is right.
- **Don't move the dependency pins** (`DEPENDENCIES.lock`, `CIRCUITPYTHON_ORACLE`)
without saying why.
- **A fix for a bug that also exists upstream** goes in this repository's
targets only, recorded in
[upstream-diff](docs/how-it-works/upstream-diff.md); open an issue before
adding a new deviation from CircuitPython. The fixes already sent upstream
are in [upstream reports](docs/upstream-reports/README.md).

## Build and release wheels

`pydevices-audiodsp` is a native CPython distribution. `python -m build` makes
a local source archive and wheel.

A GitHub Release `vX.Y.Z`, matching the `VERSION` file (which is also where
`_audiodsp.__version__` comes from), starts the organization's reusable
publishing workflow. The pin is the `@publishing-vN` ref in
`.github/workflows/publish-release-packages.yml`, with
`build-kind: native-and-wasm`. It builds and validates exactly the number of
wheels `expected-wheel-count` names in that file. If the count changes, change
it in the same pull request.
[Wheels and platforms](docs/how-it-works/wheels-and-platforms.md) lists what
that is and what it leaves out.

Final releases then go to production PyPI too, after a maintainer approves the
`pypi` environment. That upload is the `pypi` job in this repository's own
`publish-release-packages.yml`, not in the reusable workflow, because PyPI's
Trusted Publishing only matches the workflow that runs the upload
([why](https://github.com/PyDevices/.github/blob/main/docs/publishing-automation.md#production-pypi-opt-in-protected-trusted-publishing)).

After TestPyPI publication, run `python scripts/test_testpypi_install.py` on
fresh Linux and Windows hosts. It takes an optional version and defaults to
the one in `VERSION`; it builds a bare environment and one with the `[render]`
extra.

## License

audiodsp is MIT licensed; see [LICENSE](LICENSE).

The attribution that goes with it lives in [NOTICE](NOTICE). Substantial
portions of this code are ported from CircuitPython under its own MIT
license. CircuitPython is a trademark of Adafruit Industries, and this
project is not affiliated with or endorsed by them. The vendored test corpus
under `tests/vendor/` carries its own licenses. The two are separate files on
purpose: GitHub and PyPI only detect the license when LICENSE holds the MIT
text and nothing else, so please don't fold NOTICE back into it. `NOTICE` is
in setuptools' default `license-files` glob, so it ships in the wheel and
sdist alongside `LICENSE`.

The Helix MP3 decoder that `audiomp3` wraps is RPSL/RCSL-licensed, not MIT.
`scripts/fetch_deps.sh` fetches it, carried unmodified per upstream's own
terms; it isn't part of this repository. See
[upstream-diff](docs/how-it-works/upstream-diff.md).

The Tremor Vorbis decoder that `audiovorbis` wraps is in this repository, in
[third_party/tremor](third_party/tremor), under Xiph.Org's BSD-3-Clause
license ([COPYING](third_party/tremor/COPYING)), which travels with the
wheel.
Loading
Loading