# Installing bandsaunter Step by step, from nothing to a scan running. The whole of it is four dependencies and one C library; there is nothing to compile and no model to download unless you want speech transcription. If you are on Debian, Ubuntu or Mint, [build the package](#a-debian-ubuntu-mint-the-package) — it is two commands and apt does the rest. Anywhere else, use [a virtual environment](#b-anywhere-else-a-virtual-environment). **You can try the whole program before buying or plugging in a receiver.** `--simulate` runs the scanner against a synthetic band, and `bandsaunter adsb --simulate` flies imaginary aircraft past an imaginary receiver. Neither needs hardware or a network. --- ## What you need | | | |---|---| | **Python** | 3.10 or newer | | **A receiver** | any RTL2832U dongle (RTL-SDR Blog v3/v4, NESDR, generic) — *optional*, everything except live scanning works without one | | **An aerial** | whatever came with the dongle to start; a band-cut aerial for anything serious | | **Disk** | ~250 MB for the program and its dependencies; recordings are what actually fill a disk | | **Network** | only for installing, and for callsign and aircraft lookups afterwards | Operating systems: developed and packaged on Debian; runs on any Linux with Python 3.10+, and on macOS with `brew install librtlsdr`. On Windows it will run under WSL2 with USB passthrough, which is more trouble than it is worth — a Raspberry Pi is the easier answer. --- ## A. Debian, Ubuntu, Mint: the package ```bash git clone bandsaunter cd bandsaunter ./packaging/build-deb.sh # writes dist/bandsaunter__all.deb sudo apt install ./dist/bandsaunter_*.deb ``` That is the whole of it. `build-deb.sh` needs only `dpkg-deb` and `fakeroot`, both already present on a normal system; apt then pulls in numpy, scipy, rich, PyYAML and librtlsdr itself. The package also does the one piece of system setup that a `pip` install cannot: it blacklists the DVB-T television driver, which claims these dongles on sight. Read what it prints — if a receiver was plugged in during the install, unplug and replug it, or run `sudo rmmod dvb_usb_rtl28xxu` once. Uninstall with `sudo apt remove bandsaunter`, which also removes the blacklist. ### For several machines: your own apt repository `./packaging/build-repo.sh` builds the application, a speech recogniser and a model into a small apt repository under `dist/repo`, so that `apt install bandsaunter` on every other machine brings transcription with it. See **Install → From your own apt repository** in the README. --- ## B. Anywhere else: a virtual environment **Debian, Ubuntu and Fedora refuse `pip install` outside a virtual environment** (PEP 668: *"externally-managed-environment"*). That is the error most people hit first, and a virtual environment is the answer: ```bash sudo apt install librtlsdr0 # Debian/Ubuntu/Mint # sudo dnf install rtl-sdr # Fedora # sudo pacman -S rtl-sdr # Arch # brew install librtlsdr # macOS git clone bandsaunter cd bandsaunter python3 -m venv .venv . .venv/bin/activate pip install . # a few wheels; under a minute ``` That installs four wheels — numpy, scipy, rich, PyYAML — and puts two commands on the path, `bandsaunter` and `saunterbrowse`. Nothing is built from source. Use `pip install -e .` instead if you intend to change the code. The commands only exist while the environment is active. To have them always, install with [pipx](https://pipx.pypa.io) instead, which keeps its own environment and puts the commands on your path permanently: ```bash sudo apt install pipx && pipx install /path/to/bandsaunter ``` As a last resort — a throwaway machine, a container — `pip install --break-system-packages .` overrides the refusal. It puts the dependencies in among the system ones, which is what the warning is about. --- ## Check that it worked ```bash bandsaunter --version bandsaunter bands # the built-in US band plan; no hardware needed bandsaunter scan -b 2m --simulate # a whole scan against a synthetic band bandsaunter adsb --simulate --seconds 30 bandsaunter flights # draws what the last command heard ``` With a receiver plugged in: ```bash bandsaunter devices # should list the dongle bandsaunter devices --test # opens it and captures a block bandsaunter # interactive setup, then scanning ``` `bandsaunter devices` is the command to run when something is wrong: it says whether librtlsdr loaded, whether a dongle was found, and what to do about it if not. --- ## Optional dependencies Everything below is genuinely optional. The program starts, scans, records, identifies, decodes Morse and draws waterfalls with none of it, and says plainly when a feature is unavailable rather than failing. | Install | Gives you | Without it | |---|---|---| | `sudo apt install espeak-ng` | clearer spoken timestamps on combined recordings, rendered about three times faster | a built-in formant synthesiser does the same job, less clearly | | `sudo apt install ffmpeg` | `bandsaunter flights --out sky.mp4` writes a video | a GIF is written instead, and it says so | | `sudo apt install rtl-sdr` | `rtl_test`, `rtl_sdr` and friends, for diagnosing hardware | nothing missing from bandsaunter itself | | `pip install faster-whisper` | speech transcription of recorded voice — see [the step-by-step below](#speech-transcription-step-by-step) (~250 MB installed, plus a 148 MB model) | transcription is off; scans report that no recogniser is installed | | `pip install vosk` | a smaller, weaker recogniser (~10 MB plus a 40 MB model) | as above | | `pip install pyte` | the terminal-resize tests | those tests skip | **Aircraft and callsign lookups need no installation**, only a network. They ask public registers about a callsign or a 24-bit address and cache the answers for a month; `--no-lookup` turns them off, and what the address and the callsign say on their own is worked out offline either way. --- ## Speech transcription, step by step This is the only part with a real download in it, and the only part Debian cannot supply, so it gets its own section. Two pieces are needed: the **recogniser** (a Python package) and the **model** it loads (the weights). Scanning, recording, identifying and CW decoding all work without either. ### Step 1 — install the recogniser where bandsaunter can see it The recogniser must go into the same environment bandsaunter itself runs from, or bandsaunter will not find it. If you installed into a virtual environment: ```bash . .venv/bin/activate # the same one bandsaunter is in pip install faster-whisper ``` If you installed for your user with `pip install --user` (the layout this project was developed with, everything under `~/.local`): ```bash pip install --user --break-system-packages faster-whisper ``` `--break-system-packages` is what gets past the PEP 668 refusal described above; with `--user` it writes to `~/.local/lib/python3.x/site-packages` and touches nothing the distribution owns. This pulls in `ctranslate2`, `av`, `huggingface-hub`, `tokenizers` and `onnxruntime` — about 250 MB installed, no compiler needed, all wheels. ### Step 2 — check bandsaunter can see it ```bash bandsaunter transcribe --engines ``` ``` engine installed how to get it faster-whisper yes pip install faster-whisper (best on radio audio) whisper no pip install openai-whisper whisper-cli no whisper.cpp, no Python dependencies vosk no pip install vosk (small, weaker on noisy audio) pocketsphinx no pip install pocketsphinx (tiny, poor on radio audio) auto would use faster-whisper ``` `installed: yes` against `faster-whisper` and a last line naming it is the whole test. If it says `no` while pip says the package is there, they are in different environments — see [When it does not work](#when-it-does-not-work). ### Step 3 — get the model The model is **not** in the pip package. By default `base.en` is used, and the first transcription downloads it from Hugging Face (`Systran/faster-whisper-base.en`) into `~/.cache/huggingface/hub/`, about 140 MB. Everything after that is offline. You can leave it to happen by itself, but a scan that appears to hang for a minute on its first voice capture is unnerving, so it is better to fetch it deliberately: ```bash python3 -c "from faster_whisper import WhisperModel; WhisperModel('base.en', device='cpu', compute_type='int8')" du -sh ~/.cache/huggingface # about 140 MB when it has finished ``` To watch what any engine is doing, including a download in progress: ```bash BANDSAUNTER_ENGINE_OUTPUT=1 bandsaunter transcribe recording.wav --stdout ``` Model sizes, measured from the repository listings: | Model | Download | Notes | |---|---|---| | `tiny.en` | 78 MB | fastest; misses words on noisy radio audio | | `base.en` | 148 MB | **the default**; keeps up comfortably on an ordinary machine | | `small.en` | 486 MB | noticeably better on weak signals, several times slower | | `medium.en` | 1.5 GB | better again; wants a fast machine and patience | | `large-v3` | 3.1 GB | multilingual, and slow on a CPU | Everything runs **on the CPU**, at int8 — no GPU, no CUDA, no nvidia packages, on purpose: a scanner should not need a graphics card, and int8 on a CPU keeps up with a scan. ### Step 4 — turn it on ```bash bandsaunter transcribe recording.wav --stdout # one file, straight away bandsaunter transcribe ~/bandsaunter # a whole directory bandsaunter scan -b 2m --transcribe # during a scan bandsaunter config transcribe=true # or make that the default bandsaunter config transcribe_model=small.en # and choose the model ``` During a scan, transcription runs on its own thread after each recording is written, so it never holds up the sweep. Transcripts land beside the audio as `_transcription.txt`, and `saunterbrowse` shows them. ### Doing it without a network, or on many machines `./packaging/build-repo.sh` collects the recogniser and the model into two Debian packages, so no machine you install on ever reaches the network: ```bash MODEL=base.en ./packaging/build-repo.sh # any size from the table above ``` That produces `bandsaunter-transcribe` (the wheels, unpacked into `/usr/lib/bandsaunter/vendor`) and `bandsaunter-model-base-en` (the weights, in `/usr/share/bandsaunter/models/base.en`), and an apt repository serving them alongside `bandsaunter` itself. Both are `Recommends`, so a plain `apt install bandsaunter` from that repository brings the lot. For a machine that is not using apt, copy the model directory anywhere and point at it: ```bash export BANDSAUNTER_MODEL_DIR=/opt/models # holds base.en/, small.en/ ... bandsaunter config transcribe_model=/opt/models/base.en # or an outright path ``` A model name that matches a directory under `BANDSAUNTER_MODEL_DIR` is used from disk; anything else is left to the recogniser to download. ### A smaller alternative `vosk` is a tenth of the size and much weaker on the noisy, clipped audio radio produces. It is worth it on a Raspberry Pi and not otherwise: ```bash pip install vosk # ~10 MB bandsaunter config transcribe_engine=vosk ``` It fetches its own small model on first use, by language; point `transcribe_model` at an unpacked model directory to use a specific one. --- ## When it does not work **`externally-managed-environment` from pip.** Use a virtual environment or pipx, as above. This is the distribution protecting its own Python, not a problem with bandsaunter. **`bandsaunter transcribe --engines` says `no` although pip installed it.** The recogniser went into a different environment from bandsaunter. Ask each of them where it is and compare: ```bash python3 -c "import bandsaunter, sys; print(sys.executable); print(bandsaunter.__file__)" python3 -c "import faster_whisper; print(faster_whisper.__file__)" ``` Install the recogniser with the same `pip` that owns the first path — the venv's `pip` for a venv install, `pip install --user --break-system-packages` for a `~/.local` one. On a `.deb` install, bandsaunter runs as the system `python3` and looks in `/usr/lib/bandsaunter/vendor` as well, which is what the `bandsaunter-transcribe` package fills. **The first transcription takes a minute and prints nothing.** It is downloading the model. `BANDSAUNTER_ENGINE_OUTPUT=1` shows the progress, and Step 3 above fetches it deliberately instead. **`librtlsdr was not found`.** Install it: `librtlsdr0` on Debian/Ubuntu, `rtl-sdr` on Fedora and Arch, `brew install librtlsdr` on macOS. Everything that does not touch the receiver keeps working without it. **`bandsaunter devices` finds nothing, or cannot open the dongle.** Almost always the DVB-T driver, which claims these dongles the moment they are plugged in: ```bash echo 'blacklist dvb_usb_rtl28xxu' | sudo tee /etc/modprobe.d/blacklist-rtl.conf sudo rmmod dvb_usb_rtl28xxu ``` Then unplug and replug the receiver. The `.deb` does this for you. **Permission denied opening the device.** On Debian and Ubuntu the `librtlsdr0` package installs the udev rule that grants access, so this is rare; if you built librtlsdr yourself, you need the rule from its source tree in `/etc/udev/rules.d`, then `sudo udevadm control --reload` and a replug. **Nothing is recorded.** That is usually correct behaviour rather than a fault: captures are kept only when they carry voice, decodable CW or an identified digital scheme. `bandsaunter scan -b 2m --simulate` proves the whole path end to end without an aerial. --- ## Running the tests ```bash pip install pytest pyte python3 -m pytest tests/ -q ``` About 1500 tests and around fifteen minutes; they need no hardware and no network. --- ## Licence GNU General Public License, version 3 or later. The full text is in [LICENSE](LICENSE), and in an installed package at `/usr/share/doc/bandsaunter/copyright`.