Add saunterbrowse, for reading back what a scan collected

A long scan leaves hundreds of recordings, each with a JSON sidecar of
measurements and, where a recogniser heard speech, a transcript.  Reading
that meant opening files one at a time and guessing which were worth
playing.

saunterbrowse is a second executable in the same package.  Arrow keys move
through the recordings; the transcript of whichever is highlighted fills
the top of the screen, because that is the part anyone actually wants to
read.  Enter plays it, handing the file to whichever player is installed
-- the recordings are ordinary WAVs, every desktop already has something
that plays them, and a browser that cannot start would be worse than one
that cannot play.  t opens the whole transcript full screen when it is
longer than the panel, and says so rather than cutting the end off
silently.  / filters on the frequency, the name, the identification, or
anything that was said, which is the point of it: "was the repeater
mentioned" is a question about content.

Sidecars are read only for the rows on screen, so a directory of ten
thousand recordings opens instantly.  Where there is no transcript the
panel says which of the reasons applies -- Morse (decoded, and shown),
data, a bare carrier, or speech never offered to a recogniser -- because
those want different things done about them.  It only ever reads.

Two things were only found by driving it through a real terminal.
sys.stdin.read(1) goes through a buffered text wrapper, which in cbreak
mode waits for more bytes than one keypress provides: the program drew its
first frame and then hung, while tests against a stand-in stream object
passed.  It reads the file descriptor now, and the tests drive a pty.  And
stopping playback signalled only the direct child, so a player that is a
wrapper script kept the sound going with nothing on screen to stop it; the
whole process group is signalled instead, which is what start_new_session
was there for.

man saunterbrowse ships beside man bandsaunter, and the two point at each
other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
This commit is contained in:
The Dust Council 2026-08-22 15:06:33 -07:00
parent 4a272eb1d5
commit cc317914e1
11 changed files with 2233 additions and 5 deletions

View file

@ -7,6 +7,10 @@ built-in US band plan — and it sweeps them, stops on anything above the noise
floor, records it, and works out what kind of signal it was. CW/Morse is
decoded to text.
Two programs: `bandsaunter` scans, and
[`saunterbrowse`](#browsing-what-you-recorded) reads back what it collected —
transcripts, identifications and playback, in one screen.
```
╭──────────────────────────────── receiver ────────────────────────────────╮
│ Rafael Micro R820T/R820T2 2.048 MS/s gain auto +0 ppm │
@ -931,6 +935,81 @@ and `--simulate` is looking at an invented band, whose frequencies would sit in
a real settings file for ever, skipping whatever genuine signal happened to
land near one. Both still lock out for the run in hand, and say so.
## Browsing what you recorded
A long scan leaves hundreds of files. `saunterbrowse` is a second program in
the same package for reading them:
```bash
saunterbrowse # opens the scanner's output directory
saunterbrowse /mnt/recordings # or any other
```
Arrow keys move through the recordings; the transcript of whichever one is
highlighted fills the top of the screen, because that is the part you actually
want to read. Under it are the identification, the confidence, the CTCSS tone
or symbol rate where there is one, and the bands the frequency falls in.
```
╭──────────────────────────────────────────────────────────── 4 of 126 ─╮
│ 146.88 MHz NFM Sat 22 Aug 13:01:44 42.8s SNR 17.6 dB voice │
╰───────────────────────────────────────────────────────────────────────╯
╭─ transcript ──────────────────────────────────────────────────────────╮
│ │
│ Alright, moving on. It is the 4th Saturday of the month. There is │
│ an HF net at 1.30pm on 7.242 megahertz. Are there any │
│ announcements for the net? │
│ │
╰───────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────╮
│ Narrowband FM voice (CTCSS 110.9 Hz) 88% CTCSS 110.9 Hz │
│ 2 m Amateur · 2 m FM Simplex · 2 m Repeater Outputs │
╰───────────────────────────────────────────────────────────────────────╯
╭─ recordings in /mnt/global/bandsaunter ───────────────────────────────╮
│ 856.561096 MHz 13:10:25 fsk 4m00s Motorola SMARTNET / Smart… │
│ 158.294200 MHz 13:05:15 nfm 20.1s Steven, I'm over to Colvi… │
146.88 MHz 13:01:44 nfm 42.8s Alright, moving on. It is… │
│ 146.88 MHz 13:00:44 nfm 35.2s Check out communication o… │
╰───────────────────────────────────────────────────────────────────────╯
↑↓ move ⏎ play space stop / search t read s sort ? keys q
```
| Key | What it does |
|---|---|
| `↑` `↓` `k` `j` | move through the recordings |
| `PgUp` `PgDn` `Home` `End` | a screenful, or straight to either end |
| `Enter` | play the highlighted recording |
| `space` | stop playing |
| `t` | read the whole transcript full screen, scrolling |
| `/` | filter — by frequency, filename, identification, **or anything that was said** |
| `s` | sort by time, frequency or length |
| `r` | re-read the directory, picking up what a running scan has written |
| `o` | print the file's path and quit |
| `q` | quit |
Searching the transcripts is the point of it: *"did anyone mention the
repeater"* is a question about content, not about filenames.
```bash
saunterbrowse --list | grep -i "mile marker" # or ask it from a script
saunterbrowse --sort frequency # group by channel, not by time
```
Playback is handed to whichever player is installed — `pw-play`, `paplay`,
`aplay`, `sox` or `ffplay`, in that order, or whatever `--player` names. The
recordings are ordinary WAVs and every desktop already has something that
plays them; a browser that cannot start would be worse than one that cannot
play. Over ssh, where there is usually no sound server at the far end, the
transcripts still work and only `Enter` has nothing to do.
Where a recording has no transcript the panel says which of the reasons
applies — Morse (decoded, and shown), data, a bare carrier, or speech that was
never offered to a recogniser — because those want different things done about
them.
It only ever reads. Nothing in the recordings directory is renamed, moved or
deleted.
## Built-in help
Press `h` in the menus for topics covering setup, how the sweep works, why
@ -945,14 +1024,16 @@ and `bandsaunter scan --help` lists every flag grouped the same way as the menus
`man bandsaunter` documents every command, option and setting, each with a
plain-language note on what it is and why you would turn it up, down, on or
off — written for someone who does not already speak radio.
off — written for someone who does not already speak radio. `man
saunterbrowse` does the same for the browser.
It is generated from the same settings table the menus and the flags come from,
so it cannot describe a setting the program does not have, or miss one it does:
```bash
./packaging/make-man.py # regenerate packaging/bandsaunter.1
man -l packaging/bandsaunter.1 # read it without installing
./packaging/make-man.py # regenerate packaging/bandsaunter.1
./packaging/make-browse-man.py # and packaging/saunterbrowse.1
man -l packaging/bandsaunter.1 # read either without installing
```
The `.deb` installs it; installing from source does not, so read it from the