読者です 読者をやめる 読者になる 読者になる

3.SiONとDisplayObjectの連携

SiON ActionScript3

Flashでは(というか特殊なハードを介さない普通のPCアプリケーションでは),映像は描画したフレームで即出力されるのに対し,音は実際の発音より早いタイミングで合成しておく必要があります.このため,音を合成してから音の出力までには必ず遅延(レイテンシ)が発生します.
この遅延のため,ユーザーのアクションに反応する音は遅れ,音と同時に映像を処理すると映像が早くなります.現バージョンの Flash では理論上最短でも50ms程度の遅延が発生するため(実際にはもっと長い),早い反応が要求される音ゲのようなアプリケーションは,残念ながら作る事はできません.
このように,音の"合成"と"発音"は別々のタイミングで実行されるため,同期させるには何らかのギミックが必要になります.SiON では,"Synchronized Sequence", "Event Trigger" という2つの方法によって同期を行います.

Synchronized Sequence (DisplayObject に SiON を同期させる)

DisplayObject -> SiON の同期は,任意のタイミングで呼び出された発音コマンドについて,演奏中のビートと同期するように遅延して合成する事で実現します.この同期は,SiONDriver::noteOn(), SiONDriver::sequenceOn() の第4, 5引数の delay と quantize によって制御します.以下再掲.

  • 第4引数;delay:Number = 0; 音が出るまでの遅延を16分音符単位で指定します.第4引数と同様4分音符なら4,全音符なら16,32分音符なら0.5です.
  • 第5引数;quant:Number = 0; 音が出るタイミングをどの拍子にシンクロさせるかを16分音符単位で指定します.例えば4(4分音符)を指定すると4分拍子のタイミングに合わせて音を鳴らします.この時delay=2を指定すると4分拍子の8分音符後(つまり8beatの裏拍)になります.0を指定すると拍に関係なく最速で出音します.

これらはSiONDriver::play()で演奏しているシーケンスに同期します.また,null渡しでplay()を呼び出した場合は,SiONDriver::bpm プロパティで指定したテンポに同期します.

Event Trigger (SiON に DisplayObject を同期させる)

SiON では,発音のタイミングでイベントを発行する事で SiON -> DisplayObject の同期を行います.具体的には SiONDriver は ノート"オン"/"オフ"時に,音が"発音"/"合成"されるタイミングで,それぞれSiONTrackEventを発行する事ができます.つまり1つのノートに対して最大4種類のイベントが発行されます.MML演奏などに対して全イベントを生成させると大量にイベントが発行されパフォーマンスの低下を招きます.発行するイベントの種類はトラック毎に選択可能ですのでよく吟味して選択してください.

  • SiONTrackEvent.NOTE_ON_FRAME はノートが発音されるタイミングで発行されます.このイベントのリスナーで映像を操作すると発音と同期する事ができます.ハンドラに渡される SiONTrackEvent の note プロパティで発音する音階を参照できます.track プロパティで発音しているトラックを参照できますが,このイベントが発行される時点で音の合成はすでに終了しているため,このプロパティを使って操作する事はできません.また,値を参照する場合は遅延分未来の値が入っていると考えて下さい(厳密には違います).
  • SiONTrackEvent.NOTE_ON_STREAM はノートが合成されるタイミングで発行されます.このイベントは発音より早いタイミングで発行されるため,このイベントのハンドラ内で映像を操作すると音より早いタイミングで映像が変化してしまいます.しかし,このイベントは音の合成前に発行されるため,渡される SiONTrackEvent の track プロパティによるトラックの操作や,preventDefault()による発音のキャンセルが可能です.また SiONTrackEvent::frameTriggerDelay プロパティを参照すると実際に発音されるまでの遅延を[ms]単位で取得する事が出来ます.尚,このハンドラ内で track プロパティの keyOn() を呼び出すと再帰呼出でスタックオーバーフローエラーとなります.
  • SiONTrackEvent.NOTE_OFF_FRAME, NOTE_OFF_STREAM は,上記イベントのノートオフ版です.スラーやピッチベンドで音が繋がっている場合でも,次発音の直前にイベントが発行されます.

これら SiONTrackEvent を発行させるには,MML 内に"%t"又は"%e"コマンドを仕込んでおくか,SiDriver::noteOn()の第7-9引数を指定するか,SiMMLTrack::setEventTrigger() 関数を呼びます.尚,noteOn() は内部でノートオンイベントが発行されるため,返値で渡された SiMMLTrack の setEventTrigger() を呼び出してもノートオンイベントは発行されません(ノートオフイベントは発行される).第7-9引数で指定して下さい.一方,sequenceOn() はストリーミング時にイベントが発行されるため,返された SiMMLTrack の setEventTrigger() が有効です.
ここでは最も代表的な使い方である"%t"MMLコマンドについて説明します.他の使用方法でも基本的には同じで下記 3引数で設定します.

  • 第1引数;eventTriggerID; ハンドラに渡される SiONTrackEvent の eventTriggerID プロパティで参照する値を指定します.このIDを用いて,どこからイベントが発行されたかを特定する事ができます.値は任意です.
  • 第2引数;noteOnTrigger; ノートオン時のSiONTrackEventを発行するかをフラグで指定します.0なら発行しません.1なら発音のタイミングでSiONTrackEv ent.NOTE_ON_FRAMEを発行します.2なら合成開始のタイミングでSiONTrackEvent.NOTE_ON_STREAMを発行します.3なら両方発行します.
  • 第3引数;noteOffTrigger; ノートオフ時のSiONTrackEventを発行するかをフラグで指定します.0なら発行しません.1なら消音のタイミングでSiONTrackEvent.NOTE_OFF_FRAMEを発行します.2なら合成終了のタイミングでSiONTrackEvent.NOTE_OFF_STREAMを発行します.3なら両方発行します.

また"%e"コマンドは,ノートが無くても強制的にノートオンイベントを発行します.SiMMLTrack::dispatchNoteOnEvent() でも同じ挙動です.これらによってノートオンイベントは発行されますが実際に発音されません.これらのコマンド/メソッドでは,第三引数はありません.

SiONTrackEvent.BEAT/SiONDriver::setTimerInterruption()

BEATイベント (SiONTrackEvent.BEAT) と タイマ割り込み(SiONDriver::setTimerInterruption()) は,拍子に対する Event Trigger に相当します.これらによりシンプルな SiON -> DisplayObject の同期が可能です.
SiONTrackEvent.BEAT イベントは,SiONDriver::play()で演奏しているシーケンス(null渡しでplay()を呼び出した場合は,SiONDriver::bpm プロパティで指定したテンポ) の拍子が"発音されるタイミング"で発行されます.デフォルトでは 4Beat毎に発行され SiONDriver::setBeatCallbackInterval() によりイベント間隔の設定を行います.このイベントのハンドラ内で処理を行う事で拍子に合わせた映像操作が可能になります.尚,ハンドラに渡される SiONTrackEvent の eventTriggerID プロパティには,ストリーミング開始を0とした16ビートカウンタが渡され,note プロパティには 0 が渡されます.
一方,SiONDriver::setTimerInterruption() は,第二引数で渡した function を割り込み関数として,拍子が"合成されるタイミング"で呼び出します.この割り込み関数内で,SiMMLTrack::keyOn() や SiONDriver::noteOn(), sequenceOn() 等を呼び出す事で拍子に合わせた発音が可能となります.また,第一引数では割り込み間隔を16ビートカウント単位で指定します.この値は小数を指定する事もできるため,例えば bpm=120(125[msec/16beat]) で 0.1333333333(=0.125/60) を指定すると60[fps]のタイマ割込が可能です.ただし,割り込みの前に一旦全てのトラックのレンダリングを終えてから処理を返すため,高頻度の割り込みはパフォーマンスの低下を招きます.留意して下さい.
SiON Tenorion - wonderfl build flash online
BEATイベントとタイマ割り込みについては Tenorion デモが良い例になると思います.