ピアノの88の鍵盤の音の周波数を表にまとめ、Web Audio APIのOscillatorNodeで出力するようにしました。
音の周波数は1オクターブで2倍になり、1オクターブ内の12の音の周波数は $\sqrt[12]{2}=2^{\frac1{12}}$ 倍ずつ高くなります。そのため、A4(4オクターブ目のラ)の音を440Hzとすると、88の鍵盤のうちn番目の鍵盤の音の周波数は下記の式で表されます。
\[f(n) = 27.5 \cdot 2^{\frac{n-1}{12}}\]
上記の式の27.5HzはA0(0オクターブ目のラ)の音の周波数です。1オクターブ下がると音の周波数は半分になるため、A4(4オクターブ目のラ)の音を440Hzとすると、A3は220Hz、A2は110Hz、A1は55Hz、A0は27.5Hzになります。
下記の表はJavaScriptで生成しました。音はピアノの音ではなく、Web Audio APIのOscillatorNodeで波形パラメータに正弦波を指定して出力しています。
ボタンをクリックすると音が流れます。音量(特に周波数の高い音)に注意してください。
ボタンをもう一度クリックすると音が消えます。
上の表は下記のJavaScriptで生成しました。Bootstrap (v5.0.2)を使用しています。また、数式を表示するWordPressのプラグインSimple MathJaxを使用して$\flat$を表示しています。
<script type="text/javascript"> // ------------------------------------------------------- // Output Table // ------------------------------------------------------- const key_names = [ ["ラ", "", "A", ""], ["ラ#", "シ$\\flat$", "A#", "B$\\flat$"], ["シ", "","B", ""], ["ド", "","C", ""], ["ド#", "レ$\\flat$","C#", "D$\\flat$"], ["レ", "","D", ""], ["レ#", "ミ$\\flat$","D#", "E$\\flat$"], ["ミ", "","E", ""], ["ファ", "","F", ""], ["ファ#", "ソ$\\flat$","F#", "G$\\flat$"], ["ソ", "", "G", ""], ["ソ#", "ラ$\\flat$", "G#", "A$\\flat$"] ]; let table_html = "<table class='table table-striped'>"; table_html += "<tr>"; table_html += "<td>鍵盤番号</td>"; table_html += "<td>周波数(Hz)</td>"; table_html += "<td colspan='4'>音階名</td>"; table_html += "<td>音を聴く</td>"; table_html += "</tr>"; for (n = 0; n < 88; n++) { const frequency = getAudioFrequency(n); let octave = parseInt(n/12); if (n % 12 >= 3) { octave++; } const key_japanese = key_names[n % 12][0] + octave; let key_japanese_flat = ""; if (key_names[n % 12][1] != "") { key_japanese_flat = key_names[n % 12][1] + octave; } const key_english = key_names[n % 12][2] + octave; let key_english_flat = ""; if (key_names[n % 12][3] != "") { key_english_flat = key_names[n % 12][3] + octave; } const button_id = "start-stop-oscillator-" + n; const button = "<button class='btn btn-warning' id='" + button_id + "'/>"; const keyboard_number = n + 1; table_html += "<tr>"; table_html += "<td>" + keyboard_number + "</td>"; table_html += "<td>" + frequency.toFixed(3) + "</td>"; table_html += "<td>" + key_japanese + "</td>"; table_html += "<td>" + key_japanese_flat + "</td>"; table_html += "<td>" + key_english + "</td>"; table_html += "<td>" + key_english_flat + "</td>"; table_html += "<td>" + button + "</td>" table_html += "</tr>"; } table_html += "</table>"; document.getElementById('piano-keys-table').innerHTML = table_html; // ------------------------------------------------------- // Codes for Web Audio API // ------------------------------------------------------- // create web audio api context const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const oscillatorMap = new Map(); const isPlayingMap = new Map(); for (n = 0; n < 88; n++) { const frequency = getAudioFrequency(n); const buttonText = 'audio (sine, ' + frequency.toFixed(3) + 'Hz)'; const button_id = "start-stop-oscillator-" + n; CreateAudioOscillator(buttonText, button_id, 'sine', frequency); } // ------------------------------------------------------- // functions // ------------------------------------------------------- function getAudioFrequency(n) { return 27.5 * ( Math.pow( Math.pow(2, 1/12), n) ); } function CreateAudioOscillator(buttonText, buttonID, oscillatorType, frequency) { const button = document.getElementById(buttonID); button.textContent = buttonText; button.addEventListener("click", () => { let oscillator = oscillatorMap.get(buttonID); let isPlaying = isPlayingMap.get(buttonID); if (isPlaying === undefined) { isPlaying = false; } if (isPlaying === false) { oscillator = audioCtx.createOscillator(); oscillator.type = oscillatorType; oscillator.frequency.setValueAtTime(frequency, audioCtx.currentTime); oscillator.connect(audioCtx.destination); oscillator.start(); isPlaying = true; button.textContent = buttonText + " - playing"; } else { oscillator.stop(); isPlaying = false; button.textContent = buttonText; } oscillatorMap.set(buttonID, oscillator); isPlayingMap.set(buttonID, isPlaying); }); } </script>