Web Audio API でビープ音を作る・モールス信号を流してみる
ふと思い立って、モールス信号を流すツールが作れないか調べてみた。Web Audio API というのを使うと、簡単なビープ音程度であれば JavaScript で生成・再生できるようだったので、試してみた。
デモ
早速だが作ってみたモノ。↓
- デモ : Web Audio Beep Morse Code
- コード : frontend-sandboxes/index.html at master · Neos21/frontend-sandboxes
「Dit」ボタンを押すと短点 (トン)、「Dah」ボタンを押すと長点 (ツー) が再生されるはず。それぞれアクセスキーに t
と h
を設定してある。
「SOS」ボタンを押すと、Chrome ブラウザではちゃんと SOS のモールス信号が鳴るはず。iOS Safari だと上手く鳴らなかった…。この辺、制御方法がまだイマイチなんだろうな。
ビープ音の作り方
ビープ音の鳴らすためのコードは次のとおり。
const beep = options => new Promise(resolve => {
// Options
options = options || {};
const type = options.type == null ? 'sine' : options.type;
const frequency = options.frequency == null ? 440 : options.frequency;
const time = options.time == null ? 0.1 : options.time;
const volume = options.volume == null ? 0.1 : options.volume;
// Create
const audioContext = new window.AudioContext();
const oscillator = audioContext.createOscillator();
const gain = audioContext.createGain();
oscillator.connect(gain);
gain.connect(audioContext.destination);
// Set Options
oscillator.type = type;
oscillator.frequency.value = frequency;
gain.gain.value = volume;
// Start
oscillator.onended = () => {
gain.disconnect(audioContext.destination);
oscillator.disconnect(gain);
resolve();
};
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + time); // Stop Timing
});
作成した beep()
関数は連想配列でオプションを取れるようにしている。音声のタイプ、周波数、音量、音の長さを指定できる。
Web Audio API を扱うには、window.AudioContext()
でコンテキストというモノを作り、そこに波形を作る OscillatorNode
をくっつけたり、音量を操作する GainNode
をくっつけたりして音声を作っていく。
createOscillator()
で波形を調整するための OscillatorNode
を作る。波形のタイプは sine
・square
・sawtooth
・triangle
などが選べる。frequency
で周波数をヘルツ単位で指定できる。デフォルトは 440
になっているので、A の音が鳴ることになる。
- AudioContext.createOscillator() - Web API | MDN
- OscillatorNode - Web API | MDN
- OscillatorNode.type - Web APIs | MDN
- OscillatorNode.frequency - Web APIs | MDN
続いて、createGain()
で GainNode
を作り、これを使ってボリュームを調整する。大音量が鳴るとうるさいので、自分が作った beep()
関数ではデフォルトの音量を 10% (0.1
) にしている。
音声の再生は、OscillatorNode
の start()
関数と stop()
関数を使う。引数で再生する時刻を指定するのだが、window.AudioContext()
で生成したコンテキストが currentTime
という時刻情報を持っている。コレを利用すると、setTimeout()
や setInterval()
などを使うよりも正確に、再生開始のタイミング、再生停止のタイミングを設定できる。
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + time);
stop()
関数の方は、currentTime
にいくらか値をプラスすることで、「0.1秒だけ再生する」とか「2秒間再生する」みたいな設定ができる。
自作の beep()
関数は、onended
でコンテキストと Node の切断処理を一応入れて、Promise を解決するようにしてみた。Promise 形式にしたら、色んなビープ音を連続して実装しやすいかなと思ったためだ。
自作の sos()
関数は、この beep()
関数を使って「SOS」のモールス信号を組み立ててみている。iOS Safari では最初の短点しか再生されないので、どうも Promise での扱いだと微妙らしい。この辺よく分からないが、まぁいいかと思ってココまでとしている。w