[ Jpn | Eng ]

Main Menu



Recent

最近の記事

Search

サイト内検索:

Archive

Powered by
MTOS 5.2.2


g200kg > Web Audio API 解説 > 03.オシレーターの使い方

Web Audio API 解説

2016/11/14

03.オシレーターの使い方



パラメータの指定

オシレーターには周波数の指定や波形の指定などのパラメータがありますので、これらを設定できるようにしてみます。HTML側には波形、周波数、レベルを設定するフォーム(type / freq / level)があるという想定です。

ノードの接続は osc => gain => destination となっていて、typeとfreqはoscを、levelはgainをコントロールします。

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Oscillator</h1>
<img src="images/osc2.png"/>
<table>
<tr><td>Type</td><td><select id="type" onchange="Setup()"><option value="sine">Sine</option><option value="square">Square</option><option value="sawtooth">SawTooth</option><option value="triangle">Triangle</option></select></td></tr>
<tr><td>Freq(Hz)</td><td><input type="range" min="50" max="5000" size="10" id="freq" value="440" onchange="Setup()"/></td></tr>
<tr><td>Level</td><td><input type="range" min="0" max="1" step="0.01" size="10" id="level" value="1" onchange="Setup()"/></td></tr>
</table>
<br/>
<button onclick="Setup()">Play</button><br/>
<script type="text/javascript">

window.AudioContext = window.webkitAudioContext||window.AudioContext;
var audioctx = new AudioContext();

var play=0;
var osc = audioctx.createOscillator();
var gain = audioctx.createGain();
osc.connect(gain);
gain.connect(audioctx.destination);

function Setup() {
	if(play == 0) {
		osc.start();
		play = 1;
	}
	var type = document.getElementById("type").value;
	var freq = parseFloat(document.getElementById("freq").value);
	var level = parseFloat(document.getElementById("level").value);

	osc.type = type;
	osc.frequency.value = freq;
	gain.gain.value = level;
}

</script>
</body>
</html>

なお、波形の指定(type)の内、5番目の "custom" は単純に波形を指定するのではなく、倍音のスペクトラムを指定するという凝った仕様になっているのですが、使い方が違いますのでこちらを参照ください⇒オシレータのカスタム波形

テストページ:オシレーターの使い方

パラメータの多くはAudioParamというオブジェクトになっていて、直接値を代入するのではなく.valueプロパティに値を設定します。ただしパラメータによっては直接値を入れるものもありますので仕様書で確認が必要です (16.各ノードのパラメータ一覧に一覧にしてありますので参照してください)


オシレーターのパラメータ

パラメータ単位デフォルト値値の範囲内容
type文字列-"sine""sine"
"square"
"sawtooth"
"triangle"
"custom"
波形の指定
"sine" : サイン波
"square" : 矩形波
"sawtooth":鋸歯状波
"triangle":三角波
"custom":カスタム(直接指定できない)
frequencyAudioParamHz440-ナイキスト周波数

+ナイキスト周波数
周波数の指定。範囲の「ナイキスト周波数」はサンプリング周波数の1/2で、大抵のブラウザ実装では22050となります。周波数に負の値を設定すると位相が反転します。
このパラメータは a-rate です。
detuneAudioParamセント0-∞ ~ +∞デチューン。本来の周波数からずらします。単位の「セント」は半音の1/100を表し、1200で1オクターブとなります。
このパラメータは a-rate です。
start(when)
旧:noteOn
関数---再生開始。whenは開始時刻(秒)
stop(when)
旧:noteOff
関数---再生停止。whenは停止時刻(秒)
setPeriodicWave
(PeriodicWave)
関数---カスタム波形の指定


オシレーターのstart() / stop()

最初の例ではオシレータを作ってstart()する事で信号を出しましたが音を止める時にはstop()というメソッドを呼びます。しかし、ここで誤解されやすそうな仕様があって、一度stop()して止めたオシレータはもう二度と音を出す事はできません。

これはワンショットサンプルなどの音源として使うAudioBufferSourceでも同じで一度 start()して再生し終わるかstop()で止めるともうそのAudioBufferSourceは使えなくなります。というのもOscillatorやAudioBufferSourceは使い捨てで1音出す度にどんどん新しいオブジェクトを作っては再生して捨てる、というような使い方を想定しているんですね。MIDIで言うNoteOn/NoteOffの組がひとつのオブジェクトに相当しているような感じです。AudioBufferSourceはともかく「Oscillator」という名前はどうかなあと思わなくもないですが。

もちろん1つ作ったものを再生しっぱなしで確保しておいて後ろに繋げたGainでゲートする事はできます。アプリケーションにもよりますが、楽器系のアプリでOscillatorを使う場合はそういう形が多くなるのではないかと思います。


オシレーターのタイミング制御

オシレータを動かす際に今までは start() という関数を呼び出していましたが、この関数は引数を取る事ができ、動作を開始する時刻を指定できます。 時刻が過去の場合、例えば 0 を指定すると関数が呼び出されたら即時に動作を開始する事を意味していますが、現在の時刻はオーディオコンテキストのプロパティ .currentTime にありますのでこれを基準にあらかじめ動作の時刻を指定する事ができます。例えば、start(audioctx.currentTime + 1) ならば今から1秒後にオシレータが作動します。

実際のアプリ開発で実用的なものを作ろうとした場合、リズムがヨタらない演奏をするには時刻を指定する事が推奨されます。というのもこの時刻による制御によらないとすると Javascript の setInterval() などでタイミングを決める事になりますが、これだと処理が重くなって発音が遅れたりすることが普通に起こります。

下の例では Setup() が呼ばれた時にあらかじめ必要なオシレータと時刻を設定してしまいます。0.5秒ごとに0.1秒の長さの音を出すオシレータを10個作っています。基準となる時刻はSetup()が呼ばれた時の時刻 t0 で常にここからの計算になっている事が重要です。


<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Oscillator Timing Control</h1>
<br/>
<img src="images/osctiming.png"/><br/>
<button onclick="Setup()">Start</button><br/>
<script type="text/javascript">

window.AudioContext = window.webkitAudioContext||window.AudioContext;
var audioctx = new AudioContext();

function Setup() {
	var t0 = audioctx.currentTime;
	for(var i = 0; i < 10; ++i) {
		var osc = audioctx.createOscillator();
		osc.connect(audioctx.destination);
		osc.start(t0 + i * 0.5 + 0.5);
		osc.stop(t0 + i * 0.5 + 0.6);
	}
}

</script>
</body>
</html>
テストページ:オシレーターのタイミング制御

もっと実用的な実装にするには

なお、このようにあらかじめタイミングを予約する事ができるからと言って、あまりに大量の予約を詰め込む事は推奨されていません。発音の予定を組んでしまった分はユーザーの操作に反応できなくなっちゃいますしね。

じゃあどうするかと言うと、この記事「A Tale of Two Clocks - Scheduling Web Audio with Precision」に詳しいのですが、setInterval()やsetTimeout()のようなタイマーである程度発音すべき情報を先読みしつつ、ちょっと先の予定までstart()のスケジューリング機能で予定を組む、という合わせ技が必要になります。大体数十mSec間隔程度のタイマーで予定を組みながら動作する、というのがWeb Audio APIが想定している動作のようです。




g200kg