Commit graph

4 commits

Author SHA1 Message Date
The Dust Council
af51b2657d Make the simulator reproducible and widen the burst tests
A transmitter seeded itself from the builtin hash() of its label, and that
is salted per interpreter, so every run produced different synthetic
speech and keying. A test that failed could not be made to fail again --
the one thing needed to fix it. crc32 gives the same content every run.

The hang test then compounded it by listening for a 1 s burst in a 6 s
cycle over three sweeps: it is the release after the transmission that is
under test, but a missed burst failed it just the same, with "nothing
recorded". Now 2 s in 5 s over six sweeps, so only the ending can fail it.

The neighbouring test had the opposite fault: asserting only that nothing
was truncated, it passed whether or not the burst was ever heard. It now
requires the recording it is drawing a conclusion from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 22:29:29 -07:00
The Dust Council
8d94a52942 Package the speech recogniser and its model for apt
No speech recogniser is in Debian, so installing bandsaunter from a .deb
left transcription to a manual pip step on every machine. A repository of
one's own is not bound by archive policy, so build-repo.sh now packages
faster-whisper and the base.en model alongside the application:

  bandsaunter                the application (Architecture: all)
  bandsaunter-transcribe     faster-whisper, vendored (amd64)
  bandsaunter-model-base-en  the model, so nothing reaches the network

The wheels land in /usr/lib/bandsaunter/vendor rather than dist-packages,
and transcribe.py appends that directory to sys.path -- appends, so an
apt-managed numpy or PyYAML still wins and the vendor copy only fills the
gap. Duplicates of what Debian already ships are stripped from the tree.
resolve_model() turns a bare "base.en" into the packaged copy when one is
installed, and leaves it alone to be downloaded when none is.

The app package recommends the other two, so "apt install bandsaunter"
brings the lot and --no-install-recommends still gets just the scanner.
Its postinst explains how to add a recogniser only when there genuinely
is not one -- including the case where apt has already unpacked the
recogniser package but not yet configured it.

Verified with the source tree hidden and no home directory: the packaged
CLI runs, and a real recording transcribes offline from the vendored
engine and packaged model while numpy still resolves to the system one.
apt itself resolves the repository over HTTP and plans all three.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 22:12:24 -07:00
The Dust Council
52fe16123f 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>
2026-08-21 21:05:51 -07:00
The Dust Council
db3e0c79b9 Initial commit: bandsaunter, an RTL-SDR signal scanner
Sweeps any set of frequency ranges, records what it finds, and works out
what kind of signal it was.

- Frequency ranges entered by hand or picked from a 135-entry US band plan,
  including whole-band and all-CW sweeps that resolve the demodulator per
  segment.
- Detection calibrated against the peak-hold detector's own noise statistics,
  so the threshold means real margin over static rather than over the floor.
- A content gate: captures are kept only if they carry voice, decodable CW,
  or an identified digital keying scheme. Speech is recognised by a pitch
  track that drifts, which static cannot imitate.
- Identification of NFM/WFM/AM/SSB, CW with Morse decoded to text, P25, DMR,
  NXDN, D-STAR, POCSAG, FLEX, ACARS, AIS, APRS, n-FSK and n-PSK.
- Gapless streaming capture, with the signal path fast enough to keep up in
  real time, so recordings play back at the right speed.
- Optional one-file-per-frequency recording with spoken timestamps, and
  speech-to-text transcription.
- Menus and command line generated from one settings table, so neither can
  offer something the other cannot; settings persist in ~/.config.

367 tests, run against synthetic signals, a built-in receiver simulator, and
real hardware.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 20:50:20 -07:00