Under the transcript, headed DETECTED CALLSIGNS:, every callsign heard in
it with the name and location on its licence.
Finding them is not one regular expression over the text as written. A
speech recogniser is poor at callsigns -- they are not words, they are
said one character at a time -- so it breaks them wherever the speaker
paused and writes the phonetic alphabet down verbatim. The recording that
prompted this has "Alright, KU 0W" in it, with a space; spelled out it
would have been "kilo uniform zero whiskey". All three forms read back to
KU0W.
Not inventing them matters more. A run of words is accepted only when
none of its parts is an ordinary English word: "or 3. Can you open 4" and
"CC1 boy", both from real transcripts here, fit the shape once the
punctuation is gone and are not callsigns. A single token said in one
breath is still trusted, because W1BOY is a perfectly good callsign, and a
lone "a" or "i" cannot start a join or "a B4U player" becomes AB4U.
Across the 126 transcripts in the recordings directory that turns three
candidates into the one that was actually said.
Lookups use the FCC's own licence data at callook.info -- no account, no
key, the callsign the only thing sent. They never delay the display: the
entry reads "looking up" and fills itself in, and results are cached under
~/.cache so a net recorded night after night is looked up once.
--no-lookup contacts nothing and still describes a callsign from its own
structure, the ITU prefix giving the country and the digit the US
district, which is also all there is to say for callsigns outside the US.
--callsigns prints everyone who identified themselves and where they were
heard.
Also asked: are transcripts appended to, or overwritten, when another
transmission arrives on the same frequency? Neither could be shown from
reading the code alone, so there are now three tests that run real scans
and look at the files. By default each transmission has a transcript of
its own -- the timestamp is in the name, so two overs cannot land on one
file. With --combine there is one recording per frequency and therefore
one transcript, opened for append with the time of each over; a second
scan into the same directory adds to it rather than starting it over,
which is the case the last of the three tests covers.
The browser and callsign tests refuse to reach the network at all. One
test did, quietly, and passed -- visible only because the assertion it
failed printed a real operator's address.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
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