2009年3月 Archives

« 2009年2月 2009年4月 »

FlashMediaServer を使った録画と録音

FlashMediaServerを使った録画と録音をAS3で実装してみました。

New Project

Alternative content

Get Adobe Flash player



ここら辺の情報はあんまり多くない上にAS2の情報ばっかりだったりするので結構ハマりました。というか未だ解決しない問題もあるんだけど、諸事情により調査続行する必要がなくなったので晒しちゃいます。

ちなみにflaファイルです。
download

http://fms.denniehoopingarner.com/にある、AS2ソースをAS3に書き直しただけなんですが、webカムからキャプチャした画像を録画・再生できます。また、マイクからの音声だけを録音・再生もやってみました。

New Project

Alternative content

Get Adobe Flash player


基本的にトライアンドエラーでとりあえず「動いたよ」ってレベルの話なのでもっとエレガントな方法がどこかにあるはず。たぶん。


面白い事に、fmsでもred5でもswf側のコードはそのまま動きます。すごなあ〜、Red5。


stop();


var myServer:String =  "rtmp://hoge.fms.heteml.jp/var";
//myServer = "rtmp://nottinghill.llc.msu.edu/recordYourself/video"
var myRecording:String = "test001";
var myClip:String = myRecording

var myNS:NetStream
var myCam:Camera
var myMic:Microphone
var myVid:Video = _video

var myNC:NetConnection = new NetConnection();


tooltip_mc.visible = false;
   
function setStatus(msg){
    log(msg)
    status_txt.text = msg;
}


recBtn.addEventListener(MouseEvent.CLICK,recClip)
playBtn.addEventListener(MouseEvent.CLICK,playClip)
stopBtn.addEventListener(MouseEvent.CLICK,stopClip)


myNC.objectEncoding = ObjectEncoding.AMF0
myNC.addEventListener(NetStatusEvent.NET_STATUS,
    function(e:NetStatusEvent):void{
        setStatus("Connecting to server...");
        if(e.info.code == "NetConnection.Connect.Success")
        initStream();
        log(e.info.code)
    }
)

initCamera()
myNC.connect(myServer);

function initStream()
{
    setStatus("initStream");
   
    myNS = new NetStream(myNC);
    /**/
    myNS.bufferTime = 2;

    myNS.addEventListener(AsyncErrorEvent.ASYNC_ERROR,log)                     
                         
    myNS.addEventListener(NetStatusEvent.NET_STATUS,
        function(e:NetStatusEvent):void{
            trace("nsm :",e.info.code);
            switch(e.info.code)
            {
                 case "NetStream.Play.Complete":
                 setStatus("stopped.");
                 myVid.attachCamera(myCam);
                 break;
                 default:
                 break;
            }
        }
    )
    /**/
   
   
}

function initCamera():void
{   
    setStatus("initCamera");
    // init camera
    myCam = Camera.getCamera()
   
    myCam.setMode(240, 180, 15);
    myCam.setQuality(0, 90);
    myCam.setKeyFrameInterval(5);
    //myCam.setLoopback(true);
    myMic = Microphone.getMicrophone()
    myMic.setSilenceLevel(0)
    //myMic.setRate(22);
    myVid.attachCamera(myCam);
   
}

function recClip(e:MouseEvent = null)
{
    myVid.attachCamera(myCam)
   
    myNS.attachAudio(myMic);
   
    myNS.attachCamera(myCam);
    myNS.publish(myClip, "record");
    setStatus("recording.");
}

function playClip(e:MouseEvent = null)
{
    myNS.play(myClip);
    myVid.attachNetStream(myNS);
    setStatus("playing.");
}

function stopClip(e:MouseEvent = null)
{
    //myNS.publish(myClip,"stop")
    myNS.close()
    setStatus("stopped.");
    myVid.attachCamera(myCam);
}




  import flash.external.ExternalInterface;
  import flash.utils.getQualifiedClassName;

  function log(... args):void {
    var inspect:Function = function(arg:*, bracket:Boolean = true):String {
       
       
        var className:String = getQualifiedClassName(arg);
        var str:String;

        switch(getQualifiedClassName(arg)) {
            case 'Array':
              var results:Array = [];
              for (var i:uint = 0; i < arg.length; i++) {
                  results.push(inspect(arg[i]));
              }
              if (bracket) {
                str = '[' + results.join(', ') + ']';
              } else {
                str = results.join(', ');
              }
              break;
            case 'int':
            case 'uint':
            case 'Number':
              str = arg.toString();
              break;
            case 'String':
              str = arg;
              break;
            default:
              str = '[' + className + ':' + String(arg) + ']';
        }
        return str;
    }

    var r:String = inspect(args, false);
    trace(r)
   
    try
    {
        ExternalInterface.call('console.log', r);
    } catch (error:Error)
    {
    }
   
  }

Progression in MTLに行ってきたよ。

Progression in MTLに行ってきたよ。

いつになくディープな話であっという間の二時間でした。

個人的にはCommand周りの話が面白かった。ほとんどの場合サーバー連携の非同期通信の部分でカスタムコマンドを作ったりするんだけど、その他にも色々と可能性を感じたり。Tween系のカスタムコマンドとかを量産しておくとエフェクトとかトランジョンのプリセットととしてストック可能だよな、と。あるいはSOAPCommandとかを作って公開すると結構便利なんじゃないでしょうか。


Progresion案件じゃなくても非同期処理はCommandを使いたい感じなのでいっそのこと、CommandパッケージはProgressionからスピンオフしてもいいんじゃないかと思ったり。あ、でもそうすっとCastオブジェクトとの連携が逆にややこしくなるかな?

ダイナミックサウンドのパフォーマンスとか設計とか

ダイナミックサウンドを用いた作品を作る時、ほとんどの場合複数の音を操る事になると思います。単純なところで言えばサイン波と三角波とノイズを同時に鳴らす、とか。

で、このとき、三つのシグナルに対して、それぞれ三つのSoundインスタンスを生成してゴニョゴニョやるのか、単一のSoundインスタンスに対して、三つの信号を合算してゴニョゴニョするのか、二つの選択肢が生まれます。

一応テストしてみたところ、後者の方がパフォーマンスが良いと思うのですがどうでしょう?
手持ちのMBPで20個のサイン波を処理してみたところ前者81%、後者66%とかでした。

上記の仮説が正しい場合、マスターとなるSoundインスタンスをシングルトン化し、シグナルを生成するクラスのプロパティとして持たせれば良いんじゃないでしょうか。ちょうど、DisplayObjectにstageプロパティがあるように、masterプロパティを持たせるって感じ。

さらにvisibleプロパティよろしくmuteプロパティかlistenプロパティを持たせてtrue/falseでmasterへシグナルを書き込むか否かをコントロールすると、何となくFlashの表示オブジェクト系と似たような流れで処理が可能になると思うんだけど。


個人的にはダイナミックサウンド系のライブラリ設計は如何に表示オブジェクトライクに設計するかがキモなんじゃないかと思いますが、果たしてどうでしょう。春にはSFWSoundがお目見えするって話なのでとても楽しみ。

AS3で抽象クラスを泥臭く作る

AS3ではインターフェイスを定義できるもののアブストラクトクラス(抽象クラス)できない。この問題に関してはビンタ先生も「PHPが羨ましいのは抽象クラスをてきぎできるところ(だけ)」とtwitterで言ってた気がする。(間違ってたらごめんね。)

ところが、DisplayObjectなんかは間違いなく抽象クラスだし、ASDocを読んでも「このクラスは基本抽象クラスだからnewすんなyo!」とか書いてあります。

ビルトインクラスで可能なんだから、カスタムクラスでもできるんじゃないかと思って、少し考えてみたところ、泥臭いながら定義できるようになりました。

さらに泥臭いながらも抽象メソッドも定義してみました。


具体的には
1.抽象クラスのコンストラクタでgetQualifiedClassName()を使って完全修飾名から抽象クラスかサブクラスかを判断。抽象クラスならエラーを吐く。

2.抽象メソッド内にArgumentErrorを生成。抽象クラスのコンストラクタ内で実行。サブクラス内でオーバーライドしておかないとエラーを吐く。

という方法でやってます。


以下、サンプルです。

抽象クラス
package abstractClassTest 
{
      import flash.utils.getQualifiedClassName;
    
      public class AbstractClass 
      {
           public function AbstractClass() 
           {
                //直接newされるとエラーをはく
                if (getQualifiedClassName(this) ==       "abstractClassTest::AbstractClass"){
                      throw new ArgumentError(            "abstractClassTest::AbstractClass is abstruct Class");         }
                //オーバーライドされていないとエラーをはく            //ただし無駄にメソッドがコールされるので、駄目か。
                hoo()    ;   }
           /*abstact method*/
           public function hoo():void 
           {
                //オーバーライドされていないとエラーをはく
                throw new ArgumentError("hoo() is abstruct method. you must implement! ");
           }
      }  
}
具象クラス
package abstractClassTest 
{ 
    public class ConcreteClass extends AbstractClass
    {
     public function ConcreteClass() 
        {
            
        }
     override public function hoo():void
        {
            trace("実装しました")
        }
  }
}

実装忘れクラス
package abstractClassTest 
{ 
    public class WarningConcreteClass extends AbstractClass
    {    //抽象メソッドを実装し忘れてみる
        public function WarningConcreteClass() 
        {
            
        }
   }   
}
クライアントプログラム
package abstractClassTest 
{  
    import flash.display.Sprite;
    public class Main extends Sprite 
    {    
        public function Main() 
        {     //OK
                 var c:AbstractClass = new ConcreteClass();
                 c.hoo();//"実装しました
            
                 //Error
                 new WarningConcreteClass();
            
                 //Error
                 new AbstractClass()
           }   
      }   
}

more.. "AS3で抽象クラスを泥臭く作る" »

サウンドライブラリ [ASound] 

3/29日に渋谷で行われたCloque.(クロック)のランチパーティーでAS3を使ったサウンドプログラミングのデモンストレーションをしたんですが、そのときの成果物を「ASound(ア・サウンド)」と改め、libsparkにコミットしました。

視聴→http://memo.kappa-lab.com/samples/Exsample4.swf

今回を含めて数回にわたって、ASoundの概要を書いて行きたいと思ってます。

今日は手始めってことで簡単にご紹介。


220Hzのサイン波を鳴らす
ソース | 視聴

var ins:Instrument = new Instrument();
ins.signals.push(new SinOSC(220));
ins.play();

220Hzのサイン波と880Hzのサイン波と900Hzのサイン波とノイズを音響合成し、レゾナントフィルター(sazameki謹製)をかけ、音圧0からスタートし、1秒後に音圧1まで増加してさらに1秒後消音す。

ソース | 視聴
var ins:Instrument = new Instrument();
ins.signals.push(new SinOSC(220));
ins.signals.push(new SinOSC(800));
ins.signals.push(new SawOSC(900));
ins.signals.push(new NoiseOSC());
ins.generateEnvelop(0, [1, 1000, 0, 1000]);
ins.filters.push(new ResonatFilter(ins))
ins.play();

RSS + Contuct

  • rss
  • email

Credit

Copyright (C) 2007 kappa-lab.com.
All Rights Reserved.