JavaScriptでメトロノーム作ってみた

# はじめに
日々の業務を振り返っていて、ふと気づいたことがあります。それは、「動画プレイヤー以外で音を鳴らしたことがない」ということです！
音楽を趣味でやっているにも関わらず、これは一大事。

そこで、今回は音楽の練習に欠かせないメトロノームをJavaScriptを使って作ってみようと思います。
今回使う音を鳴らす技術を活用すれば、みなさんが作っているWebアプリケーションのあんなところやこんなところでも自由に音を鳴らすことができるかもしれません。
ただ、全然脈絡なく音が鳴るアプリケーションを作ると、偉い人に怒られるかもしれないので、用法用量を守ってお使いください。

# JavaScriptで音を鳴らす
さっそくJavaScriptを使って音を鳴らしてみます。
Web Audio APIを使い、単純なクリック音が鳴るようにしました。
`oscillator.frequency.value`（音の周波数）やスタートからストップまでの持続時間の設定等を変えることで、鳴らす音を変更することが可能です。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="wvbZmoG" data-pen-title="JavaScript_beep" data-user="szdqiygj-the-sasster" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/szdqiygj-the-sasster/pen/wvbZmoG">
  JavaScript_beep</a> by maabow (<a href="https://codepen.io/szdqiygj-the-sasster">@szdqiygj-the-sasster</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# ループ再生/停止できるようにする
次に、一定間隔でループ再生できるようにし、再生と停止の機能を追加します。これにより、メトロノームとしての基本的な動作が実現します。
再生ボタンを連続で押した際に、再生中の音が重複しないように、停止操作を必ず入れるようにしてください。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="KKLYoqv" data-pen-title="JavaScript_Metronome_Simple" data-user="szdqiygj-the-sasster" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/szdqiygj-the-sasster/pen/KKLYoqv">
  JavaScript_Metronome_Simple</a> by maabow (<a href="https://codepen.io/szdqiygj-the-sasster">@szdqiygj-the-sasster</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# テンポ調整機能を作る
今のままだとBPM100の固定テンポでしか利用できないため、実用的ではありません。
そこで、テンポを増減させる機能を追加し、さまざまなテンポに対応できるようにします。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="jOojxRp" data-pen-title="JavaScript_Metronome_Tempo" data-user="szdqiygj-the-sasster" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/szdqiygj-the-sasster/pen/jOojxRp">
  JavaScript_Metronome_Tempo</a> by maabow (<a href="https://codepen.io/szdqiygj-the-sasster">@szdqiygj-the-sasster</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 見た目を整える
HTMLとCSSを使ってメトロノームの見た目を整えます。
直感的なインターフェースを提供することで、使いやすさが向上します。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ZENdRYZ" data-pen-title="JavaScript_Metronome_Normal" data-user="szdqiygj-the-sasster" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/szdqiygj-the-sasster/pen/ZENdRYZ">
  JavaScript_Metronome_Normal</a> by maabow (<a href="https://codepen.io/szdqiygj-the-sasster">@szdqiygj-the-sasster</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# さらに使い勝手を良くする
楽しくなってきたので、もう少しだけ作り込んでいこうと思います。
ユーザビリティを向上させるために、リズムパターンの切り替え、テンポ調整のスライダーを追加しました。また、`requestAnimationFrame`を利用することで再生中にテンポを切り替えてもスムーズに再生が続くようにしました。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="pomXKBo" data-pen-title="JavaScript_Metronome_Full" data-user="szdqiygj-the-sasster" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/szdqiygj-the-sasster/pen/pomXKBo">
  JavaScript_Metronome_Full</a> by maabow (<a href="https://codepen.io/szdqiygj-the-sasster">@szdqiygj-the-sasster</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

そのほかにも、テンポに合わせて光るビジュアルエフェクトの追加や、クリック音のバリエーションを増やすなどの機能も考えられます。
これらの機能を追加することで、より多くのユーザーにとって使いやすいプロダクトになっていきます。
みなさんもぜひ、さまざまなアイデアを試してみてください

# まとめ
初めて動画プレイヤー以外の音を鳴らすアプリケーションを作ることができて満足しました。
今回はメトロノームを作りましたが、Web Audio APIを使った音生成や、JavaScriptでの機能実装部分を応用すれば、さまざまなアプリケーションに音の要素を取り入れることができます。音楽系のアプリだけでなく、ゲームや語学系のアプリを作ってみるのも面白いかもしれませんね。
ぜひ、皆さんも挑戦してみてください！

# 参考
[ウェブオーディオ API](https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API)
[Window.requestAnimationFrame()](https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame)