カウントダウンタイマー

今回はJavaScriptでカウントダウンタイマーを作る。指定時間後に音をならして終了する。

時間設定に文字入力を行うようにすると、入力された字が文字か数値かをチェックする仕組みが必要になるため、プルダウンを使って数値設定をするようにした。

iPadでは、文字入力だと切り替えが面倒で…。

なお、Windowsではほとんどのブラウザで、TabキーやShiftキー+Tabキーでフォーカスを合わせるとキーボード入力した数値に素早く設定してくれる。

<!DOCTYPE html>
<HTML lang="ja">
<HEAD><TITLE>カウントダウンタイマー</TITLE></HEAD>
<BODY>

<CENTER>

<H1>カウントダウンタイマー</H1>

<AUDIO id="finish">
<SOURCE src="finish.ogg" type="audio/ogg">
<SOURCE src="finish.m4a" type="audio/mpeg">
</AUDIO>

<FORM id="countdownform" name="countdownform">
<SCRIPT>
var cdid;
var audio = document.getElementById("finish");
var idnames = ["hourselect","minselect","secselect"];
var nums = [24,60,60];
for(var i = 0; i < idnames.length; i++) {
  document.write("<SELECT id=¥"" + idnames[i] + "¥" name=¥"" + idnames[i] + "¥">");
  for(var j = 0; j < nums[i]; j++) {
    document.write("<OPTION value = " + j + ">" + setDigit(j, 2) + "</OPTION>");
  }
  document.write("</SELECT>");
  if(i < 2) {
    document.write(":");
  } else {
    document.write(".");
  }
}
document.write("<INPUT id=¥"msectext¥" name=¥"msectext¥" type=¥"text¥" value=¥"000¥" size=¥"3¥" style=¥"text-align: center¥" disabled>");
document.write("<BR><BR>");
document.write("<INPUT id=¥"cdbutton¥" name=¥"cdbutton¥" type=¥"button¥" value=¥"スタート¥" onClick=¥"countdown()¥">");
var button = document.getElementById("cdbutton");
button.addEventListener("click",function() {
  audio.load();
}, false);

function countdown() {
  if(document.countdownform.cdbutton.value == "スタート") {
    document.countdownform.cdbutton.value = "ストップ";
    var hValue = document.countdownform.hourselect.value * 60 * 60;
    var mValue = document.countdownform.minselect.value * 60;
    var sValue = document.countdownform.secselect.value * 1;
    var endTime = Date.now() + (hValue + mValue + sValue) * 1000;
    cdid = setInterval(function() {
      var diff = endTime - Date.now();
      var remainTime = getTimes(diff);
      for(var i = 0; i < idnames.length; i++) {
        var pulldown = document.getElementById(idnames[i]).getElementsByTagName("OPTION");
        for(var j = 0; j < pulldown.length; j++) {
          if(j == remainTime[i]) {
            pulldown[j].selected = true;
          }
        }
      }
      document.countdownform.msectext.value = setDigit(diff % 1000, 3);
      if(diff <= 0) {
        document.countdownform.msectext.value = "000";
        audio.play();
        document.countdownform.cdbutton.value = "スタート";
        clearInterval(cdid);
      }
    }, 10);
  } else {
    document.countdownform.cdbutton.value = "スタート";
    clearInterval(cdid);
  }
}

function setDigit(value, digits) {
  res = value;
  var times = digits - value.toString().length;
  if(times > 0) {
    for(var i = 0; i < times; i++) {
      res = "0" + res;
    }
  }
  return res;
}

function getTimes(msTime) {
  var msec = msTime % 1000;
  msTime = (msTime - msec) / 1000;
  var sec = msTime % 60;
  msTime = (msTime - sec) / 60;
  var min = msTime % 60;
  var hour = (msTime - min) / 60;
  return [hour, min, sec, msec];
}
</SCRIPT>

</FORM>

</CENTER>

</BODY>
</HTML>


結果はこんな感じ。

カウントダウンタイマー



そして、やはりこのページで組み込むとInternet Explorerでは終了の音が出ない。独立したHTMLファイルだと音はなるのに…。

MIDIから各種音声ファイルを作成

ちょっとした音楽をつくるのに、いつもDominoを利用している。操作も分かりやすく、重宝している。

フリーなのに細かなところまで作ることができる…らしいが、正直、残念ながらそこまで使いこなすことができていない。

この前、JavaScriptで音を再生するにあたり、OGGとACC形式のファイルを取得しようとあちこちネット上の素材置き場をまわったが、両方の形式が入手できるのは少なく、どちらかのみであることが多かった。

調べたところ、日頃から同じく愛用しているフリーウェアAudacityでOGGとACCの出力が可能なことが分かった。(ちなみに、いつもはインストール不要のポータブル版Audacity Portableを利用している。)

さらに調べを進めると、「DTM作曲始めましょ 番外編1 MIDI→WAV→MP3」で、Audacityを使ってPCでの再生音を直接録音する方法を見つけた。

ここに書かれていることに従い、画面左上あたりにある「オーディオホスト」を「Windows DirectSound」に、その隣にある「録音デバイス」を「ステレオミキサー」に、「録音チャンネル」を「ステレオ」に、「再生デバイス」を「スピーカー」に、それぞれ変更して録音を開始し、適当なアプリケーションソフトウェアで音を再生する。

音の再生が終わったところで録音を停止し、前後の無音部分を削除する。

これにより、MIDIでも他の形式でも、PCで音を再生することさえできれば、Audacityで出力可能なファイル形式の音声データを作成することが可能だ。

教えて!goo - iTunesでmidをmp3に変換する方法」でiTunes + QuickTimeによる変換も見つけたが、iPadを独立して使っているのでiTunesは使用しておらず、めったに使わないソフトウェアを入れるのも…と思っていたので、これまでもお世話になってきたAudacityでの録音方法が分かってとてもうれしい。

というこで、「初心者になるための耳コピMIDI講座 #01-10 SMF書き出し」のようにDominoを使ってMIDIファイルを作成し、上記のようにAudacityでOGGやACCなどの形式で出力・保存すればOK。

DominoもAudacity Portableも、適当なフォルダに置いておき、不要になったらフォルダごと削除できるのがとてもうれしい。これまでにもインストール・アンインストールするたびに不安が募っていったので、できるだけフォルダ単位で管理できるアプリケーションソフトウェアを使うことにしている。

フォルダ単位で管理できるもう一つの良い点は、PC引っ越しの際にも簡単であること。1つ1つのアプリケーションソフトウェアをインストールし直す作業が不要で、データ同様バックアップから復元したら終了。そのまますぐに使えるのが良い。

Domino、もっと練習してもっと使って力をつけたい…。

ストップウォッチ(改)

前回の「ストップウォッチを作ってみた」で作ったストップウォッチを使っていたところ、スタートボタンとストップボタンが別々なことに違和感を感じたので、スタートボタンをストップボタンと兼用しようと考えた。

  • スタート・ストップボタンに表示されている文字をチェック

  • 「スタート」ボタンをクリックしたらボタン名を「ストップ」にして時間計測を開始

  • 「ストップ」ボタンをクリックしたらボタン名を「スタート」にして時間計測を終了


  • <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>ストップウォッチ</TITLE></HEAD>
    <BODY>

    <CENTER>

    <H1>ストップウォッチ</H1>

    <FORM name="stopwatch">
    <INPUT type="text" size="20" name="display" value="00:00:00.000" style="text-align: center"><BR><BR>
    <INPUT type="button" name="startstopbutton" value="スタート" onClick="swStartStop()">
    <INPUT type="button" name="resetbutton" value="リセット" onClick="swReset()" disabled>
    </FORM>

    <SCRIPT>
    var swid;

    //スタート・ストップボタンをクリックした時
    function swStartStop() {
      var buttonname = document.stopwatch.startstopbutton.value;
      if(buttonname == "スタート") {
        // ボタン表示が「スタート」の時
        document.stopwatch.startstopbutton.value = "ストップ";
        document.stopwatch.resetbutton.disabled = true;
        var nowValue = document.stopwatch.display.value;
        var hms = nowValue.split(":");
        var secmsec = hms[2].split(".");
        var prevTime = (hms[0] * 60 * 60 + hms[1] * 60 + secmsec[0] * 1) * 1000 + secmsec[1] * 1;
        var startTime = Date.now();
        swid = setInterval(function() {
          var nowTime = Date.now();
          displayTime(nowTime - startTime + prevTime);
        }, 10);
      } else {
        // ボタン表示が「ストップ」の時
        document.stopwatch.startstopbutton.value = "スタート";
        document.stopwatch.resetbutton.disabled = false;
        clearInterval(swid);
      }
    }

    // リセットボタンをクリックした時
    function swReset() {
      document.stopwatch.resetbutton.disabled = true;
      displayTime(0);
    }

    // 数値を指定桁数に変更 例)setDigit(21, 4) => 「0021」を返す
    function setDigit(value, digits) {
      res = value;
      var times = digits - value.toString().length;
      if(times > 0) {
        for(var i = 0; i < times; i++) {
          res = "0" + res;
        }
      }
      return res;
    }

    // ミリ秒 を受け取り 時:分:秒.ミリ秒 の形で表示
    function displayTime(msTime) {
      var msec = msTime % 1000;
      msTime = (msTime - msec) / 1000;
      var sec = msTime % 60;
      msTime = (msTime - sec) / 60;
      var min = msTime % 60;
      var hour = (msTime - min) / 60;
      document.stopwatch.display.value = setDigit(hour, 2) + ":" + setDigit(min, 2) + ":" + setDigit(sec, 2) + "." + setDigit(msec, 3);
    }
    </SCRIPT>

    </CENTER>

    </BODY>
    </HTML>


    これで、スタートボタンとストップボタンを一つのボタンで処理することができた。

    ストップウォッチ




    ストップウォッチを作ってみた

    今回は、JavaScriptでストップウォッチを作ってみた。

    Date.now()を使って、その瞬間をミリ秒で取得する。

    MDNの記事によれば、「UTC(協定世界時)での 1970 年 1 月 1 日 00 時 00 分 00 秒 から現在までの経過ミリ秒を数値で返します。」とのこと。

    スタートボタンをクリックした瞬間の時間と、setInterval内で繰り返す間の時間との差を計算することで、ストップウォッチの機能を実現する。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>ストップウォッチ</TITLE></HEAD>
    <BODY>

    <CENTER>

    <H1>ストップウォッチ</H1>

    <FORM name="stopwatch">
    <INPUT type="text" size="20" name="display" value="00:00:00.000" style="text-align: center"><BR><BR>
    <INPUT type="button" name="startbutton" value="スタート" onClick="swStart()">
    <INPUT type="button" name="stopbutton" value="ストップ" onClick="swStop()" disabled>
    <INPUT type="button" name="resetbutton" value="リセット" onClick="swReset()" disabled>
    </FORM>

    <SCRIPT>
    var swid;

    // スタートボタンをクリックした時
    function swStart() {
      document.stopwatch.startbutton.disabled = true;
      document.stopwatch.stopbutton.disabled = false;
      document.stopwatch.resetbutton.disabled = true;
      var nowValue = document.stopwatch.display.value;
      var hms = nowValue.split(":");
      var secmsec = hms[2].split(".");
      var prevTime = (hms[0] * 60 * 60 + hms[1] * 60 + secmsec[0] * 1) * 1000 + secmsec[1] * 1;
      var startTime = Date.now();
      swid = setInterval(function() {
        var nowTime = Date.now();
        displayTime(nowTime - startTime + prevTime);
      }, 10);
    }

    // ストップボタンをクリックした時
    function swStop() {
      document.stopwatch.startbutton.disabled = false;
      document.stopwatch.stopbutton.disabled = true;
      document.stopwatch.resetbutton.disabled = false;
      clearInterval(swid);
    }

    // リセットボタンをクリックした時
    function swReset() {
      document.stopwatch.resetbutton.disabled = true;
      displayTime(0);
    }

    // 数値を指定桁数に変更 例)setDigit(21, 4) => 「0021」を返す
    function setDigit(value, digits) {
      res = value;
      var times = digits - value.toString().length;
      if(times > 0) {
        for(var i = 0; i < times; i++) {
          res = "0" + res;
        }
      }
      return res;
    }

    // ミリ秒 を受け取り 時:分:秒.ミリ秒 の形で表示
    function displayTime(msTime) {
      var msec = msTime % 1000;
      msTime = (msTime - msec) / 1000;
      var sec = msTime % 60;
      msTime = (msTime - sec) / 60;
      var min = msTime % 60;
      var hour = (msTime - min) / 60;
      document.stopwatch.display.value = setDigit(hour, 2) + ":" + setDigit(min, 2) + ":" + setDigit(sec, 2) + "." + setDigit(msec, 3);
    }
    </SCRIPT>

    </CENTER>

    </BODY>
    </HTML>


    実行結果はこのような感じ。

    ストップウォッチ





    「// スタートボタンをクリックした時」の中の数行にポイントあり。

    var nowValue = document.stopwatch.display.value;
    var hms = nowValue.split(":");
    var secmsec = hms[2].split(".");


    <1行目>
    時間を計っている途中で止め、その続きから再び始められるように、まずは表示枠の数字を得る。

    <2行目>
    「:」でデータを小分けする。
    例)「01:25:06.094」から、hms[0]に「01」、hms[1]に「25」、hms[2]に「06.094」を入れる。

    <3行目>
    「.」でデータを小分けする。
    例)先ほどのhms[2]に入っている「06.094」から、secmsec[0]に「06」、secmsec[1]に「094」を入れる。

    これにより、hms[0]に時、hms[1]に分、secmsec[0]に秒、secmsec[1]にミリ秒が入る。


    var prevTime = (hms[0] * 60 * 60 + hms[1] * 60 + secmsec[0] * 1) * 1000 + secmsec[1] * 1;


    この「* 1」があるかないかで結果が変わる。

    先の例で考えてみると、「"01" * 60 * 60 + "25" * 60 + "06"」として計算される。

    このとき、"01"という数に「* 60」などの数をかけることで数として計算してくれるが、数値をかけていない"06"は文字列として、計算結果の後ろに付け足される。このように、「+」は文字列をつなぐ働きもある。

    "01" * 60 * 60 = 1 * 60 * 60 = 3600
    "25" * 60 = 25 * 60 = 1500
    3600 + 1500 + "06" = 5100 + "06" = 510006

    もしも「* 1」がついていれば、「"06" * 1 = 6」となり、「5100 + 6 = 5106」となる。

    ( )の中で計算した5106の単位は秒なので、1000倍してミリ秒単位である5106000を算出する。ここで、先ほどと同様に算出したミリ秒に"094"をそのまま + をしてしまうと「510600094」となってしまうので、必ず"094"に対して「* 1」を行い、数値の「94」にして計算させる。

    「displayTime」という関数を作り、与えられたミリ秒から「時:分:秒.ミリ秒」の形式で出力させる。その際に、時・分・秒は2桁で、ミリ秒は3桁で表示させるため、「setDigit」関数に数値と表示桁数を与えるようにして、指定された桁数より数値が小さければ、その数値の頭に「0」を付けて返すようにした。

    JavaScriptで色見本をつくる

    HTMLでのセーフカラーとカラーネームの一覧表ができたので、背景色と文字色の組み合わせが簡単にチェックできるようなプログラムを作ってみた。

    TABLE内のTDタグでもonClickができるとは…。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>色見本</TITLE></HEAD>
    <BODY>

    <CENTER>

    <H1>色見本</H1>

    下のカラーパレットをクリックしてそれぞれの色を選んでください。<BR><BR>
    <FORM id="colorform" name="colorform">
    <TABLE border="0" style="text-align: left; background-color: white; color: black"><TR><TD>
    <INPUT type="radio" id="backR" name="colorselect" checked>背景色
    </TD><TD>
    <INPUT type="text" id="backC" name="backC" size="12" style="text-align: center">
    </TD><TD width="30"></TD><TD>
    <INPUT type="radio" id="textR" name="colorselect">文字色
    </TD><TD>
    <INPUT type="text" id="textC" name="textC" size="12" style="text-align: center">
    </TD></TR>
    <TR><TD>
    <INPUT type="radio" id="fbackR" name="colorselect">枠内背景色
    </TD><TD>
    <INPUT type="text" id="fbackC" name="fbackC" size="12" style="text-align: center">
    </TD><TD></TD><TD>
    <INPUT type="radio" id="ftextR" name="colorselect">枠内文字色
    </TD><TD>
    <INPUT type="text" id="ftextC" name="ftextC" size="12" style="text-align: center">
    </TD></TR></TABLE>
    <BR>
    <INPUT type="text" id="text" name="text" value="背景色や文字色が変わります。" style="text-align: center; font-size: 30px" size="50">
    </FORM>
    <BR><BR>

    <SCRIPT>
    var colnum = 9;
    var colorname = ["White", "Silver", "Gray", "Black", "Red", "Maroon", "Yellow", "Olive", "Lime", "Green", "Aqua", "Teal", "Blue", "Navy", "Fuchsia", "Purple", "Orange"];
    var r = ["00","33","66","99","CC","FF"];
    var g = ["00","33","66","99","CC","FF"];
    var b = ["00","33","66","99","CC","FF"];
    document.write("<TABLE border=¥"0¥" cellspacing=¥"1¥" cellpadding=¥"5¥" style=¥"background-color: black¥">");

    // COLOR NAME
    document.write("<TR><TH rowspan=¥"" + Math.ceil(colorname.length / colnum) + "¥" style=¥"background-color: lime; color: black¥">Color<BR>Name</TH>");
    for(var i = 0; i < Math.ceil(colorname.length / colnum); i++) {
      if(i > 0) {
        document.write("</TR><TR>");
      }
      for(var j = 0; j < colnum; j++) {
        var index = colnum * i + j;
        document.write("<TD colspan=¥"" + r.length + "¥" style=¥"background-color: ");
        if(index < colorname.length) {
          document.write(colorname[index] + "; color: ");
          if(colorname[index] == "Gray" || colorname[index] == "Black" || colorname[index] == "Maroon" || colorname[index] == "Olive" || colorname[index] == "Green" || colorname[index] == "Teal" || colorname[index] == "Blue" || colorname[index] == "Navy" || colorname[index] == "Purple") {
            document.write("white");
          } else {
            document.write("black");
          }
          document.write("¥" id=¥"" + colorname[index] + "¥" onClick=¥"setColor(this)¥">");
          document.write(colorname[index]);
        } else {
          document.write("white¥">--------");
        }
        document.write("</TD>");
      }
    }

    // SAFE COLOR
    var counter = 0;
    document.write("<TR><TH rowspan=¥"" + colnum + "¥" width=¥"60¥" style=¥"background-color: fuchsia; color: black¥">Safe<BR>Color</TH>");
    for(var i = 0; i < r.length; i++) {
      for(var j = 0; j < g.length; j++) {
        if(counter % colnum == 0) {
          if(counter > 0) {
            document.write("</TR>");
          }
          document.write("<TR>");
        }
        counter++;
        for(var k = 0; k < b.length; k++) {
          var rgb = "#" + r[i] + g[j] + b[k];
          document.write("<TD style=¥"background-color: " + rgb + "¥" width=¥"5¥" height=¥"5¥" id=¥"" + rgb + "¥" onClick=¥"setColor(this)¥">");
          document.write("</TD>");
        }
      }
    }

    document.write("</TABLE>");

    function setColor(o) {
      if(document.getElementById("backR").checked) {
        document.bgColor = o.id;
        document.colorform.backC.value = o.id;
      } else if(document.getElementById("textR").checked) {
        document.fgColor = o.id;
        document.colorform.textC.value = o.id;
      } else if(document.getElementById("fbackR").checked) {
        document.colorform.text.style.backgroundColor = o.id;
        document.colorform.fbackC.value = o.id;
      } else {
        document.colorform.text.style.color = o.id;
        document.colorform.ftextC.value = o.id;
      }
    }

    </SCRIPT>

    </CENTER>

    </BODY>
    </HTML>


    以下のような感じに完成。

    色見本
    (この画像をクリックすると完成したHTMLファイルを表示)

    適当な○をクリックして下のパレットから好きな色をクリックすれば、背景色や文字色が変わり、色名かRGB値が表示される。

    これで背景色と文字色の組み合わせの確認はバッチリ!

    あとはセンスさえよければいいものが作れる…はず。

    HTMLカラーネームとセーフカラーの一覧を表示

    色を決める際、できるだけHTMLセーフカラーを使って文字や背景色を決めるようにしている。

    もうそんなにこだわる必要がないのかもしれないが、色の選択肢が多すぎるとなかなか決められない。

    毎回ネットでセーフカラーと検索すれば出て来るが、手元にあると楽だな、と思ったので、JavaScriptでセーフカラー一覧表を作ってみることにした。

    また、検索すると背景色として色見本が出てくることが多く、文字色の場合どのように見えるかも知りたいので、背景色と文字色が両方見られるようにした。

    ついでに、HTMLでの基本の16色+CSS2.1で追加されたorangeのカラーネームも一緒に表示させる。ただし、「HTML ColorName」によると、カラーネームによる色指定ではブラウザによっては表示できないことがあると書かれている。

    背景色が暗い(色名指定時RGB値指定時)と黒い文字は読みづらかったので、文字色を「White」にした。

    さらに、文字色が「White」と「#FFFFFF」の時は背景色を「Black」にした。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>HTML Color</TITLE></HEAD>
    <BODY>

    <CENTER>

    <H1>HTML Color</H1>

    <SCRIPT>
    var colnum = 6;
    var colorname = ["White" , "Silver" , "Gray" , "Black" , "Red" , "Maroon" , "Yellow" , "Olive" , "Lime" , "Green" , "Aqua" , "Teal" , "Blue" , "Navy" , "Fuchsia" , "Purple" , "Orange"];
    var r = ["00","33","66","99","CC","FF"];
    var g = ["00","33","66","99","CC","FF"];
    var b = ["00","33","66","99","CC","FF"];
    document.write("<TABLE border=¥"0¥" cellspacing=¥"1¥" cellpadding=¥"5¥" style=¥"background-color: black¥">");
    document.write("<TR><TH style=¥"background-color: white¥"></TH>");
    document.write("<TH style=¥"background-color: yellow¥" colspan=¥"6¥"><H2>Background Color</H2></TH>");
    document.write("<TH style=¥"background-color: aqua¥" colspan=¥"6¥"><H2>Text Color</H2></TH></TR>");

    // COLOR NAME
    document.write("<TR><TH rowspan=¥"" + Math.ceil(colorname.length / colnum) + "¥" style=¥"background-color: lime¥">Color<BR><BR>Name</TH>");
    for(var i = 0; i < Math.ceil(colorname.length / colnum); i++) {
      if(i > 0) {
        document.write("</TR><TR>");
      }
      ////////// background color
      for(var j = 0; j < colnum; j++) {
        var index = colnum * i + j;
      if(index < colorname.length) {
          document.write("<TD style=¥"background-color: " + colorname[index]);
          if(colorname[index] == "Gray" || colorname[index] == "Black" || colorname[index] == "Maroon" || colorname[index] == "Olive" || colorname[index] == "Green" || colorname[index] == "Teal" || colorname[index] == "Blue" || colorname[index] == "Navy" || colorname[index] == "Purple") {
            document.write("; color: white");
          }

          document.write("¥">" + colorname[index] + "</TD>");
        } else {
          document.write("<TD style=¥"background-color: white¥">-------</TD>");
        }
      }
      ////////// text color
      for(var j = 0; j < colnum; j++) {
        var index = colnum * i + j;
        if(index < colorname.length) {
          document.write("<TD style=¥"background-color: ");
          if(colorname[index] == "White") {
            document.write("black");
          } else {
            document.write("white");
          }

          document.write("; color : " + colorname[index] + "¥">" + colorname[index] + "</TD>");
        } else {
          document.write("<TD style=¥"background-color: white¥">-------</TD></TR>");
        }
      }
    }

    // SAFE COLOR
    document.write("<TR><TH rowspan=¥"" + Math.ceil(r.length * g.length * b.length / colnum) + "¥" width=¥"60¥" style=¥"background-color: fuchsia¥">Safe<BR><BR>Color</TH>");
    for(var i = 0; i < r.length; i++) {
      for(var j = 0; j < g.length; j++) {
        if(i > 0 || j > 0) {
          document.write("<TR>");
        }
        ////////// background color
        for(var k = 0; k < b.length; k++) {
          var rgb = "#" + r[i] + g[j] + b[k];
          document.write("<TD style=¥"background-color: " + rgb);
          if(i < 4 && j < 4) {
            document.write("; color: white");
          }

          document.write("¥">" + rgb + "</TD>");
        }
        ///////// text color
        for(var k = 0; k < b.length; k++) {
          var rgb = "#" + r[i] + g[j] + b[k];
          document.write("<TD style=¥"background-color: ");
          if(rgb == "#FFFFFF") {
            document.write("black");
          } else {
            document.write("white");
          }

          document.write("; color: " + rgb + "¥">" + rgb + "</TD>");
        }
        document.write("</TR>");
      }
    }

    document.write("</TABLE>");
    </SCRIPT>

    </CENTER>

    </BODY>
    </HTML>


    以下のように表示。下へスクロールするとまだまだ続きが見られる。

    HTML Color
    (この画像をクリックすると完成したHTMLファイルを表示)

    これを保存しておけば、オフラインでも確認できる。

    タイマーで複数の音を順番に繰り返し再生

    前回の「タイマーで複数の音を一定時間に繰り返し再生」にて、一定間隔で複数の音を再生することができた。

    今回は、長さの違う音を順番に再生することに挑戦する。

    HTMLクイックリファレンス ★video要素、audio要素をJavaScriptから操作する」から、音の再生が終わった時に実行するイベントリスナーが存在することが分かった。

    最初に「flag」の値を「0」にしておく。

    ボタンをクリックしたときにはまだ「flag」の値が「0」なので、if文の中に入り、すぐに「flag」の値を「1」にする。そして、「music1」を再生するとともに、「.addEventListener("ended",function() {処理},false);」を使って、再生中の音が終わった瞬間に「flag」の値を「0」にするよう準備しておく。また、その他の音はロードしておく。

    「setInterval」で100ミリ秒(=0.1秒)ごとに再生を試みるが、「flag」の値が「0」になったときにしか次の音を再生しない。

    これらにより、長さの違う音「music1」「music2」「music3」が順に流れ、また「music1」に戻って…と繰り返すことができる。今回このページで使用している音源は3つともほぼ同じ長さだが、再生時間がそれぞれ異なる別の音源でも動作確認済みである。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music1">
    <SOURCE src="sample1.ogg" type="audio/ogg">
    <SOURCE src="sample1.m4a" type="audio/mpeg">
    </AUDIO>
    <AUDIO id="music2">
    <SOURCE src="sample2.ogg" type="audio/ogg">
    <SOURCE src="sample2.m4a" type="audio/mpeg">
    </AUDIO>
    <AUDIO id="music3">
    <SOURCE src="sample3.ogg" type="audio/ogg">
    <SOURCE src="sample3.m4a" type="audio/mpeg">
    </AUDIO>

    <FORM name="musicform">
    <INPUT id="playbutton" name="playbutton" type="button" value="再生" onClick="play()">
    <INPUT id="stopbutton" name="stopbutton" type="button" value="停止" onClick="stop()" disabled><BR>
    <INPUT name="timetext" type="text" value="" size="10" style="text-align: center">
    </FORM>
    <SCRIPT>
    var repeatTimer;
    var audio1 = document.getElementById("music1");
    var audio2 = document.getElementById("music2");
    var audio3 = document.getElementById("music3");
    var playlist = [audio1, audio2, audio3];
    var count = 0;
    var flag = 0;
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      for(var i = 0; i < playlist.length; i++) {
        if(i == 0) {
          playmusic();
        } else {
          playlist[i].load();
        }
      }
    }, false);
    setInterval("displayTime()", 100);

    function playmusic() {
      if(flag == 0) {
        flag = 1;
        playlist[count].play();
        playlist[count].addEventListener("ended", function() {
          flag = 0;
        }, false);
        count++;
        if(count == playlist.length) {
          count = 0;
        }
      }
    }


    function play() {
      document.musicform.playbutton.disabled = true;
      document.musicform.stopbutton.disabled = false;
      repeatTimer = setInterval(function() {
        playmusic();
      }, 100);
    }

    function stop() {
      document.musicform.playbutton.disabled = false;
      document.musicform.stopbutton.disabled = true;
      clearInterval(repeatTimer);
      count = 0;
      for(i = 0; i < playlist.length; i++) {
        playlist[i].pause();
        playlist[i].currentTime = 0;
      }
      flag = 0;
    }

    function displayTime() {
      var nowTime = new Date();
      document.musicform.timetext.value = setTwoDigit(nowTime.getHours()) + ":" + setTwoDigit(nowTime.getMinutes()) + ":" + setTwoDigit(nowTime.getSeconds());
    }

    function setTwoDigit(num) {
      var res = num;
      if(res < 10) {
        res = "0" + res;
      }
      return res;
    }
    </SCRIPT>
    </BODY>
    </HTML>


    音楽再生



    これを使えば、CDの全曲リピートと同じように曲を楽しむことができそう。今後これらを上手に組み込んでいけるといいな。

    そして、今回もInternet Explorerでは、保存したHTMLファイルでは再生できても、埋め込んだこのページでは再生できなかった。

    タイマーで複数の音を一定時間に繰り返し再生

    前回の「タイマーで音を繰り返し再生」のときに、JavaScriptを使って1つの音を一定時間に繰り返し再生させることができた。

    ところで、「iOS/Android で HTML5 の audio/video を任意のタイミングで再生する方法」に、次のように書かれていた。

    ここで必要なオーディオファイルを全部ロードしてしまうと良さそうです。そうすれば後は好きなタイミングで音声を再生できます。


    ということは、複数の音声ファイルをロードしておけば、後から複数の音を順番に再生することが可能なのでは?

    5秒前後の音声データを3種類(それぞれOgg形式とACC形式で6つのファイル)を用意し、「playlist」という配列に曲順を覚えさせて、3曲を順番に繰り返し再生させた。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music1">
    <SOURCE src="sample1.ogg" type="audio/ogg">
    <SOURCE src="sample1.m4a" type="audio/mpeg">
    </AUDIO>
    <AUDIO id="music2">
    <SOURCE src="sample2.ogg" type="audio/ogg">
    <SOURCE src="sample2.m4a" type="audio/mpeg">
    </AUDIO>
    <AUDIO id="music3">
    <SOURCE src="sample3.ogg" type="audio/ogg">
    <SOURCE src="sample3.m4a" type="audio/mpeg">
    </AUDIO>


    <FORM name="musicform">
    <INPUT id="playbutton" name="playbutton" type="button" value="再生" onClick="play()">
    <INPUT id="stopbutton" name="stopbutton" type="button" value="停止" onClick="stop()" disabled><BR>
    <INPUT name="timetext" type="text" value="" size="10" style="text-align: center">
    </FORM>
    <SCRIPT>
    var repeatTimer;
    var audio1 = document.getElementById("music1");
    var audio2 = document.getElementById("music2");
    var audio3 = document.getElementById("music3");
    var playlist = [audio1, audio2, audio3];
    var count = 0;

    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      for(var i = 0; i < playlist.length; i++) {
        if(i == 0) {
          playlist[i].play();
        } else {
          playlist[i].load();
        }
      }

    }, false);
    setInterval("displayTime()", 100);

    function play() {
      document.musicform.playbutton.disabled = true;
      document.musicform.stopbutton.disabled = false;
      repeatTimer = setInterval(function() {
        count++;
        if(count == playlist.length) {
          count = 0;
        }
        playlist[count].play();

      }, 10000);
    }

    function stop() {
      document.musicform.playbutton.disabled = false;
      document.musicform.stopbutton.disabled = true;
      clearInterval(repeatTimer);
      count = 0;
      for(i = 0; i < playlist.length; i++) {
        playlist[i].pause();
        playlist[i].currentTime = 0;
      }

    }

    function displayTime() {
      var nowTime = new Date();
      document.musicform.timetext.value = setTwoDigit(nowTime.getHours()) + ":" + setTwoDigit(nowTime.getMinutes()) + ":" + setTwoDigit(nowTime.getSeconds());
    }

    function setTwoDigit(num) {
      var res = num;
      if(res < 10) {
        res = "0" + res;
      }
      return res;
    }
    </SCRIPT>
    </BODY>
    </HTML>


    音楽再生



    これで、10000ミリ秒(=10秒)ごとに「music1」「music2」「music3」と順に再生し、また「music1」に戻って…と繰り返し再生することができた。

    ちなみに、今回の1つの音声データの長さが5秒以内、再生間隔は10000ミリ秒(=10秒)だが、試しに100ミリ秒(=0.1秒)に設定してみると、ほぼ一斉に3つの音声ファイルが再生されてぐちゃぐちゃになってしまった。

    そして、今回もInternet Explorerでは、保存したHTMLファイルは再生できてもそれを埋め込んだこのページでの再生はできなかった。

    タイマーで音を一定時間に繰り返し再生

    iOSでのJavaScriptによる音の再生を調べていたときに、「iOS/Android で HTML5 の audio/video を任意のタイミングで再生する方法」内で気になることが書かれていた。

  • touch/mouseイベントの直接のハンドラ内でのみ有効で、タイマーを挟むとダメ

  • ユーザーイベント発生時に load() だけ呼び出し、後は任意のタイミングで play() すればよい

  • audio/videoの自動再生や再生タイミングはOSバージョンでコロコロかわる


  • とりあえず、「sample.ogg」や「sample.m4a」を5秒ほどの短い音声データにして、タイマー(今回はsetInterval)を使って10000ミリ秒(=10秒)間隔で再生させてみる。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.ogg" type="audio/ogg">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    </AUDIO>
    <FORM id="musicform">
    <INPUT id="playbutton" type="button" value="再生">
    </FORM>
    <SCRIPT>
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.load();
      setInterval(function() {
        audio.play();
      },10000);

    }, false);
    </SCRIPT>
    </BODY>
    </HTML>


    「再生」ボタンをクリックすると、10秒後に1回目の音が流れ、その後10秒間隔(再生時間も含む)で音が繰り返し再生される。

    …クリックしたときには音が再生されない?

    というわけで、次はINPUTタグにonClickを使って関数を指定して再生してみる。ついでに、タイマーの停止を行う処理を追加

    さらに、再生間隔を確認するために時計も表示させる。1秒間隔では実際の時計の秒針との表示誤差が大きいと考え、今回は100ミリ秒(=0.1秒)間隔で更新させる。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.ogg" type="audio/ogg">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    </AUDIO>
    <FORM name="musicform">
    <INPUT id="playbutton" type="button" value="再生" onClick="play()">
    <INPUT id="stopbutton" type="button" value="停止" onClick="stop()"><BR>
    <INPUT name="timetext" type="text" value="" size="10" style="text-align: center">
    </FORM>
    <SCRIPT>
    var repeatTimer;
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.load();
    }, false);
    setInterval("displayTime()", 100);

    function play() {
      audio.play();
      repeatTimer = setInterval(function() { audio.play(); }, 10000);
    }


    function stop() {
      clearInterval(repeatTimer);
    }


    function displayTime() {
      var nowTime = new Date();
      document.musicform.timetext.value = setTwoDigit(nowTime.getHours()) + ":" + setTwoDigit(nowTime.getMinutes()) + ":" + setTwoDigit(nowTime.getSeconds());
    }

    function setTwoDigit(num) {
      var res = num;
      if(res < 10) {
        res = "0" + res;
      }
      return res;
    }

    </SCRIPT>
    </BODY>
    </HTML>


    あれ?やはりボタンクリック10秒後に音がなる。

    では、ボタンのイベントリスナーで「audio.load()」でなく「audio.play()」にすれば、読み込みと再生を一度に行ってくれるので、それ以降は再生のみ行うことが可能なはず。

    ついでに、ボタンの有効化・無効化の設定にも挑戦。最初は「停止」ボタンを無効化しておき、ボタンをクリックするごとにそのボタンを無効化して相手のボタンを有効化させる。そのために、INPUTタグにname属性を追加

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.ogg" type="audio/ogg">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    </AUDIO>
    <FORM name="musicform">
    <INPUT id="playbutton" name="playbutton" type="button" value="再生" onClick="play()">
    <INPUT id="stopbutton" name="stopbutton" type="button" value="停止" onClick="stop()" disabled><BR>
    <INPUT name="timetext" type="text" value="" size="10" style="text-align: center">
    </FORM>
    <SCRIPT>
    var repeatTimer;
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.play();
    }, false);

    setInterval("displayTime()", 100);

    function play() {
      document.musicform.playbutton.disabled = true;
      document.musicform.stopbutton.disabled = false;

      repeatTimer = setInterval(function() { audio.play(); }, 10000);
    }

    function stop() {
      document.musicform.playbutton.disabled = false;
      document.musicform.stopbutton.disabled = true;

      clearInterval(repeatTimer);
    }

    function displayTime() {
      var nowTime = new Date();
      document.musicform.timetext.value = setTwoDigit(nowTime.getHours()) + ":" + setTwoDigit(nowTime.getMinutes()) + ":" + setTwoDigit(nowTime.getSeconds());
    }

    function setTwoDigit(num) {
      var res = num;
      if(res < 10) {
        res = "0" + res;
      }
      return res;
    }
    </SCRIPT>
    </BODY>
    </HTML>


    音楽再生



    同じ内容をこのページに貼りつけたところ、上のボタンをクリックして分かるように、前回と同様Internet Explorerでは再生できないが、OperaやGoogle Chromeでは再生できる。HTMLファイルはInternet Explorerで動くのに、このページに貼って動かないのは何がいけないのだろう?

    さておき、思った通り、一度再生してしまえばあとはタイマーの中でも繰り返し再生できた。でも、「停止」ボタンを押して繰り返しは止まるが、なっている途中の音が止まるわけではない。

    JavaScriptプログラミング講座 オーディオについて(HTMLAudioElement)」によれば、音を止めるための処理が必要らしい。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.ogg" type="audio/ogg">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    </AUDIO>
    <FORM name="musicform">
    <INPUT id="playbutton" name="playbutton" type="button" value="再生" onClick="play()">
    <INPUT id="stopbutton" name="stopbutton" type="button" value="停止" onClick="stop()" disabled><BR>
    <INPUT name="timetext" type="text" value="" size="10" style="text-align: center">
    </FORM>
    <SCRIPT>
    var repeatTimer;
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.play();
    }, false);
    setInterval("displayTime()", 100);

    function play() {
      document.musicform.playbutton.disabled = true;
      document.musicform.stopbutton.disabled = false;
      repeatTimer = setInterval(function() { audio.play(); }, 10000);
    }

    function stop() {
      document.musicform.playbutton.disabled = false;
      document.musicform.stopbutton.disabled = true;
      clearInterval(repeatTimer);
      audio.pause();
      audio.currentTime = 0;

    }

    function displayTime() {
      var nowTime = new Date();
      document.musicform.timetext.value = setTwoDigit(nowTime.getHours()) + ":" + setTwoDigit(nowTime.getMinutes()) + ":" + setTwoDigit(nowTime.getSeconds());
    }

    function setTwoDigit(num) {
      var res = num;
      if(res < 10) {
        res = "0" + res;
      }
      return res;
    }
    </SCRIPT>
    </BODY>
    </HTML>


    音楽再生



    これで、タイマーによる繰り返しも再生中の音も止まった。

    そして、PC内に保存したHTMLファイルではInternet Explorerで再生できるのに、このページに貼りつけたものがInternet Explorerで再生できない問題は未だに解決できていない…。

    JavaScriptで音を再生

    JavaScriptとHTML5を組み合わせると、音が再生できるらしい。

    HTML5ってどうするのだろう?と思ったら、最初に文字を少し足すだけでいいようだ。

    音の再生には、AUDIOタグとSOURCEタグを使って音源となるファイルを指定する。

    HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット」や「iOS における HTML5 の audio 要素に関する制約を克服する」によれば、ブラウザごとに対応するファイル形式が違うようだ。

    二つのサイトで微妙に内容が異なる上、個人的に内容がよく理解できなところもあったものの、更新日を参考にまとめるとおそらくこんな感じか?

    ブラウザ名WAVE
    PCM
    [.wav]
    Ogg
    Vorbis
    [.ogg]
    MP3
    [.mp3]
    AAC
    [.m4a]
    Chrome×
    Firefox
    Internet Explorer××
    Opera×××
    Safari
    ※Chromiumを除く。Android版は不明。

    この表とMP3のライセンスの話から、Ogg VorbisとAACの二種類位のファイルを準備すればよさそう。

    とりあえず「音 素材 無料」で検索して適当な音源(WAV・MP3・OGGなど)を用意し、フリーウェア「Audacity Portable」で読み込んで、[ファイル] -> [オーディオの書き出し] をしてOgg VorbisとAACの二種類のファイル「sample.ogg」「sample.m4a」を作成し、これらと同じフォルダに以下のHTMLファイルを作成。

    赤字がHTML5の宣言。
    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.ogg" type="audio/ogg">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    </AUDIO>
    <SCRIPT>
    var audio = document.getElementById("music");
    audio.load();
    audio.play();
    </SCRIPT>
    </BODY>
    </HTML>


    Windows + Internet Explorer では無事音が流れたが、iPad + FileExplorer では音は流れない。

    よくよく調べてみると、先ほどの「iOS における HTML5 の audio 要素に関する制約を克服する」の中に次のように書かれていた。

    自動再生
    モバイル版 Safari では、オーディオ・ファイルをページのロード時に自動再生することはできません。オーディオ・ファイルをロードできるのは、ユーザーによるタッチ (クリック) イベントによってのみです。以下のように HTML マークアップ内で autoplay 属性を指定しても、モバイル版 Safari はこの属性を無視し、ページのロード時にファイルを再生しません。
    <audio id="audio" src="audio_file.mp3" autoplay></audio>


    ではどうする?と調べていたら、「iOS における HTML5 の audio 要素に関する制約を克服する」のページ中ほどの「オーディオ・ストリームのロード」の項目や、「iOS/Android で HTML5 の audio/video を任意のタイミングで再生する方法」によれば、ボタンにリスナーをつけて、クリックのタイミングで実行させればよいらしい。また、「audio.load();」は書かなくても再生するようだ。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    <SOURCE src="sample.ogg" type="audio/ogg">
    </AUDIO>
    <FORM name="musicform">
    <INPUT name="playbutton" type="button" value="再生">
    </FORM>
    <SCRIPT>
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.play();
    }, false);

    </SCRIPT>
    </BODY>
    </HTML>


    …あれ?ならない。

    Interenet Explorerで[F12]キーを押してコンソールを出したり消したりしていたせいか、「Webページエラー」なるダイアログが表示されるようになった。そして、次のように表示された。

    行: 16
    エラー: 未定義または NULL 参照のプロパティ 'addEventListener' は取得できません


    どうやら、「HTMLのname属性とid属性の違いについて」で質問された方と同じミスをしていたらしい。

    <INPUT name="abc"> なら getElementsByName

    <INPUT id="abc"> なら getElementById

    と使いわけなければならない。

    さらに(私にとってとてもありがたい)その返答を読み進めると、どうやら「getElementsByName」は配列扱いで、何番目の要素かを調べなければならないそうなので、「name」より「id」を使った方が分かりやすく作れそう。

    <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>練習</TITLE></HEAD>
    <BODY>
    音楽再生<BR>
    <AUDIO id="music">
    <SOURCE src="sample.m4a" type="audio/mpeg">
    <SOURCE src="sample.ogg" type="audio/ogg">
    </AUDIO>
    <FORM name="musicform">
    <INPUT id="playbutton" type="button" value="再生">
    </FORM>
    <SCRIPT>
    var audio = document.getElementById("music");
    var button = document.getElementById("playbutton");
    button.addEventListener("click",function() {
      audio.play();
    }, false);

    </SCRIPT>
    </BODY>
    </HTML>


    結果はこんな感じ。

    音楽再生


    このHTMLファイルを Windows + Internet Explorer で動作確認できた。

    しかし、このページに埋め込んだところ、なぜかInternet Explorerでは再生できない。OperaとGoogle Chromeでは再生できた。…謎である。

    また、やはり iPad + FileExplorer では、HTMLが表示されても音が出ない。

    あれこれ試した結果、WindowsPCの共有フォルダからFileExplorerを使ってiPadの「ローカル」内にHTMLファイルと音声データを保存し、保存したHTMLファイルを開くと音がなった。

    最終的にはHTMLファイルをiPadに入れて持ち歩く予定だったが、音声ファイルを扱うJavaScriptを含むHTMLファイルをWindowsPCで作成したときは、毎回iPad内にコピーをする必要があることがわかった。

    FileExplorerを使用して、更新前のファイルが存在する状態で更新したHTMLファイルをコピーをすると、iPad内で新しいファイルに連番をつけて保存してしまう仕様になっているようなので、保存前に古いファイルを消しておかなくてはならない。

    現時点でのFileExplorerでは、ファイル名の変更ができないようだ。

    とにかく、JavaScriptを使ってiPadでも音声ファイルを再生することができた。


    calendar

    S M T W T F S
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
    << July 2017 >>

    selected entries

    categories

    archives

    links

    profile

    書いた記事数:84 最後に更新した日:2016/09/11

    search this site.

    others

    mobile

    qrcode

    powered

    無料ブログ作成サービス JUGEM