音の鳴るブログ

鳴らないこともある

timbre.js の使い方メモ: ended イベント

あたらしい timbre.js のドキュメントのドラフトみたいな感じで書く。第三弾。

あたらしいtimbre.jsではいくつかインターフェイスの変更があったのだけど、そのひとつが on メソッドで、以前の timbre.js は off と組み合わせてオブジェクトの ON/OFF(エフェクターの効果を有効にしたり無効にしたりとか)に使っていたのだけど、あたらしいtimbre.js では jQuery や node.js にならってイベントエミッター用のインターフェイスになった。
on 以外には以下のものがある( off はなくなった。)

  • addListener(type, function)
  • removeListener(type, function)
  • removeAllListeners(type)

* on と addListener は同じ

その中で最も使うのが ended イベントで、使い方を知らないと困る場合があるので書く。

ended: 終わった時に呼び出される

何が終わったときかというと、音の持続とかそういう非常に長い非同期処理が終わった時に呼ばれて待機状態になる。オブジェクトは待機になった後も動作し続けるので、停止させたいときは明示的に書かないといけない。でないと処理が非常に重たくなる場合がある。

主だったものを列挙する。

T("timeout") / T("interval")

timeout プロパティに設定した時間(msec) 後に ended イベントが呼ばれて待機状態になる。きちんと停止するには stop() を実行する。ちなみに待機中に bang() を呼ぶと初期状態から処理を再開する。

T("interval", {interval:100, timeout:10000}).on("ended", function() {
  this.stop();
}).start();

T("env")

エンベロープが終端に達したときに ended イベントが呼ばれて待機状態になる。きちんと停止するには puase() を実行する。ちなみに待機中に bang() を呼ぶと初期状態から処理を再開する。

T("perc", T("sin")).on("ended", function() {
  this.pause();
}).bang().play();

T("buffer") / T("audio") / T("tape")

バッファの再生が終わると ended イベントが呼ばれて待機状態になる。きちんと停止するには pause() を実行する。ちなみに待機中に bang() を呼ぶと初期状態から処理を再開する。

T("audio", {load:"sample.wav"}).on("ended", function() {
  this.pause();
}).play();

T("param")

linTo などで値を移動し終えたときに ended イベントが呼ばれて最終値を出力し続ける。

var sin = T("sin").play();

var param = T("param").on("ended", function() {
  param.linTo(Math.random() * 2000 + 200, 500);
}).setAt(440);

sin.freq = param;

T("mml")

MMLの終端が終わると(たとえば最後の2分音符がおわったときとか) ended イベントが呼ばれて待機状態になる。きちんと停止するには pause() を実行する。ちなみに待機中に bang() を呼ぶと初期状態から処理を再開する。

T("mml", {mml:"cegec2"}, T("OscGen").play()).on("ended", function() {
  this.stop();
  this.inputs[0].pause(); // OscGenの停止
}).start();

T("rec")

録音が終わると ended イベントが呼ばれて待機状態になる。きちんと停止するには pause() を実行する。ちなみに待機中に bang() を呼ぶと初期状態から処理を再開する。イベント時に渡される引数は録音した内容の SoundBuffer オブジェクト。

T("rec", T("noise")).on("ended, function(buffer) {
    this.stop();
}).start();

自動で止まれば良いんじゃないの?

なぜ自動で止まらないかというと、たとえば以下のようなコードの場合 perc の処理を終えたあと、コードの意図までは判断できないので、どうしたら良いのか判断できない。

var perc= T("perc", T("sin")).bang();

T("delay", perc).play();

そのため特に処理せず 0 で埋まったバッファを返したりするのだけど、そういうのがたまってくると 0 を 100回足し算して 0 を出力するみたいな状態になって処理が重たくなってしまうので、明示的に停止してやる。

T("audio").load("naruhodius.wav", function() {
  var audio= this;
  T("interval", {interval:1000}, function() {
    audio.clone().play().on("ended", function() {
        this.pause();
    });
  }).start();
});

ちなみに上記の場合、下記コードも似たような動作をするし、pause も使わないし、より軽量だけどモノフォニックになる。

T("audio").load("naruhodius.wav", function() {
  var audio= this.play();
  T("interval", {interval:1000}, function() {
    audio.clone().bang();
  }).start();
});

以前の on/off は?

以前の on / off に相当するものもあれば便利なはずだけど、どういう名前にするか迷っている。bypass とか through とかかなぁと思っているのだけど。。あと enabled とか。