A Python library for extracting scanner radio tones from scanner audio.
Project description
icad_tone_detection
Detect Two-Tone (Quick Call), Pulsed Single-Tone (On/Off Beeps), Long Tones, Hi–Low warble tones, MDC1200 / FleetSync, and DTMF in scanner-audio recordings.
The heavy DSP is performed by a bundled native binary (icad_decode), while the Python wrapper handles audio I/O and STFT-based frequency extraction.
Features
- Single function:
tone_detect()or CLI toolicad-tone-detect - Tone types:
- Pulsed single-tone
- Two-Tone / Quick Call
- Long tones
- Hi–Low warble tones
- MDC1200 / FleetSync
- DTMF
- Flexible inputs: File path, URL,
bytes,BytesIO, orpydub.AudioSegment - Automatic resample to 16 kHz mono PCM via FFmpeg
- Fully configurable: All thresholds & detection params exposed as keyword args or CLI flags
- Binaries included for:
- Linux (
x86_64,arm64,armv7) - macOS (
x86_64,arm64) - Windows (
x86_64)
- Linux (
Installation
pip install icad_tone_detection
Requires: Python 3.9+ and
ffmpeginPATH.
Quick start — Python
from icad_tone_detection import tone_detect
result = tone_detect("my_scanner_recording.wav")
print(result.pulsed_result)
print(result.two_tone_result)
Quick start — CLI
# Show help
icad-tone-detect --help
# Analyze a file with MDC disabled
icad-tone-detect my.wav --detect_mdc false --debug
Boolean flags accepted: true/false, yes/no, or 1/0.
Full CLI example
icad-tone-detect my_scanner_recording.wav \
--detect_pulsed true \
--pulsed_center_hz 1010 --pulsed_bw_hz 25 \
--pulsed_min_cycles 6 \
--pulsed_min_on_ms 120 --pulsed_max_on_ms 900 \
--pulsed_min_off_ms 25 --pulsed_max_off_ms 350 \
--detect_two_tone true \
--tone_a_min_length 0.85 --tone_b_min_length 2.6 \
--detect_hi_low true --hi_low_interval 0.2 --hi_low_min_alternations 6 \
--detect_long true --long_tone_min_length 3.8 \
--detect_mdc false --detect_dtmf true \
--time_resolution_ms 50 --matching_threshold 2.5 \
--debug
Example output (debug mode)
############################################################
ICAD Tone Detection: DEBUG - v2.8.0
------------------------------------------------------------
Decode binary path: /…/bin/linux_arm64/icad_decode
Analyzing audio at: my_scanner_recording.wav
Matching Threshold: 2.5%
Time Resolution (ms): 50
… (trimmed) …
------------------------------------------------------------
DETECTION SUMMARY
------------------------------------------------------------
Two-Tone (Quick Call): 1
Long Tones: 0
Hi-Low Warble: 0
Pulsed Single Tone: 3
MDC1200/FleetSync: 0 (disabled)
DTMF: 2
------------------------------------------------------------
{
"pulsed": [
{
"tone_id": "pl_1",
"detected": 1010.1,
"start": 2.31, "end": 5.12, "length": 2.81,
"cycles": 8,
"on_ms_median": 180, "off_ms_median": 95
}
],
"two_tone": [
{
"tone_id": "qc_1",
"detected": [473.2, 810.0],
"tone_a_length": 0.90, "tone_b_length": 2.84,
"start": 6.23, "end": 9.07
}
],
"long_tone": [],
"hi_low": [],
"mdc": [],
"dtmf": [
{ "digit": "5", "start": 12.01, "end": 12.08 },
{ "digit": "9", "start": 12.35, "end": 12.42 }
]
}
Python API — tone_detect() signature
result = tone_detect(
audio_path="my.wav", # path / URL / BytesIO / AudioSegment
# STFT & grouping
matching_threshold=2.5, # % tolerance for grouping freqs
time_resolution_ms=50, # STFT hop size in ms
# Quick Call (two-tone)
tone_a_min_length=0.85, # sec – min A-tone
tone_b_min_length=2.6, # sec – min B-tone
# Hi/Low warble
hi_low_interval=0.2, # sec – max gap between hi/low groups
hi_low_min_alternations=6, # min alternations
# Long tone
long_tone_min_length=3.8, # sec – min duration
# Pulsed single-tone (~1 kHz)
pulsed_center_hz=None, # Hz – None=auto estimate (200–3000 Hz)
pulsed_bw_hz=25.0, # Hz ± deviation counted as ON
pulsed_min_cycles=6, # min ON→OFF cycles
pulsed_min_on_ms=120, # ms – ON min
pulsed_max_on_ms=900, # ms – ON max
pulsed_min_off_ms=25, # ms – OFF min
pulsed_max_off_ms=350, # ms – OFF max
# Detector toggles
detect_pulsed=True,
detect_two_tone=True,
detect_long=True,
detect_hi_low=True,
# External decoders
detect_mdc=True, # MDC1200 / FleetSync
mdc_high_pass=200, # Hz
mdc_low_pass=4000, # Hz
detect_dtmf=True,
debug=False
)
Result object
tone_detect() returns a ToneDetectionResult dataclass with:
pulsed_result— Pulsed single-tone hits:tone_id,detected,start,end,length,cycles,on_ms_median,off_ms_mediantwo_tone_result— Quick-Call matches:tone_id,detected[A,B],tone_a_length,tone_b_length,start,endlong_result— Long tone hits:tone_id,detected,length,start,endhi_low_result— Warble sequences:tone_id,detected[low,high],alternations,length,start,endmdc_result— Decoded frames from external MDC/FleetSync decoder (if enabled)dtmf_result— Decoded DTMF presses (if enabled)
Platforms & binaries
| OS | Architectures | Wheel folder name |
|---|---|---|
| Linux | x86_64, arm64, armv7 | linux_x86_64, linux_arm64, linux_armv7 |
| macOS | x86_64, arm64 | macos_x86_64, macos_arm64 |
| Windows | x86_64 | windows_x86_64 |
Example audio
Sample WAV files are in examples/example_audio/.
Contributing
Issues and pull requests welcome: GitHub repo
License
MIT © TheGreatCodeholio • Version 2.8.2 • Python 3.9+
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file icad_tone_detection-2.8.2.tar.gz.
File metadata
- Download URL: icad_tone_detection-2.8.2.tar.gz
- Upload date:
- Size: 2.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7efc7d050be7b13a2cd25a9ee7983bb9f5206d9b0a355e20a16b0b6a2355035c
|
|
| MD5 |
ad2177929264ca64365363322bf46ba0
|
|
| BLAKE2b-256 |
0ea54c9392bb72277091d53540488b27417e68ad3c768ede38b7d2cd1857c813
|
Provenance
The following attestation bundles were made for icad_tone_detection-2.8.2.tar.gz:
Publisher:
python-package.yml on TheGreatCodeholio/icad_tone_detection
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icad_tone_detection-2.8.2.tar.gz -
Subject digest:
7efc7d050be7b13a2cd25a9ee7983bb9f5206d9b0a355e20a16b0b6a2355035c - Sigstore transparency entry: 374870390
- Sigstore integration time:
-
Permalink:
TheGreatCodeholio/icad_tone_detection@2ac074c8608337cf90cff82b4671118621daa883 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/TheGreatCodeholio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-package.yml@2ac074c8608337cf90cff82b4671118621daa883 -
Trigger Event:
push
-
Statement type:
File details
Details for the file icad_tone_detection-2.8.2-py3-none-any.whl.
File metadata
- Download URL: icad_tone_detection-2.8.2-py3-none-any.whl
- Upload date:
- Size: 2.9 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1ac578357b180011b3666b93b30b8f64069dd507f347e723325660e131a7040
|
|
| MD5 |
799f38ce4f2ba208fd80916b87f969e5
|
|
| BLAKE2b-256 |
9e5fe42884b5563e5e909fe83b2e99f4f8e5693a54cfff3d5b6efdca3825e2ec
|
Provenance
The following attestation bundles were made for icad_tone_detection-2.8.2-py3-none-any.whl:
Publisher:
python-package.yml on TheGreatCodeholio/icad_tone_detection
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icad_tone_detection-2.8.2-py3-none-any.whl -
Subject digest:
c1ac578357b180011b3666b93b30b8f64069dd507f347e723325660e131a7040 - Sigstore transparency entry: 374870414
- Sigstore integration time:
-
Permalink:
TheGreatCodeholio/icad_tone_detection@2ac074c8608337cf90cff82b4671118621daa883 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/TheGreatCodeholio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-package.yml@2ac074c8608337cf90cff82b4671118621daa883 -
Trigger Event:
push
-
Statement type: