2012.04.05 | 

こんばんは。muchoです。
今日はほかの会社の方とランチしながら情報交換しました。
やっぱりSublime Text 2アツいですよね。
coffee scriptやらねばー。
お忙しい中ありがとうございました。
また情報交換とか勉強会とかお花見とかやりましょう。

が、しかしブログネタはFlash+Cinderです。
前回のOSC通信に続き、AIRとCinderで連携させてみました。
http://bubblebird.at/tuioflash/で提供されているライブラリを使いました。TUIOプロトコル用のライブラリですが、OSCプロトコルのライブラリが同梱されています。

今回は送信側をAIRアプリ、受信側をCinderにしてテストしました。

受信側のCinderは前回の記事と同じです。



package 
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;

	import org.tuio.connectors.UDPConnector;
	import org.tuio.osc.OSCManager;
	import org.tuio.osc.OSCMessage;

	public class Main extends Sprite 
	{
		private var prefix:String = "/devjam_osc";
		private var oscManager:OSCManager;
		
		public function Main():void 
		{
			oscManager = new OSCManager(null, new UDPConnector("127.0.0.1", 3000, false));
			stage.addEventListener(MouseEvent.CLICK, onClick);
		}

		private function onClick(e:MouseEvent):void
		{
			
			// とりあえずこれだけ・・・
			sendArgument("fullscreen", 1, "i");
		}

		private function sendArgument(address:String, value:*, type:String = "f"):void
		{
			/*
			 * type
			 * s:A string
			 * i:An integer
			 * f:A float
			*/
			var msg:OSCMessage = new OSCMessage();
			msg.address = prefix + "/" + address; //アドレスと
			msg.addArgument(type, value); //形式と値を入れて
			oscManager.sendOSCPacket(msg); //送信!なんてシンプル
		}
	}
}


cinder側に入ってたOSCライブラリでは、データ形式にString,Interger,Float
の3種類しかやり取りできないようなことが書いてありましたが、Tuio as3 libraryだと
もっとたくさんの形式に対応してるようです。Cinder側にもTUIOライブラリがあったので、
そっちを使うといろんなデータのやり取りができるかも?
s A string
i An integer
f A float
b A blob / ByteArray
t An OSCTimetag
d A double
c An ascii character
r A RGBA color
T A boolean true. You don't have to specify a value for this type.
F A boolean false. You don't have to specify a value for this type.
N A null value. You don't have to specify a value for this type.
I Infinity. You don't have to specify a value for this type.

また、私が作ったサンプルだと1データで送信してますが、まとめて送信もできるようです。




    var myBundle:OSCBundle = new OSCBundle();
    myBundle.addPacket(myMsg); //OSCMessage
    myBundle.addPacket(myMsg2); //OSCMessage
    [...]
     
    oscManager.sendOSCPacket(myBundle);


以上、OSC通信のテストでした!

2012.04.01 | 

こんにちは。muchoです。もうすぐお花見のシーズンですね。

さてさて、cinderにはフルスクリーンになる機能があるんですが、
プロジェクターや別のモニターでフルスクリーンにして、
手元のPCでフルスクリーン画面の方をコントロールしたい!
ということでアプリが2個になってしまうのですが、
描画プログラムとパラメーターを制御するプログラムと分割してみました。

OSCはデフォルトのままでは動かないので、blocks以下にライブラリを入れてください。
ライブラリはこちらから
https://github.com/cinder/Cinder/tree/master/blocks/osc

追加リンカファイル
$(CINDER_PATH)/blocks/osc/lib/macosx/osc.a

追加インクルード
$(CINDER_PATH)/blocks/osc/include

OSCでの通信は以下のデータを使います。
・送信先(IPアドレス)
・ポート
・アドレス(変数名のようなもの)
・値の型(int,float,stringのいずれか)
・値

以下の抜粋サンプルではアドレスをプログラムの固有IDと変数名から生成するような
形にしてます。



//-----------------------------------------------------
// senderApp

#include "OscSender.h"

class senderAPP : public AppBasic {
  public:
	void setup();
	void update();
	
	void sendString(string address, vector arg);
	void sendInt(string address, vector arg);
	void sendFloat(string address, vector arg);

	osc::Sender	sender;
	std::string	host;
	std::string	prefix;
	int		port;
};

void senderAPP::setup()
{
	host = "localhost";
	prefix = "/devjam_osc";
	port = 3000;
	sender.setup(host, port);
}

void senderApp::update()
{
	sendFloat("quat", wxyz);
	sendFloat("colora", rgba);
	sendFloat("position", xyz);
}

void senderApp::sendString(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addStringArg(arg[i]);
	}
	sender.sendMessage(message);
}

void senderApp::sendInt(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addIntArg(arg[i]);
	}
	sender.sendMessage(message);
}

void senderApp::sendFloat(string address, vector arg)
{
	osc::Message message;
	message.setRemoteEndpoint(host, port);
	message.setAddress(prefix + "/" + address);
	for(int i = 0; i < arg.size(); i++){
		message.addFloatArg(arg[i]);
	}
	sender.sendMessage(message);
}

//-----------------------------------------------------
// listenerApp

#include "OscListener.h"

class listenerApp : public AppBasic {
  public:
	void prepareSettings( Settings *settings );
	void setup();
	void update();

	osc::Listener	listener;
	std::string	prefix;
};

void listenerApp::prepareSettings( Settings *settings )
{
	settings->enableSecondaryDisplayBlanking( false );
}

void listenerApp::setup()
{
	prefix = "devjam_osc";
	listener.setup(3000);
}

void listenerApp::update()
{
	while (listener.hasWaitingMessages()) {
		osc::Message message;
		listener.getNextMessage(&message);
		string adr = message.getAddress();
		vector substrings = split(adr, "/");
		if(substrings[0] == prefix){

			if(substrings[1] == "quat") {
				float qw = message.getArgAsFloat(0);
				float qx = message.getArgAsFloat(1);
				float qy = message.getArgAsFloat(2);
				float qz = message.getArgAsFloat(3);
				Quaternion oscQuat = Quaternion(qw, qx, qy, qz);
			}
			
			if(substrings[1] == "colora") {
				float vr = message.getArgAsFloat(0);
				float vg = message.getArgAsFloat(1);
				float vb = message.getArgAsFloat(2);
				float va = message.getArgAsFloat(3);
				ColorA oscColor = ColorA(vr, vg, vb, va);
			}
			
			if(substrings[1] == "position") {
				float px = message.getArgAsFloat(0);
				float py = message.getArgAsFloat(1);
				float pz = message.getArgAsFloat(2);
				Vec3f oscPos = Vec3f(px, py, pz);
			}
		}
	}
}


そして・・・できたサンプルがこちら左が送信側プログラム、右が受信側です。

にしてもインターフェースを作るにはcinderは不向きなので、
コントローラー側はflashで作ろうと思います。

2012.03.14 | 

こんばんはmuchoです。
JSONやらサーバ絡みで日付を取得すると
Wed Apr 12 15:30:17 GMT-0700 2006
↑こんな感じで文字列になってることが多いのですが、
これを一発でタイムスタンプに変換してくれる命令が
ActionScriptにはありました。
JavaScriptにもありました。
いつの間にこんな便利な関数が出来てたんでしょう?
ちょっと衝撃だったので忘れないようにメモ。



JSだと
thisday=new Date("Nov, 5 1997 00:00:00");
みたいな大技もあり、これは知っていたのですが。
timestamp=Date.parse("Nov, 5 1997 00:00:00");
これで1970年1月1日0時0分0秒(UTC)からの秒数(ミリ秒単位)を得ます。

ActionScriptだとこんな感じ
timestamp=Date.parse("Nov, 5 1997 00:00:00");

以下の形式に対応してるとのこと。
     MM/DD/YYYY HH:MM:SS TZD
     HH:MM:SS TZD Day Mon/DD/YYYY 
     Mon DD YYYY HH:MM:SS TZD
     Day Mon DD HH:MM:SS TZD YYYY
     Day DD Mon HH:MM:SS TZD YYYY
     Mon/DD/YYYY HH:MM:SS TZD
     YYYY/MM/DD HH:MM:SS TZD

さらに
年、月、曜日は、スラッシュ(/)またはスペースで区切ることができますが、
ダッシュ(-)で区切ることはできません。
月、曜日、年だけというように、これらの形式の一部分を含めることもできます。
だそうです。


区切り記号で分割したりしてたあの日々はいずこへ・・・

2012.03.09 | 

こんばんはmuchoです。

USTREAMをFlash内に読み込もうとして、あれこれやってみたのでメモ。
下記のページを参考にしました。
Flash Client API Documentation (AsDoc)

USTREAM Flash Client APIの使い方
Flash : Ustream Flash Client APIを使ってみる - SWFなカスタムパネルで中継を再生



/*
ちょっと苦しんだのが、再生動画のオリジナルサイズを取得する方法
viewer.channel.streamRect
に格納されるみたいです。

再生開始時のイベントもうまく取れませんでした。
viewer.channel.addEventListener("found", onStart);
viewer.channel.addEventListener("createStream", onStart);
このどちらもviewer.channel.streamRect取得できず、
また表示のタイミングともちょっとズレがあるような?
そこはいい解決法が見つからず悲しい力技になってしまいました。
今後の課題です。
*/




		
		public function main():void 
		{
			getRsl();
			visible = false;
		}

		private function getRsl():void 
		{
			Security.allowDomain("*");
			Security.allowInsecureDomain("*");
			viewerLoader = new Loader();
			viewerLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onRslLoad);

			this.addChild(viewerLoader);

			var applicationDomain:ApplicationDomain = ApplicationDomain.currentDomain;
			var loaderContext:LoaderContext = new LoaderContext();
			var request:URLRequest = new URLRequest("http://www.ustream.tv/flash/viewer.rsl.swf");

			loaderContext.applicationDomain = applicationDomain;
			viewerLoader.load(request, loaderContext);
		}

		private function onRslLoad(e:Event):void
		{
			var logicClass:Class = viewerLoader.contentLoaderInfo.applicationDomain.getDefinition("tv.ustream.viewer.logic.Logic") as Class;
			viewer = new logicClass();
			viewer.volume = 0;
			this.addChild(viewer.display);
			playChannel(id);
		}

		private function playChannel(id:String = null):void 
		{
			var channelId:String = id;
			if(id == null) {
				id = default_channelID;
			}
			viewer.createChannel(id);
			addEventListener(Event.ENTER_FRAME, onStart);
			viewer.playing = true;
		}
		
		private function onStart(e:Event):void
		{
			if (!viewer.channel.streamRect) return;
			e.target.removeEventListener(e.type, arguments.callee);
			var vw:Number = viewer.channel.streamRect.width;
			var vh:Number = viewer.channel.streamRect.height;
			viewer.volume = vol;
			viewer.display.x = 0;
			viewer.display.y = 0;
			viewer.display.width = viewer_width;
			viewer.display.height = viewer_height = viewer_width * (vh / vw);
			visible = true;
		}



2012.02.28 | 

最近やたら長いページが多くなってしかもパララックス効果とかあったりして
どうせなら滑らかにスクロールさせたいなーと思う今日この頃、
今夜は雪らしいですよ。こんにちはmuchoです。

というわけで、マウスホイールでのスクロールやスクロールバーをドラッグした時に
滑らかにスクロールするプラグインです。
smoothScrollerDemo

最初、ユーザーからのスクロール変更情報をキャプチャできないものかと画策したのですが、
mousewheelのイベントならともかく、onscrollイベントだと画面のスクロールそのものにかかってしまい、
ユーザーがスクロールバーを操作して発生したイベントかどうか判別できず断念。
そこで、
0.position:fixedをサポートしてるブラウザかチェック
1.コンテンツ全体を新規divでくるんでposition:fixedをかけて、
2.さらに空のdivタグでコンテンツ全体の高さを保持。
3.スクロールイベントでtop位置の変更をsetIntervalで回す。

BODYタグに背景画像を入れたり、
position:fixedのオブジェクトが他にあると
挙動がおかしくなるかもしれません。
使っていくうちにブラッシュアップできればと思います。



// コンテンツ全体を一つのオブジェクトに包んでプラグインを当てる
$(document).ready(function () {
	$("#page").smoothScroller({fps:60,speed:0.1});
});



というわけでまだアルファ版ですがよろしければどうぞ。
jquery.smoothScroller.zip