Metadata-Version: 2.4
Name: sweeptune
Version: 0.1.0
Summary: Measure your room with a sweep and get settings for a 10-band graphic EQ
Project-URL: Homepage, https://github.com/maxischuh/sweeptune
Project-URL: Repository, https://github.com/maxischuh/sweeptune
Project-URL: Issues, https://github.com/maxischuh/sweeptune/issues
Author: Maximilian Schuh
License-Expression: MIT
License-File: LICENSE
Keywords: acoustics,audio,equalizer,measurement,room-correction
Classifier: Environment :: Console
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
Requires-Python: >=3.12
Requires-Dist: matplotlib>=3.9
Requires-Dist: numpy>=2.0
Requires-Dist: rich>=13.7
Requires-Dist: scipy>=1.13
Requires-Dist: sounddevice>=0.5
Requires-Dist: soundfile>=0.12
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# 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

```bash
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):

```toml
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

```bash
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 to `streamer.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

```bash
uv run pytest
```

## Releasing

1. Bump `version` in `pyproject.toml` (PyPI never accepts the same version twice), commit and push.
2. Publish a GitHub release whose tag is that version with a `v` prefix, e.g. `v0.2.0`.
   The `publish` workflow tests, builds and uploads to PyPI via trusted publishing (no token needed).

## License

[MIT](LICENSE) © 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.
