DTMF Tone Detection & Generation

Dual-Tone Multi-Frequency (DTMF) is the signalling system used by touch-tone telephones. Each keypad button is encoded as a pair of sinusoids — one from a low-frequency “row” group and one from a high-frequency “column” group:

1209 Hz

1336 Hz

1477 Hz

1633 Hz

697 Hz

1

2

3

A

770 Hz

4

5

6

B

852 Hz

7

8

9

C

941 Hz

*

0

#

D

The frequencies were chosen to avoid harmonic relationships, preventing false detections from speech.

Timing standards

ITU-T Q.24 specifies:

  • Minimum tone duration: 40 ms

  • Minimum inter-digit pause: 40 ms

Practical systems typically use 70–120 ms for both.

Generating tones

import pyminidsp as md

# Generate "5551234" at 8 kHz with 70 ms tones and pauses
sig = md.dtmf_generate("5551234", sample_rate=8000.0, tone_ms=70, pause_ms=70)

Each digit is rendered as the sum of its row and column sinusoids at amplitude 0.5 (peak combined amplitude = 1.0).

Detecting tones

tones = md.dtmf_detect(sig, sample_rate=8000.0)
for digit, start_s, end_s in tones:
    print(f"{digit}  {start_s:.3f}{end_s:.3f} s")

Detection uses a sliding Hanning-windowed FFT with a state machine that enforces ITU-T Q.24 minimum timing. The FFT size is the largest power of two fitting within 35 ms (e.g. 256 at 8 kHz, giving 31.25 Hz resolution).

Round-trip verification

digits = "5551234"
sig = md.dtmf_generate(digits, sample_rate=8000.0)
detected = md.dtmf_detect(sig, sample_rate=8000.0)
result = "".join(t[0] for t in detected)
assert result == digits

md.shutdown()