/
VoRoN
/
HTML
Обзор
Документация
Войти
/
VoRoN
/
HTML
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
DTMF.html
329 строк
10 KB
Александр Владимирович
create DTMF.html
31 мар 2024, 19:51
31 мар 2024, 19:51
46cfa6d
Код
Авторство
О чём код?
<script> var dtmf = { play: false, ready: false, keys: {}, audio: null, dst: null, rec: null, data: [], tone0: null, tone1: null, sequence: null, time_on: -1, time_off: -1, space: -1, duration: -1, button_replay: null, button_restop: null, restop_flag: false, init: function () { dtmf.audio = new window.AudioContext(); dtmf.dst = dtmf.audio.createMediaStreamDestination(); dtmf.rec = new MediaRecorder(dtmf.dst.stream); dtmf.rec.ondataavailable = function(evt){dtmf.data.push(evt.data)}; dtmf.rec.onstop = function(evt) {document.getElementById('dtmf_record').title ="num_"+document.getElementById('dtmf_sequence').value+".ogg"; document.getElementById('dtmf_record').src = URL.createObjectURL(new Blob(dtmf.data, { 'type' : 'audio/ogg; codecs=opus' }))}; dtmf.ready = true; }, freqs: function (key) { let freqs = dtmf.keys[key]; if (freqs !== undefined) { return freqs; } return null; }, start: function (event = null, replay = null) { if (!dtmf.ready) { dtmf.init(); } if (dtmf.play) { return false; } dtmf.duration = parseInt(document.getElementById('dtmf_duration').value); dtmf.space = parseInt(document.getElementById('dtmf_space').value); let key = -1; if (replay !== null) { key = replay; } else if (event instanceof MouseEvent) { key = this.innerText.trim(); dtmf.sequence.value += "" + key; } else { key = event.key; } key = key.toUpperCase(); let tones = dtmf.freqs(key); if (tones === null) { return false; } dtmf.play = true; dtmf.tone0 = dtmf.audio.createOscillator(); dtmf.tone0.type = 'sine'; dtmf.tone0.frequency.setValueAtTime(tones[0], dtmf.audio.currentTime); dtmf.tone1 = dtmf.audio.createOscillator(); dtmf.tone1.type = 'sine'; dtmf.tone1.frequency.setValueAtTime(tones[1], dtmf.audio.currentTime); if (replay !== null) { dtmf.tone1.connect(dtmf.dst); dtmf.tone0.connect(dtmf.dst); } else { dtmf.tone0.connect(dtmf.audio.destination); dtmf.tone1.connect(dtmf.audio.destination); } dtmf.tone0.start(); dtmf.tone1.start(); dtmf.time_on = new Date().getTime(); return true; }, stop: function () { dtmf.time_off = new Date().getTime(); let ms = dtmf.time_off - dtmf.time_on; if (ms < dtmf.duration) { setTimeout(dtmf.stop, dtmf.duration + 1 - ms); return; } if (dtmf.tone0 !== null) { dtmf.tone0.stop(); dtmf.tone0 = null; } if (dtmf.tone1 !== null) { dtmf.tone1.stop(); dtmf.tone1 = null; } dtmf.play = false; }, restop: function () { dtmf.restop_flag = true; }, backspace: function () { dtmf.sequence.value = dtmf.sequence.value.substring(0, dtmf.sequence.value.length - 1); }, clear: function () { document.getElementById('dtmf_sequence').value = ''; }, replay: function (index = - 1, space = false) { if (index !== -1) { dtmf.stop(); } else { dtmf.button_replay.disabled = true; dtmf.keyboard(false); dtmf.button_restop.disabled = false; dtmf.data = []; dtmf.rec.start(); } if (space) { setTimeout(dtmf.replay, dtmf.space, index, false); return; } if (!dtmf.restop_flag && index < dtmf.sequence.value.length) { dtmf.sequence.selectionStart = index + 1; dtmf.sequence.selectionEnd = index + 2; dtmf.sequence.focus(); index++; key = dtmf.sequence.value.charAt(index); dtmf.start(null, key); setTimeout(dtmf.replay, dtmf.duration, index, true); } else { dtmf.button_replay.disabled = false; dtmf.keyboard(true); dtmf.button_restop.disabled = true; dtmf.restop_flag = false; dtmf.sequence.focus(); if (dtmf.rec !== null && dtmf.rec.state == 'recording') { dtmf.rec.stop(); } } }, keyboard: function (enable) { buttons = document.querySelectorAll('#dtmf_keyboard button'); buttons.forEach(function (button, index) { button.disabled = !enable; }); }, load: function () { dtmf.sequence = document.getElementById('dtmf_sequence'); dtmf.button_replay = document.getElementById('dtmf_replay'); dtmf.button_restop = document.getElementById('dtmf_restop'); let f = [1209, 1336, 1477, 1633, 697, 770, 852, 941]; dtmf.keys = { '1':[f[0], f[4]], '2':[f[1], f[4]], '3':[f[2], f[4]], 'A':[f[3], f[4]], '4':[f[0], f[5]], '5':[f[1], f[5]], '6':[f[2], f[5]], 'B':[f[3], f[5]], '7':[f[0], f[6]], '8':[f[1], f[6]], '9':[f[2], f[6]], 'C':[f[3], f[6]], '*':[f[0], f[7]], '0':[f[1], f[7]], '#':[f[2], f[7]], 'D':[f[3], f[7]] }; buttons = document.querySelectorAll('#dtmf_keyboard button'); buttons.forEach(function (button, index) { button.addEventListener('mousedown', dtmf.start); button.addEventListener('mouseup', dtmf.stop); button.addEventListener('mouseleave', dtmf.stop); }); dtmf.sequence.focus(); } }; document.addEventListener('DOMContentLoaded', dtmf.load); </script> <style> :root{ --c-back-body:#f9f9f9; --c-back-main:#fff; --c-back-button:#efefef; --c-back-button-hover:#e7e7e7; --c-back-plate:#f7f7f7; --c-back-progress:#f1f1f1; --c-border:#aaa; --c-border-banner:#bbb; --c-text:#111; } @media (prefers-color-scheme:dark){ :root{ --c-back-body:#323436; --c-back-main:#2c2c2c; --c-back-button:#464a4b; --c-back-button-hover:#535353; --c-back-plate:#3d4042; --c-border:#787878; --c-border-banner:#5d6265; --c-text:#d7d7d7; }} body,html{margin:0;padding:0} html{height:100vh;width:100%} body{background-color:var(--c-back-body);font-family:'Open Sans',sans-serif;font-size:16px;color:var(--c-text);min-height:100vh;min-width:280px;display:flex;flex-direction:column} input,button,textarea,select,.button{outline:0;font-family:FontAwesome,'Open Sans',sans-serif;font-size:14px} input,button,.button{padding:5px;margin:3px;border:1px solid var(--c-border);background-color:var(--c-back-main);color:var(--c-text)} .button{text-align:center;text-decoration:none} input:disabled,button:disabled,.button:disabled{color:var(--c-border-banner)} input[type=button],input[type=submit],button,.button{padding:5px 10px;background-color:var(--c-back-button);cursor:pointer} input[type=button]:hover:enabled,input[type=submit]:hover:enabled,button:hover:enabled,.button:hover{background-color:var(--c-back-button-hover)} input:read-only{background-color:var(--c-back-plate)} textarea{box-sizing:border-box;border:1px solid var(--c-border);background-color:var(--c-back-main);color:var(--c-text)} select{padding:2px;background-color:var(--c-back-main);color:var(--c-text)} select,select:disabled{border:1px solid var(--c-border)} #content{line-height:1.75em} #content .plate{border:1px solid var(--c-border-banner);background-color:var(--c-back-plate);padding:15px;margin:15px 0} #content .form .line{display:flex;flex-wrap:wrap;margin-bottom:5px} #content .form .line:last-of-type{margin-bottom:0} #content .form .line>:not(.item):first-child{margin-left:0} #content .form .item{display:flex;flex-direction:column} #content .form .item:not(:last-child){margin-right:5px} #content .form .field{display:flex;flex-direction:row;align-items:center} #content .form .field>input:first-child{margin-left:0} #dtmf_keyboard button { width: 3em; height: 3em; } #dtmf_keyboard span{ width: 1.5em; display: inline-block; } #dtmf_panel { display: flex; flex-direction: column; flex-grow: 1; } #dtmf_panel textarea { width: 100%; } </style> <div id="content"> <h1>DTMF Generator</h1> <div class="brief"> <div> Phone dial tones online synthesizer. Dial keyboard emulator. </div> </div> <div style="display: flex;flex-direction: row;flex-wrap: wrap;"> <div id="dtmf_keyboard" class="plate" style="margin: 0.5em 0;"> <div> <button>1</button> <button>2</button> <button>3</button> <span></span> <button>A</button> </div> <div> <button>4</button> <button>5</button> <button>6</button> <span></span> <button>B</button> </div> <div> <button>7</button> <button>8</button> <button>9</button> <span></span> <button>C</button> </div> <div> <button>*</button> <button>0</button> <button>#</button> <span></span> <button>D</button> </div> </div> <div style="padding: 0 0.5em;"></div> <div id="dtmf_panel" class="plate form" style="margin: 0.5em 0;"> <div class="line"> <div class="item" style="flex-grow: 1;"> <div class="label"> Sequence </div> <div class="field"> <textarea spellcheck="false" id="dtmf_sequence" onkeydown="return dtmf.start(event);" onkeyup="dtmf.stop();"></textarea> </div> </div> </div> <div class="line"> <button id="dtmf_replay" onclick="dtmf.replay();" style="flex-grow: 1;"> Replay </button> <button id="dtmf_restop" onclick="dtmf.restop();" disabled=""> Stop </button> <button onclick="dtmf.backspace();"> Back </button> <button style="margin-right: 0;" onclick="dtmf.clear();"> Clear </button> </div> <div class="line"> <div class="item"> <div class="label"> Duration [ms] </div> <div class="field"> <input type="number" id="dtmf_duration" min="35" max="1000" value="150"> </div> </div> <div class="item"> <div class="label"> Space [ms] </div> <div class="field"> <input type="number" id="dtmf_space" min="5" max="1000" value="50"> </div> </div> </div> <div><audio id="dtmf_record" controls></audio></div> </div> </div> </div>