Javascriptで24行のピアノ:演奏したら音楽

携帯電話メーカーは誰かが薄い人で測定されますが、プログラマは短い人で測定され続けます。



また、この特別な自発的なコーディングコンペティションに参加することを決めました。彼女のミュージシャンの1人のフレーズを思い出しました。「演奏するなら、ピアノです。」 そして彼は決心した。 演奏する代わりに、ピアノを書きます。 そして書いた



私はすぐに予約します:私はミュージシャンではありません。私の音楽教育は、動揺したギターで数十人の泥棒の歌に限定されています。



それでは始めましょう。


クラシックピアノのキーボードは、A0(laサブカウンターオクターブ、音の周波数27.5 Hz)からC8(最大5オクターブ、周波数4186 Hz)の範囲をカバーする88個のキーで構成されています。 キーボードの各オクターブは、12のノートで構成されています。

CCシャープ 、D、 Cシャープ 、Mi、Fa、 Cシャープ 、ソルト、 Gシャープ 、A、 Aシャープ/ Bフラット 、C。 上段のキーは太字で強調表示され、通常キーボードでは黒です。



実際、1オクターブは次のようになります。



画像



鳴っている音の周波数の表を見るだけで、パターンが明らかになります。後続の各オクターブは、前のオクターブの2倍です。 したがって、次のことが言えます。



Nx = N1×2 x-1 、ここで:



式では、サブカウンターオクターブ(N0)の音の一部の音の周波数が人間の耳による聴覚のしきい値(<20 Hz)より低いため、N0の代わりにN1が表示されます。



音をきれいにするために、対照的な音の周波数のかなり正確な値が必要であり、そこから数え始めます。 実際には、ここにあります:



C:32.703、

C#:34.648、

D:36.708、

D#:38.891、

E:41.203、

F:43.654、

F#:46.249、

G:48.999、

G#:51.913、

A:55、

#:58.27、

B:61.735



これに基づいて、 "A4"



または"C5#"



の形式のキーの名前を持つ文字列を引数として受け取り、その音の周波数を返す関数を作成します。



 function play(key) { var controctave = { 'C': 32.703, '#': 34.648, 'D': 36.708, 'D#': 38.891, 'E': 41.203, 'F': 43.654, 'F#': 46.249, 'G': 48.999, 'G#': 51.913, 'A': 55, 'A#': 58.27, 'B': 61.735, }, note = key[0].toUpperCase(), octave = parseInt(key[1]), sharp = key[2] == '#' ? true : false; if (sharp) { return controctave[note + '#'] * Math.pow(2, octave-1); } else { return controctave[note] * Math.pow(2, octave-1); } }
      
      





そうそう、私たちは美しく書いているのではなく、まもなく書いています。 少し短くする:



 function play(key) { var controctave = { 'C': 32.703, '#': 34.648, 'D': 36.708, 'D#': 38.891, 'E': 41.203, 'F': 43.654, 'F#': 46.249, 'G': 48.999, 'G#': 51.913, 'A': 55, 'A#': 58.27, 'B': 61.735}; freq = key[2] == '#' ? controctave[key[0].toUpperCase() + '#'] * Math.pow(2, (key[1]|0) - 1) : controctave[key[0].toUpperCase()] * Math.pow(2, (key[1]|0) - 1); return freq; }
      
      







4行のコードがすでに使用されています。



キーボードを描きましょう


88個のキーボードキーはAノート(A0)で始まります。

したがって、サイクルは次のようになります。サイクルでは12個のキーを描画し、2、4、7、9、11 番目ごとに黒を作成します。 各キーには、押されたときに再生するノートに対応するIDが割り当てられます。



一般的に、このように:



 var width = 1000; var deck = document.createElement('div'), octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], id = "", keynumber = 0, whitekeys = 0, keys = []; deck.style.width = width; parent: for (var i = 0; i < 8; i++) { for (var j = 0; j < 12; j++) { keynumber = (i * 12) + j; if (keynumber >= 88) break parent; keys[keynumber] = document.createElement('div'); keys[keynumber].style.border = "1px solid black"; keys[keynumber].style.position = "absolute"; id = (octave[j][1] == '#') ? octave[j] + i + 's' : octave[j] + i; keys[keynumber].id = id; switch(j%12) { case 1: case 3: case 6: case 8: case 10: keys[keynumber].style.backgroundColor = 'black'; keys[keynumber].style.left = ((width / 50 * whitekeys) - (width / 200)) + 'px'; keys[keynumber].style.width = width/100 + "px"; keys[keynumber].style.height = "200px"; keys[keynumber].style.zIndex = 10; break; default: keys[keynumber].style.backgroundColor = 'white'; keys[keynumber].style.left = (width / 50 * whitekeys) + 'px'; keys[keynumber].style.width = width/50 + "px"; keys[keynumber].style.height = "300px"; whitekeys++; } deck.appendChild(keys[keynumber]); } } document.body.appendChild(deck);
      
      





繰り返しますが、通常のコードを読み取り不可能なものに変え、少し最適化適用します。



 var width = 1000, octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], id = "", div, whitekeys=0, keys = []; parent: for (var i = 0; i < 8; i++) { for (var j = 0; j < 12; j++) { if ((i * 12) + j >= 88) break parent; div = document.createElement('div'); div.id = (octave[j][1] == '#') ? octave[j][0] + ((((i * 12) + j + 9) / 12)|0) + 's' : octave[j] + ((((i * 12) + j + 9) / 12)|0); if (j % 12 == 1 || j % 12 == 4 || j % 12 == 6 || j % 12 == 9 || j % 12 == 11) { div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:black; left:' + ((width / 50 * whitekeys) - (width / 200)) + 'px; width:' + width/100 + 'px; height: 200px; z-index:1;');} else { div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:white; left:' + (width / 50 * whitekeys) + 'px; width:' + width/50 + 'px; height:300px;'); whitekeys++; } document.body.appendChild(div);}}
      
      







さらに13行を使い果たしました。



ピアノを教えて音を出す


これを行うには、 Web Audio APIが必要です。現時点では、WebkitベースのブラウザーとFirefoxでのみサポートされています。



オーディオコンテキストの作成をグローバル変数宣言行に追加します。

 context = window.AudioContext ? new AudioContext() : new webkitAudioContext();
      
      





キーストロークハンドラーを追加します。

 document.body.addEventListener('click', play);
      
      





プレイ機能自体を次のように変更します。

 function play(e) { var controctave = { 'C': 32.703, 'Cs': 34.648, 'D': 36.708, 'Ds': 38.891, 'E': 41.203, 'F': 43.654, 'Fs': 46.249, 'G': 48.999, 'Gs': 51.913, 'A': 55, 'As': 58.27, 'B': 61.735}, osc = context.createOscillator(); osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1); osc.type = "square"; osc.connect(context.destination); osc.start(0); setTimeout(function() { osc.stop(0); osc.disconnect(context.destination); }, 1000 / 2);}
      
      







ここでオシレーターを作成しました: osc = context.createOscillator();



、必要な音の​​周波数を設定します: osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1);



osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1);



(まあ、コードのクリーンさときれいさを監視しませんよね?)、波形を設定します: osc.type = "square";



(デフォルトでは正弦波でした)サウンド出力デバイスに接続しました: osc.connect(context.destination);



、再生を開始するコマンドを与えました: osc.start(0);



。 その後、しばらく(500ms)後にキーを無音にする必要があります。そうしないと、キーキーが鳴ります。 これを行うには、間隔にラップされたosc.stop(0)



使用します。 必須要素osc.disconnect(context.destination);



-出力デバイスから発振器を切断します。



要約すると、次のような簡単なコードが得られました。



 var width = 1000, octave = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'], id = "", div, whitekeys=0, keys = [],context = window.AudioContext ? new AudioContext() : new webkitAudioContext(); parent: for (var i = 0; i < 8; i++) { for (var j = 0; j < 12; j++) { if ((i * 12) + j >= 88) break parent; div = document.createElement('div'); div.id = (octave[j][1] == '#') ? octave[j][0] + ((((i * 12) + j + 9) / 12)|0) + 's' : octave[j] + ((((i * 12) + j + 9) / 12)|0); if (j % 12 == 1 || j % 12 == 4 || j % 12 == 6 || j % 12 == 9 || j % 12 == 11) { div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:black; left:' + ((width / 50 * whitekeys) - (width / 200)) + 'px; width:' + width/100 + 'px; height: 200px; z-index:1;');} else { div.setAttribute('style', 'border:1px solid black; position:absolute; background-color:white; left:' + (width / 50 * whitekeys) + 'px; width:' + width/50 + 'px; height:300px;'); whitekeys++; } document.body.appendChild(div);}} document.body.addEventListener('click', play); function play(e) { var controctave = { 'C': 32.703, 'Cs': 34.648, 'D': 36.708, 'Ds': 38.891, 'E': 41.203, 'F': 43.654, 'Fs': 46.249, 'G': 48.999, 'Gs': 51.913, 'A': 55, 'As': 58.27, 'B': 61.735}, osc = context.createOscillator(); osc.frequency.value = e.target.id[2] == 's' ? controctave[e.target.id[0] + 's'] * Math.pow(2, (e.target.id[1]|0) - 1) : controctave[e.target.id[0]] * Math.pow(2, (e.target.id[1]|0) - 1); osc.type = "square"; osc.connect(context.destination); osc.start(0); setTimeout(function() { osc.stop(0); osc.disconnect(context.destination); }, 1000 / 2);}
      
      







結論として、 21世紀のStradivarius Web Audio API を呼び出す必要があります-非常にクールで興味深いことです。 もちろん、 MDNでそれについて読むことができます。HTML5Rocksの素晴らしいチュートリアル別の楽しい実験をお勧めします。



そして、ピアノはひどく原始的でしたが、私はまだ実験に満足しています。 あなたも興味を持っていたと思います。



プレイする



コードを表示



たとえば、PS MacBookスピーカーは、小さなオクターブ(つまり、最大130 Hz)までの可聴音を出すことを拒否しますが、これは驚くことではありません。 一般に、キーボードの左側がまったく鳴っていないように見えても驚かないでください。



All Articles