A Python library for extracting scanner radio tones from scanner audio.
Project description
icad_tone_detection
A Python library for extracting scanner radio tones from scanner audio. This includes Two-Tone (Quick Call), Long Tones, Hi-Low “warble” tones, MDC1200/FleetSync, and DTMF signals. The library uses STFT-based frequency extraction as well as an included external decoder binary (icad_decode) to process advanced signals like MDC1200 and DTMF.
Features
- Easy-to-use main function
tone_detectfor detecting:- Two-Tone / Quick Call tones
- Long tones
- Hi-Low / warble tones
- MDC1200 / FleetSync
- DTMF
- Flexible audio input: Local file paths, URLs, raw byte data,
io.BytesIO, or existingpydub.AudioSegment. - Automatic resampling to PCM 16bit @16 kHz mono for consistent detection.
- Cross-platform included binaries for MDC/DTMF decoding:
- Windows (x86_64)
- Linux (x86_64, ARM64)
- macOS (ARM64)
- Configurable detection thresholds and parameters.
Installation
pip install icad_tone_detection
Requirements
- Python 3.10 or later.
- ffmpeg (must be installed and available on the system
PATH). - The following Python packages (automatically installed if not present):
numpy>=1.26.4requests>=2.31.0pydub>=0.25.1scipy>=1.12.0
Getting Started
Here is a quick example on how to use the tone_detect function:
from icad_tone_detection import tone_detect
# Point to an audio file (can be local .wav, .mp3, URL, or BytesIO, etc.)
audio_path = "my_scanner_recording.wav"
# Detect various tones
result = tone_detect(
audio_path=audio_path,
matching_threshold=2.5, # % difference threshold for grouping frequencies
time_resolution_ms=50, # STFT window hop in ms
tone_a_min_length=0.85, # Minimum A-tone length for Quick Call
tone_b_min_length=2.6, # Minimum B-tone length for Quick Call
hi_low_interval=0.2, # Maximum gap between warble tones
hi_low_min_alternations=6,# Minimum alternations for hi-low
long_tone_min_length=3.8, # Minimum length for long tone
detect_mdc=True, # Enable MDC1200/FleetSync detection
mdc_high_pass=200, # High-pass frequency for MDC decoding
mdc_low_pass=4000, # Low-pass frequency for MDC decoding
detect_dtmf=True, # Enable DTMF detection
debug=False # Print debug info
)
# Results are available in the ToneDetectionResult object:
print("Two-Tone/QuickCall:", result.two_tone_result)
print("Long Tones:", result.long_result)
print("Hi-Low/Warble Tones:", result.hi_low_result)
print("MDC1200/FleetSync:", result.mdc_result)
print("DTMF:", result.dtmf_result)
Inputs Supported
The tone_detect function can handle:
- String pointing to:
- A local file path (e.g.,
"audio.wav") - A URL (e.g.,
"https://example.com/audio.wav")
- A local file path (e.g.,
- Bytes or bytearray objects (raw audio data).
- File-like objects (
io.BytesIO, open file handle, etc.). pydub.AudioSegmentobjects.
If you pass a local file path or a URL, the library will attempt to read the audio file and then convert it to a standard 16 kHz mono WAV internally using ffmpeg. For raw byte data or file-like objects, it similarly uses ffmpeg to resample on the fly.
Function Reference
tone_detect(...)
def tone_detect(audio_path, matching_threshold=2.5, time_resolution_ms=50,
tone_a_min_length=0.85, tone_b_min_length=2.6,
hi_low_interval=0.2, hi_low_min_alternations=6,
long_tone_min_length=3.8, detect_mdc=True, mdc_high_pass=200,
mdc_low_pass=4000, detect_dtmf=True, debug=False):
"""
Loads audio from various sources including local path, URL, BytesIO object, or a PyDub AudioSegment.
Parameters:
audio_path: string or other supported input types
matching_threshold (float): ...
time_resolution_ms (int): ...
tone_a_min_length (float): ...
tone_b_min_length (float): ...
hi_low_interval (float): ...
hi_low_min_alternations (int): ...
long_tone_min_length (float): ...
detect_mdc (bool): ...
mdc_high_pass (int): ...
mdc_low_pass (int): ...
detect_dtmf (bool): ...
debug (bool): ...
Returns:
ToneDetectionResult with:
- two_tone_result
- long_result
- hi_low_result
- mdc_result
- dtmf_result
"""
pass
Parameters
- audio_path (various types):
The source of audio. Can be a string (path or URL), bytes,BytesIO, orAudioSegment. - matching_threshold (float):
The percentage threshold for grouping frequencies, e.g.2.5means frequencies within ±2.5% are considered matching.
Default: 2.5 - time_resolution_ms (int):
The time window hop (in ms) used by STFT. Smaller = finer resolution but heavier computation.
Default: 50 - tone_a_min_length (float):
Minimum length (seconds) of Tone A for Two-Tone detection.
Default: 0.85 - tone_b_min_length (float):
Minimum length (seconds) of Tone B for Two-Tone detection.
Default: 2.6 - hi_low_interval (float):
Maximum allowed gap (seconds) between consecutive alternating hi-low warble tones.
Default: 0.2 - hi_low_min_alternations (int):
Minimum number of alternations for a hi-low warble sequence.
Default: 6 - long_tone_min_length (float):
Minimum length (seconds) for a long tone detection.
Default: 3.8 - detect_mdc (bool):
Whether to attempt detecting MDC1200/FleetSync frames.
Default: True - mdc_high_pass (int):
Frequency (Hz) of the high-pass filter for MDC detection.
Default: 200 - mdc_low_pass (int):
Frequency (Hz) of the low-pass filter for MDC detection.
Default: 4000 - detect_dtmf (bool):
Whether to attempt detecting DTMF signals.
Default: True - debug (bool):
Enable debug info (prints STFT matches, config details, etc.).
Default: False
Returns
A ToneDetectionResult object with the fields:
two_tone_resultlong_resulthi_low_resultmdc_resultdtmf_result
Each field holds a list of detected tones or an empty list if none found.
Result Caveats
The result includes timestamps in the file where the tones were detected as start and end.
These may not align with the original audio due to internal conversions from your input to PCM 16bit @16kHz Mono. If
those timestamps are important make sure the input matches those requirements.
Command-Line Example
There is an example script called detect_test.py under the examples/ folder. Usage:
python examples/detect_test.py -p my_scanner_recording.wav \
--matching_threshold 2.5 \
--time_resolution_ms 25 \
--tone_a_min_length 0.7 \
--tone_b_min_length 2.7 \
--long_tone_min_length 3.8 \
--debug
This script prints out the detected tone data in JSON to stdout.
Example Audio Files
Under examples/example_audio, you can find sample WAV files demonstrating:
dtmf_example.wavhi_low_example.wavlong_tone_example.wavmdc_example.wavtwo_tone_example.wav
Use them to experiment with the library.
Platform Binaries
The icad_decode binary is automatically chosen depending on your OS/architecture:
linux_x86_64linux_arm64macos_arm64windows_x86_64
On non-Windows systems, the library will automatically chmod +x the binary when needed.
If your platform is not supported, you will see a RuntimeError. Currently, only the above architectures and operating systems are supported.
License
This project is licensed under the MIT License.
Contributing / Issues
Contributions, bug reports, and feature requests are welcome. Please open issues or submit pull requests on GitHub.
Links
- Homepage: GitHub Repository
- Issue Tracker: GitHub Issues
Author: TheGreatCodeholio
Version: 2.5
Python versions: 3.10+
License: MIT
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.6.tar.gz.
File metadata
- Download URL: icad_tone_detection-2.6.tar.gz
- Upload date:
- Size: 2.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deb90fa359c8e366c5c7b96939eba4dfa202d81779770968ae1f361cf0b318f6
|
|
| MD5 |
78836b288d097c5638ab0879eeb21297
|
|
| BLAKE2b-256 |
6db93f918b4d81d0927e4ce946cbbac7606581103ea9eb9737a0117f3fa66ab5
|
Provenance
The following attestation bundles were made for icad_tone_detection-2.6.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.6.tar.gz -
Subject digest:
deb90fa359c8e366c5c7b96939eba4dfa202d81779770968ae1f361cf0b318f6 - Sigstore transparency entry: 245459094
- Sigstore integration time:
-
Permalink:
TheGreatCodeholio/icad_tone_detection@cec3990619a1897cdfc219ddebcd892130b47a3d -
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@cec3990619a1897cdfc219ddebcd892130b47a3d -
Trigger Event:
push
-
Statement type:
File details
Details for the file icad_tone_detection-2.6-py3-none-any.whl.
File metadata
- Download URL: icad_tone_detection-2.6-py3-none-any.whl
- Upload date:
- Size: 2.3 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 |
f7dd229027e06a000f624b768943821163b6f607ba1a83d8dfd42c5c5f185888
|
|
| MD5 |
88c6d70e37b590e7b7201f578896a4e6
|
|
| BLAKE2b-256 |
8374aa32c4dcc000870f729255d48267522f595a73823a58cdea4cee581bfb76
|
Provenance
The following attestation bundles were made for icad_tone_detection-2.6-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.6-py3-none-any.whl -
Subject digest:
f7dd229027e06a000f624b768943821163b6f607ba1a83d8dfd42c5c5f185888 - Sigstore transparency entry: 245459095
- Sigstore integration time:
-
Permalink:
TheGreatCodeholio/icad_tone_detection@cec3990619a1897cdfc219ddebcd892130b47a3d -
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@cec3990619a1897cdfc219ddebcd892130b47a3d -
Trigger Event:
push
-
Statement type: