Add packaging, date-based versioning, and full install docs

Versions are now the release date and a revision within that day, padded to
two digits so they sort as text: 2026-08-21_01.

Neither packaging system accepts that form, so it is converted at the edge
rather than kept as a second version string that could drift out of step:
PEP 440 forbids dashes and underscores in a release segment, and a Debian
version may not contain an underscore at all. The date and revision in
__init__.py are the single source; pyproject reads the converted form, and
the tests check that pip and dpkg both order releases correctly.

packaging/build-deb.sh builds a .deb with plain dpkg-deb. Every dependency
is already in Debian, so apt resolves the lot; the package also blacklists
the DVB-T driver that would otherwise claim the receiver. Deliberately not
debhelper: the payload is pure Python with nothing to compile, and this way
the build needs nothing installed beyond dpkg.

The speech recognisers are not packaged for Debian and can only come from
pip, so they are suggested rather than depended on -- transcription is off
by default and reports plainly when no recogniser is present.

README now documents every dependency with its package name on Debian,
Fedora and Arch, how to let a user reach the receiver, and how to check the
install worked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
The Dust Council 2026-08-21 21:05:51 -07:00
parent db3e0c79b9
commit 52fe16123f
5 changed files with 313 additions and 30 deletions

125
README.md
View file

@ -28,45 +28,118 @@ decoded to text.
## Install
### From a package (Debian, Ubuntu, Mint)
```bash
sudo apt install rtl-sdr librtlsdr0 espeak-ng # Debian/Ubuntu
./packaging/build-deb.sh # writes dist/bandsaunter_<version>_all.deb
sudo apt install ./dist/bandsaunter_*.deb
```
apt pulls in every dependency itself, and the package blacklists the DVB-T
driver that would otherwise claim the receiver. Nothing else to do.
### From source
```bash
sudo apt install rtl-sdr librtlsdr0 espeak-ng # Debian, Ubuntu, Mint
pip install -e .
```
### Dependencies
## Dependencies
| | Package | Needed for |
|---|---|---|
| **required** | `librtlsdr0` (`rtl-sdr`) | talking to the dongle at all |
| **required** | `numpy`, `scipy` | all signal processing |
| **required** | `rich` | the menus and the live display |
| **required** | `PyYAML` | the settings file and profiles |
| *recommended* | `espeak-ng` | clearer spoken timestamps |
| *optional* | `faster-whisper` (pip) | transcribing speech to text |
Everything required is packaged in Debian, Fedora and Arch, so nothing has to
be built.
`espeak-ng` is a **recommendation, not a requirement**: without it the spoken
timestamps are produced by a built-in formant synthesiser, so the feature
works on a machine with nothing else installed. With it they are clearer and
render about three times faster. Any of `espeak`, `pico2wave`, `flite` or
macOS `say` is used if found instead.
| | Package | Debian/Ubuntu | Fedora | Arch | Needed for |
|---|---|---|---|---|---|
| **required** | librtlsdr | `librtlsdr0` | `rtl-sdr` | `rtl-sdr` | talking to the receiver at all |
| **required** | NumPy | `python3-numpy` | `python3-numpy` | `python-numpy` | all signal processing |
| **required** | SciPy | `python3-scipy` | `python3-scipy` | `python-scipy` | filters, resampling, spectra |
| **required** | Rich | `python3-rich` | `python3-rich` | `python-rich` | menus and the live display |
| **required** | PyYAML | `python3-yaml` | `python3-pyyaml` | `python-yaml` | settings file and profiles |
| *recommended* | eSpeak NG | `espeak-ng` | `espeak-ng` | `espeak-ng` | clearer spoken timestamps |
| *optional* | rtl-sdr tools | `rtl-sdr` | `rtl-sdr` | `rtl-sdr` | `rtl_test` and friends for diagnosis |
| *optional* | faster-whisper | pip only | pip only | AUR | transcribing speech to text |
| *optional* | Matplotlib | `python3-matplotlib` | `python3-matplotlib` | `python-matplotlib` | nothing yet; reserved for plots |
For a Debian package that maps to `Depends: librtlsdr0, python3-numpy,
python3-scipy, python3-rich, python3-yaml`, `Recommends: espeak-ng,
rtl-sdr` and `Suggests: python3-vosk` — transcription is off by default and
the scan reports it plainly when no recogniser is installed. `rtl-sdr` itself only supplies command-line tools bandsaunter does not
call — the library is what matters.
Two notes on the optional ones:
`bandsaunter scan --combine --dry-run` reports which engine will be used.
**eSpeak NG is a recommendation, not a requirement.** Without it the spoken
timestamps come from a built-in formant synthesiser, so that feature works on
a machine with nothing else installed. With it they are clearer and render
about three times faster.
If the dongle is not accessible, the DVB-T kernel driver has usually claimed
it:
**Speech recognition is not packaged for Debian** and can only come from pip.
Transcription is off by default and says so plainly when no recogniser is
present, so this never blocks an install:
```bash
echo 'blacklist dvb_usb_rtl28xxu' | sudo tee /etc/modprobe.d/blacklist-rtl.conf
sudo rmmod dvb_usb_rtl28xxu
pip install faster-whisper # best on radio audio, ~120 MB
pip install vosk # ~10 MB plus a 40 MB model, weaker on noise
bandsaunter transcribe --engines
```
Check with `bandsaunter devices --test`.
### Other distributions
```bash
sudo dnf install rtl-sdr python3-numpy python3-scipy python3-rich \
python3-pyyaml espeak-ng # Fedora
sudo pacman -S rtl-sdr python-numpy python-scipy python-rich \
python-yaml espeak-ng # Arch
brew install librtlsdr espeak-ng && pip install -e . # macOS
```
### Letting your user reach the receiver
The DVB-T television driver claims RTL dongles on sight and has to be kept
away from them. The `.deb` does this for you; from source:
```bash
echo 'blacklist dvb_usb_rtl28xxu' | sudo tee /etc/modprobe.d/blacklist-rtlsdr.conf
sudo rmmod dvb_usb_rtl28xxu # or just unplug and replug the receiver
```
If the device is found but cannot be opened, your user needs permission for
it. Most distributions ship a udev rule with `rtl-sdr`; failing that:
```bash
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666"' \
| sudo tee /etc/udev/rules.d/20-rtlsdr.rules
sudo udevadm control --reload-rules && sudo udevadm trigger
```
### Check it worked
```bash
bandsaunter devices --test # opens the receiver and captures a test block
bandsaunter scan -b 2m --simulate # exercises everything without hardware
```
## Versioning
Releases are named for the day they were made and a revision within that day:
```
2026-08-21_01 first build on the 21st
2026-08-21_02 second build the same day
2026-09-01_01
```
The revision is padded to two digits so that versions sort correctly as text —
without it, revision 10 would sort before revision 2.
Packaging tools cannot use that form directly, so it is converted at the edge
rather than kept as a second version string that could drift:
| Where | Form | Why |
|---|---|---|
| the program, `--version` | `2026-08-21_01` | what you asked for |
| pip, `pyproject.toml` | `2026.8.21.1` | PEP 440 forbids dashes and underscores in a release |
| dpkg, the `.deb` | `2026.08.21.01-1` | Debian versions may not contain underscores |
`bandsaunter/__init__.py` holds the date and revision; the other two forms are
derived from it, and the test suite checks that all three describe the same
release and that both pip and `dpkg --compare-versions` order them correctly.
## Quick start