DTMF Decoder

A Java library for detecting and generating telephone keypad tones in recorded or streaming audio.

DTMF Decoder is a Java library for finding the tones produced by telephone keypads. It can decode a complete recording, process audio as it arrives, or generate a valid sequence of tones for testing another system.

The project began in 2015 as a small decoder. I returned to it years later and rebuilt it as a Java 17 library with a clearer API, a streaming architecture and a much stronger definition of correctness.

What is DTMF?

DTMF stands for dual-tone multi-frequency signalling. Pressing a key on a telephone does not produce one note: it plays two frequencies at the same time. One comes from the key’s row and one from its column.

1209 Hz1336 Hz1477 Hz1633 Hz
697 Hz123A
770 Hz456B
852 Hz789C
941 Hz*0#D

Those pairs let a receiver distinguish sixteen possible keys reliably over a voice channel. The familiar digits, star and hash are joined by A-D, a fourth column originally used in specialist telephone systems.

DTMF is still useful anywhere software needs to recognise keypad input in audio: interactive voice-response systems, call recordings, test equipment, radio control and telecommunications tooling.

Why a Goertzel detector?

A general Fourier transform can describe all the frequencies in a signal, but a DTMF decoder is interested in only eight of them. The library therefore uses a bank of eight Goertzel filters, each tuned to one DTMF frequency.

That focused approach avoids calculating a complete frequency spectrum that the decoder will immediately discard. It also lets the analysis window be sized around the frequency resolution the detector needs instead of forcing it to a power of two.

For every block of audio, the detector finds the strongest low-group and high-group frequencies, checks that their energy and balance meet the configured thresholds, and feeds the result into a state machine. A tone is reported only after it has remained valid for long enough; brief interruptions can be absorbed without splitting one key press into two.

One pipeline, three ways to use it

Batch and streaming detection share the same internal analysis pipeline. That means decoding a buffer in one call or sending the same samples in arbitrary chunks produces the same sequence and timing.

The public API supports:

  • batch decoding from double, float, short, integer and 24-bit PCM samples;
  • push-based streaming with a callback when a tone is confirmed;
  • pull-based streaming through an iterator;
  • mono, independent stereo and stereo-to-mono processing;
  • WAV and MP3 input through separate file-I/O modules; and
  • generation of valid DTMF sequences for tests and other applications.

Preset configurations cover telephone, VoIP and noisy audio, while an advanced builder exposes sample rate, window function, twist tolerances, timing and confirmation settings.

Designing for evidence, not just a demo

Signal-processing code can look convincing while failing on timing boundaries, noise or a different input format. The project treats those behaviours as an explicit contract.

Its property-based tests check invariants such as generator-to-decoder round-trips, chunk independence, stereo behaviour, sample conversion and timing accuracy. Integration tests exercise a larger tone corpus at multiple sample rates, sixty seconds of silence and noise false-positive limits. JMH benchmarks compare the Goertzel implementation with an FFT-based reference.

The library follows the frequency and signalling tolerances described by ITU-T Q.23 and Q.24. The core and Goertzel modules have no runtime dependency beyond Java itself; optional MP3 support is kept in a separate module.

Version 2.1.0 is available as source under the MIT licence. A command-line interface, graphical app, microphone capture and Maven Central publication are deliberately outside the current release rather than half-supported features.