プログラム日記φ(..)

おもにPython関係のプログラムメモ

「Tone.js」で88鍵ピアノ(HTML5 JavaScript Piano)を作ってみる

前回

1オクターブ+1鍵の13鍵ピアノを「Tone.js」で作ってみましたが、

 

memomemokun.hateblo.jp

 

これから模擬的にブログで音を鳴らすのに、1オクターブでは音域が狭いので、「Tone.js」を使い、88鍵のフルピアノ(HTML5 JavaScript Piano)を作ってみました。

 

こんな感じ。ブログのレイアウト上+鍵盤を1行で表示するには記事内のエリアだけでは幅が狭すぎるので、88鍵の鍵盤が自動改行されてますがご容赦を。

    上の鍵盤は、以下のHTML + JavaScript + CSS からなっています。

    <div>
      <ul id="piano">
      </ul>
    </div>
    
    <style type="text/css">
    <!--
    ul {
      width: 100%;
      margin: 0 auto;
      padding: 0 0;
      position: relative;
      text-align: center;
    }
    li {
      display: inline-block;
      border: 1px solid black;
      height: 80px;
    }
    .whitekey {
      background: white;
    }
    .blackkey {
      background: black;
      position: absolute;
      margin: 0px 0 0px -10px;
      border-left: 2px solid white;
      border-bot: 2px solid white;
    }
    
    .whitekey:hover {
      background-color: #ddd;
    }
    .blackkey:hover {
      background-color: #555;
    }
    -->
    </style>
    
    
    <script src="http://chamu.org/tonejs/Tone.min.js"></script>
    <script>
    var synth;
    
    // ページ読み込み時pianoを生成
    document.addEventListener("DOMContentLoaded", (e) => {
    
      // シンセサイザーを生成
      synth = new Tone.Synth({
        // 発振器の設定
        oscillator:{
            type:"triangle8"
        },
        // エンベロープ(包絡線)の設定
        envelope:{
            attack:0.005,  // 最大音量アタック・レベル(Attack Level)に達する時間
            decay:0.1,     // 一定音量まで減衰(Decay)する時間
            sustain:0.4,   // 一定振幅(Sustain Level)が続く時間
            release:2      // 音が消えるまでの時間
        }
    }).toMaster();
    
      // 鍵盤を表示
      const totalWidth = window.innerWidth;
      const height = 140;
      
      const allNotes = 
            [
              "A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8"
            ];
      
      const sizePerNote = (totalWidth / allNotes.length)*1.5;
    
      const piano = document.getElementById('piano'); 
    
      
      for (let i = 0; i < allNotes.length ; i++) {
        var currentNote = allNotes[i];
        var node = document.createElement("li"); 
        node.className = 'whitekey';
        node.style.height = height + "px";
        node.style.width = sizePerNote + "px";
        if (~currentNote.indexOf("#")) {
          node.className = 'blackkey';
          node.style.width = sizePerNote/1.6 + "px";
          node.style.height = height/1.6 + "px";
        }
        node.setAttribute('data-key', currentNote);
        piano.appendChild(node); 
      }
      
    });
    
    
    // 鍵盤でマウスが押されたら音を鳴らす
    document.querySelector('#piano').addEventListener('mousedown', e => {
      key = e.target.dataset.key
      synth.triggerAttackRelease(key);
    })
    
    // 鍵盤で押されたマウスが離されたら音を消す
    document.querySelector('#piano').addEventListener('mouseup', e => {
      key = e.target.dataset.key
      synth.triggerRelease();
    })
    
    </script>