Yearly Archives: 2009

2009-11-28

Sleep Cycle Alarm Clock

iPodTouchで試してみた。

  • やっぱりバッテリー駆動じゃダメなのね。起きたときにはバッテリーが切れていた。それ以前にバッテリー駆動だと自動的にスリープ状態になってしまうのでは? いや、ケーブルがつながっていても同じ? よくわからん。
  • 首と背中が痛くてアラームが鳴る前に起きてしまった。iPodTouchを踏まないように意識してしまったせいなのか、寝る姿勢がいつもと変わってしまっていたらしい。
  • 睡眠のサイクル以前に薄っぺらくなってしまったマットを何とかしないとダメなんだと思う。
  • そもそも、寝る前に起きる時間をハッキリ意識すると、わりとぴったり起きられるもんじゃね?

これ以上試すにはケーブルを何とかしないと。

2009-11-26

ActionScriptのSoundとSoundChannelで気になった点

いくつか気になった点をテストプログラムで調べてみた。

Q.Soundのplayを何回も呼ぶとどうなるか。

A.同時に複数のSoundChannelが作られ、同時に再生される(音が重なる)。

Q.SOUND_COMPLETEはstopでも発生するのか。

A.発生しない。リファレンスには「サウンドの再生が終了したときに送出されます」とだけ書かれていたことによる疑問。

Q.ストリーム再生はどのような条件で行われるのか。

A.基本的に長い音ならばダウンロードが完了する前にplay()すれば常に行われると考えて良いみたい。ローカルからの再生は読み込みが速すぎてよく分からない。ローカルからの再生でもPROGRESSイベントは多数起きることだけは分かる。

Q.ストリーム再生はstop()だけでは止められないのか(明示的なcloseが必要なのか)。

A.開発ガイドには次のように書かれている。

ActionScript 3.0 のプログラミング / サウンドの操作 / サウンドの再生

サウンドのストリーミングの停止

ストリーミングしているサウンド、つまり再生中もロードを行うサウンドの再生には特異な処理があります。ストリーミングサウンドを再生している SoundChannel インスタンスの SoundChannel.stop() メソッドをアプリケーションで呼び出すと、1 つのフレームのサウンドの再生が停止し、次のフレームのサウンドの先頭から再生が再開されます。これは、サウンドのロード処理が実行中になっているためです。ストリーミングサウンドのロードと再生の両方を停止するには、Sound.close() メソッドを呼び出します。

↑の意味がよく分からないことによる疑問。stopすればちゃんと再生は止まる。再開されるようなことはないよ? 次のフレームってどういう意味だろう。もちろんcloseしなければロードは最後まで進行する。

Q.ストリーム再生中にstopせずにcloseするとどうなるのか。

A.読み込みが終わったところまで再生される。SOUND_COMPLETEイベントは発生しない。

テストに使ったコード

//Test.as
package{
    import flash.display.*;
    import flash.text.*;
    import flash.media.*;
    import flash.events.*;
    import flash.net.URLRequest;

    public class Test extends Sprite
    {
	private var tf:TextField = new TextField;
	private var snd:Sound = new Sound();
	private var channel:SoundChannel;
	private var tfPrevLength:int = -1;
	private var tfCurrLength:int = -1;

	public function Test()
	{
	    addButton("[STOP]", onClickStop, 0, 0);
	    addButton("[CLOSE]", onClickClose, 100, 0);

	    tf.text = "";
	    tf.autoSize = TextFieldAutoSize.LEFT;
	    tf.y = 16;
	    addChild(tf);

	    snd.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
	    snd.addEventListener(Event.COMPLETE, onLoadComplete);
	    snd.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
	    snd.load(new URLRequest("test.mp3")); //読み込みが終わるまでにボタンが押せるくらい大きなmp3ファイル。
	    channel = snd.play();
	    channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
	}

	private function addButton(text:String, func:Function, x:int, y:int):void
	{
	    var t:TextField = new TextField();
	    t.text = text;
	    t.x = x;
	    t.y = y;
	    t.autoSize = TextFieldAutoSize.LEFT;
	    addChild(t);
	    t.addEventListener(MouseEvent.CLICK, func);
	}

	private function onClickStop(e:MouseEvent):void
	{
	    tf.appendText("channel.stopn");
	    channel.stop();
	}

	private function onClickClose(e:MouseEvent):void
	{
	    tf.appendText("snd.closen");
	    snd.close();
	}

	private function onLoadProgress(e:ProgressEvent):void
	{
	    // Progressイベントは全部表示すると鬱陶しいので、出来るだけまとめる。
	    if(tfCurrLength == tf.text.length){
		tf.text = tf.text.substr(0, tfPrevLength);
	    }
	    tfPrevLength = tf.text.length;
	    tf.appendText("LoadProgress " + e.bytesLoaded + "/" + e.bytesTotal + "n");
	    tfCurrLength = tf.text.length;
	}

	private function onLoadComplete(e:Event):void
	{
	    tf.appendText("LoadCompleten");
	}

	private function onSoundComplete(e:Event):void
	{
	    tf.appendText("SoundCompleten");
	}

	private function onIOError(e:IOErrorEvent):void
	{
	    tf.appendText("IOError " + e.text);
	}

    }
}
2009-11-26

ActionScriptのSoundとSoundChannel

そろそろSoundまわりに手を付けてみますかね。ということで、開発ガイドやリファレンスに目を通してみました。うーん、なかなかお手軽に使えそうですね。

//Test.as
package{
    import flash.display.*;
    import flash.media.Sound;
    import flash.net.URLRequest;

    public class Test extends Sprite
    {
	public function Test()
	{
	    new Sound(new URLRequest("nyandaful.mp3")).play();
	}
    }
}

最低限再生するだけならこのくらいでOK。エラーに備えてEvent.IO_ERRORくらいは補足した方が良さそうですが。

playメソッドでは開始位置やリピート回数を指定することも出来るみたいです。ただ、ループ区間を指定することは出来ないみたいなのが残念。

サウンドを止めるためにSoundにstopメソッドがあるのかな、と思ったらそうではなく、play()の戻り値であるSoundChannelにstopメソッドがあります。Soundオブジェクトは今鳴っている音そのものを表すのではなく、あくまで一つの音の種類というか、データソースというか、一つの音源を表すみたいです。今鳴っている音自体はSoundChannelオブジェクトで表されます。だから、Soundのplay()でSoundChannelオブジェクトが生まれ、stop()でその役目を終える。再度再生したい場合はSoundのplay()でまた新たなSoundChannelオブジェクトを作る。ボリュームやパンニングは再生中の音に対する属性だから、SoundChannelのsoundTransformプロパティで制御する。そういった考え方のようです。

こういう設計だから、一つの音源を同時に複数鳴らすことも簡単にできます。Soundのplay()メソッドを何回も呼べば、呼んだ分だけSoundChannelオブジェクトが作られ、同時に再生されます。

//Test.as [PLAY]の文字をクリックするとmp3を再生する例。何回もクリックすると、その分音が重なっていく。
package{
    import flash.display.*;
    import flash.text.*;
    import flash.media.Sound;
    import flash.net.URLRequest;
    import flash.events.*;

    public class Test extends Sprite
    {
	private var snd:Sound = new Sound(new URLRequest("nyandaful.mp3"));
	private var tf:TextField = new TextField;
	public function Test()
	{
	    tf.text = "[PLAY]";
	    tf.autoSize = TextFieldAutoSize.LEFT;
	    addChild(tf);
	    tf.addEventListener(MouseEvent.CLICK, onClick);
	}

	private function onClick(e:MouseEvent):void
	{
	    snd.play();
	}
    }
}
2009-11-23

s5fの画像リソース読み込みまわり

ようやく最低限の実装が出来た。

最近はエラー時の細々とした処理を実装していた。エラー報告用のUIと再試行・無視の処理など。

事前読み込み用のコマンドなんかも用意したけど、ネットワークの速度が速くて、使わなくてもそれほど困らない。まあ、安定した動きをさせたいのなら使っておいた方が良いんだけど。こういう機能ってテストが難しい。

2009-11-23

flash.display.BitmapDataのメモリリーク?

タスクマネージャでスタンドアロンのFlashPlayerが猛烈にメモリを食っていることが分かって、長々と調べた結果、どうやら自分で作ったBitmapDataインスタンスのdispose()を呼んでいないことが原因らしい。えー、何で何で? たぶんどこからも参照されていないと思うんだけど。ローカルフレームからの参照が残ってるのかなぁ。そんなわけないよな、new BitmapDataして変数に入れただけでは残らないし。

ん? new Bitmap(new BitmapData(640, 480, false, 0)); と1行書いただけでダメみたい。もちろん作ったオブジェクトの参照は変数にも入れていないし、addChildもしていない。なんか内部的な理由によるものなんだろうか……。

Loaderで読んだBitmapやBitmapDataはdisposeしなくてもちゃんと解放されてるみたいなんだけどなぁ。