JSFiddle - React, Tailwind, and code Playground
JavaScript
'use strict';
// Web Audio APIを利用するためのインスタンス生成
var audioContext = new AudioContext();
// キーごとにMIDIノートナンバーを割り振る
var keymap = {
// Zキー = C4
90: 60,
// Sキー = C#4
83: 61,
// Xキー = D4
88: 62,
// Dキー = D#4
68: 63,
// Cキー = E4
67: 64,
// Vキー = F4
86: 65,
// Gキー = F#4
71: 66,
// Bキー = G4
66: 67,
// Hキー = G#4
72: 68,
// Nキー = A4
78: 69,
// Jキー = A#4
74: 70,
// Mキー = B4
77: 71,
// ,キー = C5
188: 72
};
// キーダウンした際の処理
document.onkeydown = function(keyDownEvent) {
// キー押しっぱなしの状態で発火した場合は、動作を終了する
if (keyDownEvent.repeat === true) {
return;
}
// オシレーターを作成
var osciillatorNode = audioContext.createOscillator();
// エンベロープジェネレーターを作成
var envelopeGen = audioContext.createGain();
// MIDIノートナンバーを周波数に変換
var freq = 440.0 * Math.pow(2.0, (keymap[keyDownEvent.keyCode] - 69.0) / 12.0);
// オシレーターの周波数を決定
osciillatorNode.frequency.value = freq;
// オシレーターをエンベロープジェネレーターに接続
osciillatorNode.connect(envelopeGen);
// エンベロープジェネレーターを最終出力にx接続
envelopeGen.connect(audioContext.destination);
// 現在の時間を取得
var t1 = audioContext.currentTime;
envelopeGen.gain.cancelScheduledValues(t1);
envelopeGen.gain.setValueAtTime(1, t1);
// オシレーター動作
osciillatorNode.start();
// キーを離した際に音が止まるよう、イベントを登録する
document.addEventListener('keyup', checkKeyUp);
// キーを離したかどうかチェック
function checkKeyUp(keyUpEvent) {
var release = 0.01;
// 離したキーが、押下したキーで無い場合は処理を行わない
if (keyUpEvent.keyCode !== keyDownEvent.keyCode) {
return;
}
var keyUpTime = audioContext.currentTime;
// キーをリリースした後にクリック音がなるのを防ぐため、現在の音量をセットする
envelopeGen.gain.setValueAtTime(envelopeGen.gain.value, keyUpTime);
envelopeGen.gain.linearRampToValueAtTime(0, keyUpTime + release);
// オシレーターを停止する
osciillatorNode.stop(keyUpTime + release);
// 自身のイベントを削除
removeEventListener('keyup', checkKeyUp);
}
};