sweeptune
Minimal macOS CLI that measures your listening room with a log sine sweep and tells you what to enter into the Fosi Audio S3 10-band EQ (31.5 Hz – 16 kHz, ±10 dB, 0.5 dB steps) to reach a neutral-but-pleasing, Harman-like in-room curve. It also reports reverberation (RT60), early reflections and room modes, because EQ cannot fix echo.
Install
brew install uv
uv tool install sweeptune # from PyPI, puts `sweeptune` on your PATH
sweeptune --help
From a clone instead: uv sync, then prefix the commands below with uv run.
Setup
Select the Fosi S3 as the Mac's sound output (Control Center → Sound → AirPlay) before measuring.
Device names can be overridden in an optional sweeptune.toml (see src/sweeptune/config.py for all keys):
output_device = "S3" # name fragment of the AirPlay output
input_device = "" # name fragment; empty = mic profile default
max_boost_db = 4.0
shelf_db = 6.0 # bass shelf of the harman-like target
Workflow
uv run sweeptune doctor # routing, mic inputs, noise floor
uv run sweeptune balance --live # set the amp's balance knob at the seat (L/R level + distance)
uv run sweeptune measure --mic audyssey # 7 positions, L and R, EQ flat
uv run sweeptune eq suggest # table + copy string for the S3
uv run sweeptune plot # frequency response vs target + suggested EQ (PNG, opens in Preview)
# enter the values on the S3 (and lower its volume by the headroom shown)
uv run sweeptune verify # re-measure, compare to prediction, next correction
uv run sweeptune verify # repeat until converged
uv run sweeptune report # sessions/<timestamp>/report.md + PNGs
Balance
sweeptune balance --live plays L, R, L sweeps at the listening seat and shows how much louder one side is
(500 Hz – 4 kHz, where the stereo image lives) and how much farther one speaker is. Turn the amp's balance
knob, press Enter to re-measure, and stop within ±0.5 dB. Fix a distance difference by moving the
speaker first; the balance control is for the remaining level difference. Without --live,
sweeptune balance reports the same figures from the latest multi-position measurement. The S3 EQ acts on both
channels equally, so balance and EQ can be set in either order.
Optional:
sweeptune eq probe 125– change one band by −6 dB and learn the S3's real filter Q (saved tostreamer.json).sweeptune mic relcal iphone17pro --ref audyssey– derive a calibration for another mic at the same spot.sweeptune sweep export+sweeptune analyze rec1.wav rec2.wav …– offline path, e.g. recording on the iPhone with an app that offers a measurement (unprocessed) mode.sweeptune plot --channels– left and right speaker on a shared level, so a balance offset is visible.sweeptune --simulate …– run any command against a synthetic room, no speakers needed.
Microphones
| id | Mic | Use |
|---|---|---|
audyssey |
Audyssey mic bundled with AV receivers, MacBook 3.5 mm jack | primary; trusted 20 Hz – 10 kHz |
iphone17pro |
iPhone 17 Pro via Continuity mic, or offline WAV | secondary; AGC check first |
macbook-m1pro |
built-in array | last resort; 100 Hz – 8 kHz, compare iterations only |
None of these mics has a traceable calibration, so all results are relative. The MacBook jack is CTIA TRRS;
if doctor finds no external mic, the Audyssey plug needs a TRS→TRRS mic adapter.
Tests
uv run pytest
Releasing
- Bump
versioninpyproject.toml(PyPI never accepts the same version twice), commit and push. - Publish a GitHub release whose tag is that version with a
vprefix, e.g.v0.2.0. Thepublishworkflow tests, builds and uploads to PyPI via trusted publishing (no token needed).
License
MIT © 2026 Maximilian Schuh. Free to use, modify and redistribute, including commercially, as long as the copyright notice and license text are kept — i.e. with acknowledgement.
Metadata
Release files for sweeptune 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sweeptune-0.1.0.tar.gz | 105.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sweeptune-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 156.3 kB
Release files / sweeptune-0.1.0.tar.gz
| Download URL | sweeptune-0.1.0.tar.gz |
|---|---|
| Size | 105.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
40618a7db0b92d5e36c01e2eaabce7bb1f0448ad5e05b80b9fe8f056e693bdeb
|
|
BLAKE2b-256 checksum How to use checksums |
15491c0a40440bc9b1063950fd9e6ae1576251db030da7ebab3b1f587a6696e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / sweeptune-0.1.0-py3-none-any.whl
| Download URL | sweeptune-0.1.0-py3-none-any.whl |
|---|---|
| Size | 51.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
55ffe519a258ef966cc406566fa7359eb83fc2c80127b2be75d7ea5f2a0b5146
|
|
BLAKE2b-256 checksum How to use checksums |
c9d60ecf058b47fd49614828fea957cf3c16195e1fd2996afa0d62f453897986
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log