Multi-modal MF (multi-frequency) "bluebox" tone generator with CLI, TUI, and an installable, offline-capable web app (PWA). Built for PhreakMe CTF / ProjectMF lab prep.
⚠️ Authorized lab use only. SoftBlue generates the 2600 Hz seize tone and Bell System R1 MF tones used by the ProjectMF / PhreakMe hobbyist Asterisk environment, which emulates legacy phone switching. These tones have no effect on modern public telephone networks. Use only against systems you are authorized to test (your own ProjectMF lab / a CTF environment). The web server has no authentication — only bind it to a non-local interface (--host 0.0.0.0) deliberately on an isolated network.
pip install -e ".[all]" # everything
pip install -e ".[audio]" # CLI + live playback
pip install -e . # CLI + WAV export onlysoftblue generate 8675309 -o call.wav # write a WAV
softblue play 1234 --seize 3 --wink 1.0 # live playback (short or long flags)
softblue verify call.wav # FFT-analyse a WAV
softblue devices # list audio devices
softblue preset list # built-in + saved presets
softblue tui # interactive terminal UI
softblue web --open # browser interfaceLong and short timing flags are interchangeable everywhere:
--seize-duration/--seize, --wink-delay/--wink, --digit-duration/--digit,
--inter-digit-gap/--gap, --kp-duration/--kp, --st-duration/--st.
--seize-only emits just the 2600 Hz trunk-seize tone (no KP/digits/ST).
softblue web serves the browser UI, but the front-end is fully client-side:
every tone (MF/R1, CCITT #5, DTMF, US/UK red box, 3-slot bell, green box, 2600 sweep) is
synthesized in-browser with the Web Audio API. The Python server is optional
— it only adds server-side audio output and shared preset/macro storage. Presets
and macros live in localStorage, so the app is fully functional with no
backend at all.
The front-end is a PWA, so you can install it to a home screen and run it in airplane mode:
- Host the static folder
softblue/static/over HTTPS — this is required, iOS only registers a service worker on a secure origin (a plainhttp://LAN address will not cache offline). All asset paths are relative, so a sub-path deploy (user.github.io/softblue/) works. No build step — the folder is the app.- GitHub Pages (included): the
Deploy PWA to GitHub Pagesworkflow publishessoftblue/static/on every push. One-time setup: repo Settings → Pages → Source: GitHub Actions. URL:https://<user>.github.io/<repo>/. - Or drag the folder onto Netlify Drop / connect Cloudflare Pages.
- GitHub Pages (included): the
- Open the HTTPS URL in Safari (iOS) or Chrome (Android) → Add to Home Screen.
- Launch it once from the home screen while online so the service worker caches everything; afterward it runs fullscreen and offline.
iOS note: WebKit purges a PWA's cache after ~7 days of non-use. Open the app at least once a week to keep it primed for offline launches. For eviction-proof permanent offline, wrap
softblue/static/in a native shell (e.g. Capacitor) and sideload with an Apple Developer account.
The service worker (sw.js) version-stamps its cache
and fetches with cache: "reload" on install. When you change a static asset,
bump CACHE in sw.js and the ?v= query on the style.css / *.js
references in index.html so clients pick it up.
A toggle in the header switches between the default Modern dark UI and a
1972 Blue Box skin — brushed blue anodized panel, silver pushbuttons, amber
KP/ST keys, and a red LED readout. The choice persists in localStorage and is
applied before first paint (no flash).
Optional ~/.softblue/config.yaml (see docs/usage.md). Set
$SOFTBLUE_HOME to relocate config + presets (used by the test suite).
engine.py— numpy tone synthesis, sequence builder, WAV I/Oaudio.py— sounddevice / aplay / paplay outputpresets.py— JSON preset store (name-sanitised)verify.py— numpy-FFT frequency verificationcli.py/tui.py/web.py— the three front-endsstatic/— the PWA: client-side tone engine (tone-engine.js), UI (app.js,style.css), service worker (sw.js), and web app manifest
pip install -e ".[dev]" && pytest