簡易ピアノアプリの開発③

簡易自動演奏Webアプリの開発の忘備録です

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web簡易ピアノ</title>
  <style>
    
    .piano {
      width: 600px;
      height:300px;
      margin-top:20px;
      background-color:#FFF;
      padding-top:20px;
      
    }

    .piano .music {
      width:400px;
      height:100px;
      background-color: #F799FF;
      padding-top:30px;
      margin-top:20px;
      margin:auto;
    }

    .music #display {
      width:95%;
      text-align:center;
      font-size:40px;
      color:#0031FF;
    }

    .keyboard {
      width:490px;
      height:80px;
      background-color:#FFF;
      margin:20px auto;
      display:flex;
    }
    .keyboard .key {
      width:calc(100% / 6 - 10px);
      height:40px;
      padding-top:10px;
      margin-left:5px;
      margin-right:5px;
      border-radius:2px #00F;
      background-color:#FAA;
      text-align: center;
      font-size:18px;
      
      
    }

    .button1 {
      width:300px;
      height:50px;
      background-color:#FFF;
      margin:10px auto;
      display:flex; 
    }

    .button1 .but1 {
      width:calc(100% - 20px);
      height:35px;
      padding-top:8px;
      padding-left:8px;
      margin-left:5px;
      margin-right:5px;
      border-radius:2px #000;
      background-color:#0AA;
      color:#80F;
      text-align: center;
      font-size:15px;
    }

    
  </style>
</head>
<body>
  <!-- 簡易ピアノ -->
  <div class="piano">
    <!-- 音名表示 -->
    <div class="music">
      <h1 id="display"></h1>
    </div>
    <!-- キーボード表示 -->
    <div class="keyboard">
      <div id="C4" class="key">ド</div>
      <div id="D4" class="key">レ</div>
      <div id="E4" class="key">ミ</div>
      <div id="F4" class="key">ファ</div>
      <div id="G4" class="key">ソ</div>
      <div id="A4" class="key">ラ</div>
      <div id="B4" class="key">シ</div>
    </div>  
    <div class="button1">
      <input type="button" id="autoplay" name="autoplay" class="but1" value="自動演奏">
      <input type="button" id="autostop" name="autostop" class="but1" value="演奏中止">
    </div>
  </div>  
  <script>
      // AudioContext オブジェクトを新しく作成
      var audioCtx;
      // ド(C4)～ド(B5)までのIDからオブジェクトを取得する
      const C4 = document.getElementById('C4');
      const D4 = document.getElementById('D4');
      const E4 = document.getElementById('E4');
      const F4 = document.getElementById('F4');
      const G4 = document.getElementById('G4');
      const A4 = document.getElementById('A4');
      const B4 = document.getElementById('B4');
      // 自動演奏ボタンの定義
      const autoplay = document.getElementById('autoplay');
      // 演奏中止ボタンのオブジェクトを取得する
      const autostop = document.getElementById('autostop');
      autostop.style.display = 'none';
      // 音階を格納する配列を定義する
      const sound_array = ['ド','レ','ミ','ファ','ソ','ラ','シ'];
      // 周波数を格納する配列を定義する
      const hz_array = [261,293,329,349,392,440,493,1];
      // 音階表示エリアのオブジェクトを定義する
      const display = document.getElementById('display');
      // タイマー変数の定義
      let timer;
      // 作動時間の制御
      let work_time = 0;
      // 音を鳴らす時間の設定
      let playing_seconds = 1500;
      // 音階を表示する時間
      let display_seconds = 1000;
      // きらきら星の音階
      const kirakira = [
                        '0/500',
                        '7/500',
                        '0/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '5/500',
                        '7/500',
                        '5/500',
                        '7/500',
                        '4/2000',
                        '3/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '1/500',
                        '7/500',
                        '1/500',
                        '7/500',
                        '0/2000',
                        '4/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '1/2000',
                        '4/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '1/2000',
                        '0/500',
                        '7/500',
                        '0/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '4/500',
                        '7/500',
                        '5/500',
                        '7/500',
                        '5/500',
                        '7/500',
                        '4/2000',
                        '3/500',
                        '7/500',
                        '3/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '2/500',
                        '7/500',
                        '1/500',
                        '7/500',
                        '1/500',
                        '7/500',
                        '1/4000'
                      ];
      // チューリップの音階
      const tyuri = [   
                    '0/500',
                    '1/500',
                    '2/1000',
                    '0/500',
                    '1/500',
                    '2/1000',
                    '4/500',
                    '2/500',
                    '1/500',
                    '0/500',
                    '1/500',
                    '2/500',
                    '1/1000',
                    '0/500',
                    '1/500',
                    '2/1000',
                    '0/500',
                    '1/500',
                    '2/1000',
                    '4/500',
                    '2/500',
                    '1/500',
                    '0/500',
                    '1/500',
                    '2/500',
                    '0/1000',
                    '4/250',
                    '7/250',
                    '4/250',
                    '7/250',
                    '2/250',
                    '7/250',
                    '4/250',
                    '7/250',
                    '5/250',
                    '7/250',
                    '5/250',
                    '7/250',
                    '4/1000',
                    '2/250',
                    '7/250',
                    '2/250',
                    '7/250',
                    '1/250',
                    '7/250',
                    '1/250',
                    '7/250',
                    '0/4000'
                ];
      //作業用配列
      var array3; 
         
      function play(music1,hz,test_time){
            audioCtx = new AudioContext();
            // 正弦波の音を作成
            let osc = audioCtx.createOscillator();   
            //ヘルツ（周波数）指定
            osc.frequency.value = parseInt(hz);
            //音の出力先
            var audioDestination = audioCtx.destination;
            //出力先のスピーカーに接続
            osc.connect(audioDestination);
            
            timer = setInterval(osc.start(),250);
            
            
            if (music1 !== null){
              display.textContent = music1;
              setTimeout(function() {
                    display.textContent = "";
              },display_seconds);
            }  
            sleep(test_time);     
            clearInterval(timer);
            osc.stop();
            
      }

      function sleep(time1) {
        const d1 = new Date();
        while (true){
            const d2 = new Date();
            if (d2 - d1 >= time1){
               break;
            }
        }
      }
           

      // ピアノの音階をクリック
      C4.addEventListener('click',function() {
          const d = sound_array[0];
          const h = hz_array[0];
          play(d,h,playing_seconds);
      },false);

      D4.addEventListener('click',function() {
        const d = sound_array[1];
        const h = hz_array[1];
        play(d,h,playing_seconds);
      },false);
          
      E4.addEventListener('click',function() {
        const d = sound_array[2];
        const h = hz_array[2];
        play(d,h,playing_seconds);
      },false);
          
      F4.addEventListener('click',function() {
        const d = sound_array[3];
        const h = hz_array[3];
        play(d,h,playing_seconds);
      },false);
          
      G4.addEventListener('click',function() {
        const d = sound_array[4];
        const h = hz_array[4];
        play(d,h,playing_seconds);
      },false);
          
      A4.addEventListener('click',function() {
        const d = sound_array[5];
        const h = hz_array[5];
        play(d,h,playing_seconds);
      },false);
          
      B4.addEventListener('click',function() {
        const d = sound_array[6];
        const h = hz_array[6];
        play(d,h,playing_seconds);
      },false);
          
      
          
      autoplay.addEventListener('click',function() {
        C4.style.visibility = 'hidden';
        D4.style.visibility = 'hidden';
        E4.style.visibility = 'hidden';
        F4.style.visibility = 'hidden';
        G4.style.visibility = 'hidden';
        A4.style.visibility = 'hidden';
        B4.style.visibility = 'hidden';
        display.textContent = "自動演奏";
        autoplay1();
      },false);    

      function autoplay1() {
        const random = Math.floor(Math.random() * 2);
        if (random == 0){
          array3 = kirakira;
        } else {
          array3 = tyuri;
        }
        
        
        for(let j=0;j<array3.length;j++){
              const array4 = array3[j].split('/');
              const number = array4[0];
              const playsec = array4[1];
              play(sound_array[number],hz_array[number],playsec);
        } 
        C4.style.visibility = 'visible';
        D4.style.visibility = 'visible';
        E4.style.visibility = 'visible';
        F4.style.visibility = 'visible';
        G4.style.visibility = 'visible';
        A4.style.visibility = 'visible';
        B4.style.visibility = 'visible';

      }

      

      function autostop1() {
            AudioContext().createOscillator().stop();
            clearInterval(timer);
      }      



  </script>
</body>
</html>
```

現在処理が重く、ブラウザの待機が大量に発生しています。