ファミコンの音源は矩形波x2+三角波+ノイズという構成なんだけど、さらに矩形波にはデューティ比を変更させるという機能がある。 これをWebAudioで実現するにはどうしたらいいのかと考えていた。
仕組み
WebAudioにはオシレータで山と谷が等しい矩形波を生成することができるが、デューティ比を変更するような機能はない。 オシレータを使わずに自分で計算して作ったバッファに波形を構築してやればそういう波形も作れるけど、面倒なのでできればしたくない。 でどうしたものかと思っていたら、実現しているサイトを見つけた: Oscilloscope and Pulse-Width control
どうやっているのかソースを見てみると、ノコギリ波を組み合わせて実現していた。 通常のノコギリ波に加えて、ゲインを反転させてデューティ比に合わせてディレイさせたものを組み合わせると、波が打ち消しあって矩形波が作り出せるようだ。
デモ
ということでデモを作ってみた:
playボタンで再生開始して、「Duty cycle」のスライダー、または数値入力でデューティ比を変更できる。 またキャンバスをドラッグで周波数とボリュームを変更できる。
ソース
内容は結構簡単で、音源となるノコギリ波を発生させるオシレータを生成し、そのオシレータから分岐させてゲインを反転させてディレイさせたものをつなげる。 そしてそれぞれを全体のボリュームをいじるゲインノードにつなぎ、最終的な出力ノードにつなげる:
// [/|/|] |
ユーザの操作に従って周波数やボリューム、デューティ比を変更する:
function updateAudio() { |
雑感
- グラフでは赤と青のノコギリ波が打ち消し合うことを見やすくするため基準線を境に描いているが、実際にはWebAudioのノコギリ波は-1~+1の範囲
- Web Audio Demosのページでは合成した値の基準を合わせるため、直流成分を加えている。ただ、そのゲインを
1.7*(0.5-amt)
としているのがよくわからない…。 - Web Audio Demosのページで発生している音の波形を表示するのにAudioContext.createAnalyserでAnalyserNodeを作り周波数に分解し、またgetTimeDomainDataで波形そのものを取り出している。
追記
ドラクエで学ぶファミコン音色の時間変化 / NES tone technique - YouTube
正直、デューティ比変更を実装しなくても別にそれほど効果ないしわからないでしょ、と軽く見ていた人間でした。 機能があると追求して有効に使う人がいるんだなぁ…。