<div class="wrapper">
  <ul class='dtmf-interface js-dtmf-interface'>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>*</li>
    <li>0</li>
    <li>#</li>
  </ul>
</div>
@import url(https://fonts.googleapis.com/css?family=Karla:400);

body{
  background: #f8f8f8;
  font-family:Karla, sans-serif;
}

.wrapper{
	width:250px;
	height:310px;
	position:absolute;
	left:50%;
	top:50%;
	margin:-155px 0 0 -125px;
  text-align:center;
}


.dtmf-interface{
  width:250px;
  margin:0;
  padding:0;
  overflow:hidden;
}

.dtmf-interface li{
  float:left;
  margin:10px;
  list-style:none;
  width:30px;
  height:30px;
  text-align:center;
  line-height:30px;
  font-size: 24px;
  border: solid 1px #333;
  border-radius:3px;
  padding:15px;
  transition: all 0.5s;
}

.dtmf-interface li:hover{
  color: #3CD9FD;
  border-color:#3CD9FD;
  transition-duration:0s;
  cursor:pointer;
}

.dtmf-interface li:active{
  color: #F60;
  border-color:#F60;
  transition-duration:0s;
}
// polyfill
var AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;

function Tone(context, freq1, freq2) {
	this.context = context;
	this.status = 0;
	this.freq1 = freq1;
	this.freq2 = freq2;
}

Tone.prototype.setup = function(){
	this.osc1 = context.createOscillator();
	this.osc2 = context.createOscillator();
	this.osc1.frequency.value = this.freq1;
	this.osc2.frequency.value = this.freq2;

	this.gainNode = this.context.createGain();
	this.gainNode.gain.value = 0.25;

	this.filter = this.context.createBiquadFilter();
	this.filter.type = "lowpass";
	this.filter.frequency = 8000;

	this.osc1.connect(this.gainNode);
	this.osc2.connect(this.gainNode);

	this.gainNode.connect(this.filter);
	this.filter.connect(context.destination);
}

Tone.prototype.start = function(){
	this.setup();
	this.osc1.start(0);
	this.osc2.start(0);
	this.status = 1;
}

Tone.prototype.stop = function(){
	this.osc1.stop(0);
	this.osc2.stop(0);
	this.status = 0;
}

var dtmfFrequencies = {
	"1": {f1: 697, f2: 1209},
	"2": {f1: 697, f2: 1336},
	"3": {f1: 697, f2: 1477},
	"4": {f1: 770, f2: 1209},
	"5": {f1: 770, f2: 1336},
	"6": {f1: 770, f2: 1477},
	"7": {f1: 852, f2: 1209},
	"8": {f1: 852, f2: 1336},
	"9": {f1: 852, f2: 1477},
	"*": {f1: 941, f2: 1209},
	"0": {f1: 941, f2: 1336},
	"#": {f1: 941, f2: 1477}
}

var context = new AudioContext();

// Create a new Tone instace. (We've initialised it with 
// frequencies of 350 and 440 but it doesn't really matter
// what we choose because we will be changing them in the 
// function below)
var dtmf = new Tone(context, 350, 440);

$(".js-dtmf-interface li").on("mousedown touchstart", function(e){
	e.preventDefault();

	var keyPressed = $(this).html(); // this gets the number/character that was pressed
	var frequencyPair = dtmfFrequencies[keyPressed]; // this looks up which frequency pair we need

	// this sets the freq1 and freq2 properties
	dtmf.freq1 = frequencyPair.f1;
	dtmf.freq2 = frequencyPair.f2;

	if (dtmf.status == 0){
		dtmf.start();
	}
});

// we detect the mouseup event on the window tag as opposed to the li
// tag because otherwise if we release the mouse when not over a button,
// the tone will remain playing
$(window).on("mouseup touchend", function(){
	if (typeof dtmf !== "undefined" && dtmf.status){
	  	dtmf.stop();
	}
});

Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js