ActionScript3 の Sound 関連

ActionScript3 で Sound クラスを扱う際のまとめ。癖があるので、少し使いにくいです。

Sound クラスの初期化

まず Sound クラスの利用方法から。オブジェクトとして Sound を使うには、外部のファイルをロードするかリンケージを利用してライブラリに登録したクラスを読み込む必要があります。
外部ファイルをロードする場合は、ロードの完了などをチェックする必要があるので注意して下さい。

// 外部のファイルをロードする
var mySound:Sound = new Sound();
var req:URLRequest = new URLRequest("sample.mp3");
mySound.load(req);
// リンケージを使い、ライブラリに登録したファイルを MySound クラスとして使用
var mySound:Sound = new MySound();

Sound クラスの再生と停止

Sound クラスの再生には play メソッドを使います。この時、引数として再生位置、再生回数、サウンドトランスフォームが指定可能で、これらの引数はすべて省略可能です。
なお、サウンドトランスフォームについては後述します。

var mySound:Sound = new MySound();
// 先頭から1回再生する
mySound.play(0, 1);
// 先頭から1000ミリ秒の位置から3回再生する
mySound.play(1000, 3);

ボタンクリックなどで停止を行う場合、 SoundChannel クラスを利用して再生チャネルを取得する必要があります。先ほどの play メソッドは返り値として自身の SoundChannel を返すので、これを受け取って制御します。

var mySound:Sound = new MySound();
var channel:SoundChannel;
// 再生チャネルを受け取る
channel = mySound.play();

// 停止ボタンのクリックイベント
function onStopBtnClick(event:Event):void {
  channel.stop();
}

また、停止位置から再生したい場合、 SoundChannel.position を利用します。

// 再生ボタンのクリックイベント
function onPlayBtnClick(event:Event):void {
  // 再生チャネルが初期化されている(再生中)?
  if(channel) {
    channel = mySound.play(channel.position);
  }else {
    channel = mySound.play();
  }
}

サウンドトランスフォームの利用

先ほど後に回したサウンドトランスフォーム(SoundTransform)は、音量や定位を操作するクラスです。設定は再生開始時に行います。
なお、音量のみを操作したい場合も、定位を0に設定しておかないと正しく設定が行われないようです。

var mySound:Sound = new MySound();
var channel:SoundChannel = new SoundChannel();
var trans:SoundTransform = new SoundTransform();
// 音量を0〜1で指定
trans.volume = 0.5;
// 定位を-1〜1で指定
trans.pan = 0;

// サウンドトランスフォームを指定して、再生開始
channel = mySound.play(0, 1, trans); 

再生の途中でサウンドトランスフォームを操作したい場合、再生チャネルを通して設定します。この時、再生チャネルが初期化されていないとエラーになるので注意して下さい。

// 音量操作用変数、0〜3の4段階で操作
var myVolume:int = 0;

// 音量操作ボタンのクリック時イベント
function onVolumeBtnClick(event:Event):void {
  // 再生チャネルは初期化されている?
  if(channel) {
    myVolume = ++myVolume % 4;
    switch(myVolume) {
      case 0:
        trans.volume = 1;
        break;
      case 1:
        trans.volume = 0.6;
        break;
      case 2:
        trans.volume = 0.2;
        break;
      case 3:
        trans.volume = 0;
        break;
    }
    channel.soundTransform = trans;
  }
}

再生終了を判定する

再生の終了をイベントとして受け取るには SoundChannel で SOUND_COMPLETE イベントをリッスンします。
注意点として、途中でサウンドを停止した場合、改めてイベントを設定しなおす必要があります。また、必要なくなったリスナはきちんと削除しておくようにします。

var mySound:Sound = new MySound();
channel:SoundChannel;
channel = mySound.play();
// まず、再生開始時にイベントをリッスンしておく
channel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleted);

// 停止ボタンのクリックイベント
function onStopBtnClick(event:Event):void {
  // 一旦イベントのリッスンを停止する(メモリリークの防止)
  channel.removeEventListener(Event.SOUND_COMPLETE, onSoundCompleted);
  channel.stop();
}

// 再生ボタンのクリックイベント
function onPlayBtnClick(event:Event):void {
  // 再生チャネルが初期化されている(再生中)?
  if(channel) {
    channel = mySound.play(channel.position);
  }else {
    channel = mySound.play();
  }
  // 改めてイベントをリッスンする
  channel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleted);
}

// 再生完了時イベント
function onSoundCompleted(event:Event):void {
  // 一旦イベントのリッスンを停止する(メモリリークの防止)
  channel.removeEventListener(Event.SOUND_COMPLETE, onSoundCompleted);
  // 最初に戻って再生を開始する
  channel = mySound.play();
  // 改めてイベントをリッスンする
  channel.addEventListener(Event.SOUND_COMPLETE, onSoundCompleted);
}

問題点

以上が Sound クラスの基本的な使い方ですが、問題点として play メソッドを使わないと再生チャネルが初期化できない点が挙げられます。
例えば、再生開始前からサウンドトランスフォームを操作したい場合、一旦再生を開始し、直後に停止する必要があります。

var mySound:Sound = new MySound();
var channel:SoundChannel;
var trans:SoundTransform = new SoundTransform();
trans.volume = 0.5;
trans.pan = 0;

// 再生チャネルを強引に初期化する
channel = mySound.play(0, 1, trans);
channel.stop();

乱暴なコードですが、単純に再生チャネルだけを得るメソッドが存在しないため、こうするより他方法がありません。恐らく、実際の再生時に再生チャネルの空きをチェックし、空いているチャネルを割り当てている関係だと思いますが…