JavaScriptで音声案内

new SpeechSynthesisUtterance を試す

便利な世の中になったものだ。
イントネーションがちょっと違う
それとサンプルの音声内容にびっくりするかもしれないけれど。
サンプルのまま使いう施設は限られているかな?
単位は1分単位です

<!DOCTYPE hrml>
<html lang="ja">
<meta charset="UTF-8">
<style>
input[name="TIME"] {
  width: 6ex;
  color: green;
  font-size: x-large;
  border: none;
  text-align: center;
}
select {
  font-size: x-large;
  color: green;
  border: none;
}
td:nth-of-type(2) input[type=button] {
  width: 5ex;
}
input:disabled,
select:disabled {
  color: red;
  background: rgba(255,200,200,.5)
}
input[name="SET"] {
width:100%;
height:3em;
box-sizing:border-box;
}
</style>


<body>
<h1>音声案内サーポート</h1>
<table border="1">
  <thead>
  <tr>
    <th>Time
    <th>up/down
    <th>Massage
    <th>Switch
  <tbody>
  <tr>
  <td>
	  <input type="text" name="TIME">
	  <input type="hidden" value="" name="TMID">
  <td>
	  <input type="button" value="+1" name="PLUS1">
	  <input type="button" value="+5" name="PLUS5">
	  <input type="button" value="+10" name="PLUS10"><br>
	  <input type="button" value="-1" name="MINUS1">
	  <input type="button" value="-5" name="MINUS5">
	  <input type="button" value="-10" name="MINUS10">
  <td>
	  <select name="MESS">
	    <option value="設定時刻と成りました。">--
	    <option
	      value="そろそろ、到着予定時刻です"
	            >到着予定
	    <option
	      value="そろそろ、告別室に案内放送を、行う時刻です"
	            >告別室誘導
	    <option
	      value="そろそろ、待合室の清掃の案内放送を、行う時刻です"
	            >待合室清掃
	    <option
	      value="そろそろ、しゅうこつの案内放送を、行う時刻です"
	            >収骨案内
	    <option
	      value="宗家、御遺族及び会葬者の、退場を促す放送を、行う時刻です"
	            >帰路案内
	  </select>
  <td>
	  <input type="button" value="Message Set" name="SET">
</table>
<script>
{
  let
    tbody = document.querySelector ('tbody'),
    tr    = tbody.querySelector ('tr:first-of-type'),
    cnt   = 10;
  for (let i = 0; i < cnt; i++) {
    tbody.appendChild (tr.cloneNode (true));
  }
}

function zp (num) {
  return ('00' + num).slice (-2);
}

function getTime (dt = new Date) {
  return [zp(dt.getHours ()), zp(dt.getMinutes ())].join (':');
}

function addTime (str = '', offset = 0) {
  if (! str)
    str = getTime ();
  let
    dt = new Date,
    [h, m] = str.split (':');
    dt.setHours (parseInt (h, 10));
    dt.setMinutes (parseInt (m, 10));
    dt.setMinutes (dt.getMinutes () + offset);

  return getTime (dt);
}

function getMinutes (str = '00:00') {
  let
    [h, m] = str.split (':');
  return parseInt (h, 10) * 60 + parseInt (m, 10);
}

function inp (e) {
  let tr = e.parentNode.parentNode,
  [t, tmid, ...es] = tr.querySelectorAll ('input, select');
  switch (e.name) {
  case 'TIME' :
    t.value = getTime ();
    break;
  case 'PLUS1' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 1);
    break;
  case 'PLUS5' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 5);
    break;
  case 'PLUS10' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 10);
    break;
  case 'PLUS1' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 1);
    break;
  case 'PLUS5' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 5);
    break;
  case 'PLUS10' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, 10);
    break;
  case 'MINUS1' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, -1);
    break;
  case 'MINUS5' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, -5);
    break;
  case 'MINUS10' :
    if (! t.value)
      t.value = getTime ();
    t.value = addTime (t.value, -10);
    break;
  case 'SET' :
    if (! t.value) return;
    switch (e.value) {
    case 'Message Set' :
      let
        t0 = getMinutes (t.value) * 60 * 1000,
        t1 = getMinutes (getTime ()) * 60 * 1000;
      if (t0 < t1) {
        alert ('マイナスの時刻が設定されています');
        return;
      }
      e.value = 'Cansell';
      disabled ([t,...es], e, true);
      tmid.value = setTimeout (crMess (es[6]),  t0 - t1); 
      break;
    case 'Cansell' :
      if (tmid.value) {
        clearTimeout (parseInt (tmid.value, 10));
        tmid.value = '';
      }
      e.value = 'Message Set';
      disabled ([t,...es], e, false);
      t.value = '';
      break;
    }
  }
}


function disabled (ary, drop, state) {
  for (let e of ary)
    if (e !== drop)
      e.disabled = state;
}


function crMess (e) {
  return function () {
    let
      ssu = new SpeechSynthesisUtterance (),
      tr = e.parentNode.parentNode,
      es = tr.querySelectorAll ('input, select');

    ssu.lang = 'ja-JP';
    ssu.pitch = 1.6;
    ssu.rate = 1.2;
    ssu.text = e.value + '。繰り返します。' + e.value;
    speechSynthesis.speak (ssu);

    for (let a of es)
      a.disabled = false;
    es[0].value = '';
    es[9].value = 'Message Set';
  };
}

function handler (event) {
  let e = event.target;
  if (e.disabled)
    return;
  console.log (e.disabled);
    
  switch (e.tagName) {
  case 'INPUT' :
    inp (e);
    break;
  case 'SELECT' :
    break;
  }
}

document.addEventListener ('click', handler, false);

</script>