Generating DTMF with SoX

Generating DTMF with SoX

In this post I’ll show how SoX can generate DTMF, (Dual-tone multi-frequency signaling) which is commonly used in phone and security systems. These dual tone signals are the foundation from which digital communications are based. The technology around DTMF is not complex. Lets cover the history of DTMF.

DTMF was developed by Bell Labs and put in production in the early 1960’s. It was mostly used to replace pulse dialing systems that had limits on how far a phone could be from the switch at the phone company. Pulse dialing systems created open circuit conditions at set intervals from the phone. These pulses would need to be registered on the switch at the phone company. It was the electrical characteristics of this method that imposed the limits. DTMF does not have these limits since they were acoustic by nature. In addition, DTMF links could be coupled using acoustic devices already available. There are 16 possible tone combinations with DTMF, which means it can transmit hexadecimal information, or 4 bits of data, versus 1 bi with pulse data. This technology led to the development of the modem.

Now back to SoX. We can generate several types of signal with SoX. In previous posts I had covered noise generation. SoX can also produce sine, square, sawtooth, triangle, and other signals at set frequencies and durations. In this example we’ll play a generated dial tone for a duration of 10 seconds.

play -n synth 10 sin 350 sin 440 remix - # North American Dial Tone

The command above generates two sine waves (350 Hz and 440 Hz) for the set duration of 10 seconds then combines them into a single mono channel.

In this example, we’ll creat the tone used to indicate a ring tone.

play -n synth 2 sin 440 sin 480 remix - # North American Ring Tone

It’s important to note that the ring tone spec has a gap of silence between each signal. To mimic this behavior we’ll use a script that loops through the signal generation and silence gap for a number of 10 times. Here is the code for that script.

==== Script - RingTone.py

import os

count = 0

# The values in range(x,y,z) are x=start, y=end, z=step
for N in range(1,10,1):
count = count + 1
os.system("play -n synth 2 sin 440 sin 480 remix - # North American Ring Tone")
os.system("play -n trim 0.0 3.0 remix - # North American Ring Tone Gap")

==== EoC

Another type of signal used to inform a caller when a line is busy, is called a busy signal. These are two sine waves of 480 and 620 hertz that have a duration of 500ms separated by an equal amount of silence. To create a busy signal, use this script.

==== Script - BusySignal.py

import os

count = 0

# The values in range(x,y,z) are x=start, y=end, z=step
for N in range(1,50,1):
count = count + 1
os.system("play -n synth 0.5 sin 480 sin 620 remix - # North American Busy Signal")
os.system("play -n trim 0.0 0.5 remix - # North American Busy Signal Gap")

==== EoC

Before I delve into DTMF signals I want to cover one more signal used to alert a phone owner know that the line is off the hook. The off hook signal is designed to get attention and used 4 sine waves at 1400, 2060, 2450, and 2600 hertz. The tones have a short duration of 100ms separated by an equal mount of silence. Use this script to create an off hook signal.

==== Script - OffHook.py

import os

count = 0

# The values in range(x,y,z) are x=start, y=end, z=step
for N in range(1,50,1):
count = count + 1
os.system("play -n synth 0.1 sin 1400 sin 2060 sin 2450 sin 2600 remix - # North American Off Hook Signal")
os.system("play -n trim 0.0 0.1 remix - # North American Off Hook Signal Gap")

==== EoC

Now, back to DTMF signals and how to create them with SoX. As I mentioned earlier there are 16 possible combinations of DTMF signals that represent numbers, letters, and characters. Here is a list of the sine waves and characters they correspond with.

697 1209 - 1
697 1336 - 2
697 1477 - 3
697 1633 - A
770 1209 - 4
770 1336 - 5
770 1477 - 6
770 1633 - B
852 1209 - 7
852 1336 - 8
852 1477 - 9
852 1633 - C
941 1209 - *
941 1336 - 0
941 1477 - #
941 1633 - D

Here is a script that dials through the entire range of DTMF signals with short pauses between each.

==== Script - KeyPress.py

import os

count = 0
# The values in range(x,y,z) are x=start, y=end, z=step

pause = "play -n trim 0.0 0.1 remix - # North American Off Hook Signal Gap"

for N in range(1,2,1):
count = count + 1
os.system("play -n synth 0.1 sin 697 sin 1209 remix - # Keypad 1 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 697 sin 1336 remix - # Keypad 2 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 697 sin 1477 remix - # Keypad 3 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 697 sin 1633 remix - # Keypad A Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 770 sin 1209 remix - # Keypad 4 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 770 sin 1336 remix - # Keypad 5 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 770 sin 1477 remix - # Keypad 6 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 770 sin 1633 remix - # Keypad B Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 852 sin 1209 remix - # Keypad 7 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 852 sin 1336 remix - # Keypad 8 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 852 sin 1477 remix - # Keypad 9 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 852 sin 1633 remix - # Keypad C Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 941 sin 1209 remix - # Keypad * Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 941 sin 1336 remix - # Keypad 0 Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 941 sin 1477 remix - # Keypad # Signal")
os.system(pause)
os.system("play -n synth 0.1 sin 941 sin 1633 remix - # Keypad D Signal")
os.system(pause)

==== EoC

The process using SoX has been cleaned up thanks to the efforts Thomas Sailer and the use of the multimon gen command. Multimon’s gen leverages SoX to do a keypad entry. You may need to install it if the command gen isn’t recognoized. Use this to do that.

sudo apt-get install multimon

Once installed, the command can be used to create audio files that contain the key press tones in the sequence entered. Here is the command.

gen -t wav -d 123A456B789C*0#D /home/local/Desktop/DTMF/KeyPress.wav

Multimon can do more than just generate DTMF. A fork called multimon-ng is a next generation of the project that can also decode DTMF and display the key press value on screen. You can find more information about multimon-ng here, https://github.com/EliasOenal/multimon-ng/. I won’t cover multimon or multimon-ng in greater detail here, perhaps another time.

DTMF signal generation with SoX takes some work, but hopefully this has been a good introduction on the topic. The DTMF codes are still in use today. The audible tones used in DTMF were used in first generation modem. These modems took advantage of circuitry that could modulate and demodulate the signal to pack more bits in per second. DTMF really was the first widespread digital method that preceded the Internet and its legacy remains.

 

Comments are closed.