Hi-farm blog

ActionScript 3.0 , AIR , FLEXからCocoa, OpenGL

Archive for the ‘Flex’ Category

iPhoneでFlashの画面を操作する

以前、名古屋のFxugにて少し発表した内容なんですが、ずっと記事にできてなかったので、今更ながらまとめます。

密かに前から社内用発表会のネタとして作ってはいたのですが、僕個人的にも、なかなか披露する機会がないまま、時間が過ぎてしまいました。

概要としては、
1. iPhone上でボタンをタップすると、AIR 2で作ったサーバーに、iPhoneからSocket経由で信号を送ります。
2. AIR 2のサーバーが、信号を受け取り、信号に応じた処理を行います。

これが作ったアプリのキャプチャです。

viewer

iPhoneとAIR 2サーバーの関係は、この通りです。

kousei

簡単に行ってしまえば、これだけです。
では、ここから説明します。

1. AIR 2のサーバー部分を作成
AIRでサーバーを作るには、UDPとTCPのサーバーがありますが、今回はTCPで通信するので、flash.net.ServerSocketクラスを使用します。

宣言〜受付開始

<pre>import flash.net.ServerSocket;

// 接続してきたSocketを保持する
var socks:Vector. = new Vector.();
// インスタンス生成
var server:ServerSocket = new ServerSocket();
// 接続時のイベントハンドラ作成
server.addEventListener(ServerSocketConnectEvent.CONNECT, serverSocketConnectHandler, false, 0, false);
// 待ち受けポートを指定(43243番で受け付ける)
server.bind(43243);
// 待ち受け開始
server.listenen();</pre>

接続時:

function serverSocketConnectHandler(event:ServerSocketConnectEvent):void
{
  // 接続してきたSocket
  var socket:Socket = event.socket;
  // 接続してきたSocketにデータを返すため、イベント設定
  socket.addEventListener(ProgressEvent.SOCKET_DATA, receiveHandler, false, 0, false);
  // 接続してきたSocketを保持する
  socks.push(socket);
}

受信時:(本来は宛先を指定するべきだが、特に指定せず、全てのSocketに送信しています)

function receiveHandler(event:ProgressEvent):void
{
  // データを送信したSocketを取得
  var socket:Socket = event.target as Socket;
  if(socket!=null)  // nullチェック
  {
    // 受信データを取得
    var recv:String = socket.readUTFBytes(socket.bytesAvailable);
    // 操作対象のVideoPlayerを取得
    var target:VideoPlayer = getCurrentVideo(); // 自作のメソッドです
    // コマンドを取得し、操作を実行。コマンドを取得するため、indexOfを使っています。
    if( recv.indexOf("prev") >= 0) {
      setPos("prev");
    } else if( recv.indexOf("next") >= 0) {
      setPos("next");
    } else if( recv.indexOf("play") >= 0) {
      if( target.playing ) {
        target.pause();
      } else {
        target.play();
      }
    }
  }
}

AIRで作るサーバー周りは、こんなところです。エラー処理や切断時の処理などは書いてなくてごめんなさい。

iPhone側アプリケーションのSocket処理
では、次。iPhoneのほう。これも簡単な書き方でごめんなさいね。と、いうかCで最低限の実装しかしていないです。

TCPSendClient.m
接続:

-(void)connect:(NSString *)ip toPort:(NSInteger)port
{
  	if(_connected)  // TCPSendClientが持っている、接続状態を保持する変数
	{
		return;
	}
	_connected = NO;
	// IPアドレスを取得
	servIP = [ip UTF8String];
	// portを取得
	servPort = port;
	// socketが正しく生成できているかチェック
	if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
	{
		NSLog(@"socket creation error.");
		return;
	}
	// socketの設定
	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = inet_addr(servIP);
	servAddr.sin_port = htons(servPort);
	// 接続
	if(connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
	{
		NSLog(@"connect error.");
		return;
	}
	_connected = YES;
	NSLog(@"connect succeed.");
}

送信:

-(void)send:(NSString *)message
{
  mes = [message UTF8String];
  mesLen = strlen(mes);
  // 送信
  if(send(sock, mes, mesLen, 0) != mesLen) {
    NSLog(@"send failed.");
  }
}

ちなみに、
TCPSendClientクラスは、Socket処理を受け持つクラスで、自作しています。
TCPSendClient.hはこんな風に書いています。

#import <Foundation/Foundation.h>
#import <stdio.h>
#import <sys/socket.h>
#import <arpa/inet.h>
#import <stdlib.h>
#import <string.h>
#import  <unistd.h>

@interface TCPSendClient : NSObject {
	int sock;
	struct sockaddr_in servAddr;
	unsigned short servPort;
	const char *servIP;
	const char *mes;
	unsigned int mesLen;
	BOOL _connected;
}

-(void)connect:(NSString *)ip toPort:(NSInteger)port;
-(void)send:(NSString *)message;
-(void)close;
-(BOOL)getConnected;
@property(readonly) BOOL connected;

@end

このサンプルでは、このようにTCPSendClientを使っています。

PagerViewController.m

-(IBAction) processConnect:(id)sender  // ボタンをタップした時のAction
{
	if([connectSwitch isOn])  // これは、接続のon/offを切り替えるUISwitchです。
	{
		[sendc connect:@"10.0.2.1" toPort:43243];  // sendcというのがTCPSendClientです
		stateField.text = @"connect";
	}
	else
	{
		[sendc close];  // 本文では紹介しなかったですが、切断します。
		stateField.text = @"disconnect";
	}
}

データ送信:

-(IBAction) btnUp:(id)sender  // 各ボタンのTouchUpInsideと関連づけています。
{
	isPress = NO;
	prevValue = 0;
	if( (UIButton*)sender == btn) // btnとは、一つ前の動画にフォーカスをあてるためのボタンです。
	{
		dir = @"prev";
		[sendc send:dir];
	}
	else if((UIButton*)sender == nextBtn) { // nextBtnとは、一つ次の動画にフォーカスをあてるためのボタンです。
		dir = @"next";
		[sendc send:dir];
	}
	else if((UIButton*)sender == playBtn) { // playBtnとは、フォーカスがあたっている動画を再生するためのボタンです。
		dir = @"play";
		[sendc send:dir];
	}
}

ちなみに、こちらがiPhoneアプリの画面です。(すごい地味ですね。。。笑えない)

Interface Builderのキャプチャです。

ib

Macをルーターにする
最後に、iPhoneとAIRサーバーを接続するための設定をします。Macなら「インターネット共有」を使えば簡単にルーターにして連携させる事が可能です。こういうときに、一つのメーカーが作っている事が良い事に思えますね。
今回は、AirMac経由で共有します。

kyouyuu

1. 「システム環境設定」を開く
2. 「共有」を開く
3. 「インターネット共有」を選択する
4. 「共有する接続回路」がAirMac以外であることを確認。なっていなければ変更します。
→iPhoneとMacをAirMac(無線)で接続する
5. 「インターネット共有」のチェックを入れると、共有を開始するか確認してきますので、開始をクリックします。すると、画面右のAirmacのアイコンがこのようになります。

airmac

開始順としては、AIRサーバーとiPhoneが接続する必要があるので、
1. Macをルーターにする
2. AIRサーバーアプリを起動する
3. iPhoneアプリを起動して接続する。
4. iPhone上で操作する。

というところです。

今回簡単に紹介しすぎててすみません。このままでわかりにくいなどご意見ありましたら整理した上で、ソース込みで全て公開します。

本当にものすごく久々の投稿になってしまいました。

先日、11/26に行われた、Spark勉強会で、Dynamic Sound Generationの発表をしてきたので、その資料をアップします。

(※再生には音楽ファイルを必要なので、各自用意して下さい。)

ソース一式

PDF

「フーリエ変換を使わない、エフェクトのかけかた」というタイトル通り、信号処理には本来フーリエ変換は欠かせないものですが、フーリエ変換の話しになると一気に敷居が高くなる(というか自分が今勉強している状態なので、この様な発表になりました。

 

ただ、やはりフーリエ変換を使えていない&勉強途中での発表になってしまったので、波形が途切れてしまっているところがあるようで、ぷつぷつと途切れる音が結構聴こえてしまいます。。。

あくまでご参考程度にしていただければと思います。

 

 

[ファイル構成について]

 

SoundGeneration.mxml:ラジオボタンやスライダーがついているView + 実際に音を鳴らすファイル

model/SoundObj.as:Dynamic Sound Generationを使って音楽を再生したり、エフェクトをかけたりするスクリプトを記述しているファイル。

 

SoundObj.asに関しては、mxmlでも使いやすいように、IMXMLObjectインターフェイスを実装しています。

 

[SoundObj.asの仕組み]

_currentEffectというプロパティを切り替えて、どのエフェクトをかけるのかを選択します。

 

extractメソッドを呼び出すたびに、bufferプロパティにデータを蓄えています。

これを使って、ディレイや逆再生を実現しています。

 

なお、逆再生に関しては、こちらが大変参考になります。

次は、フーリエ変換からめてしっかりとエフェクトをかけられるようになりたいなあ。
フーリエ変換とエフェクトの掛け方を勉強できる機会があれば、是非参加したいです。

spark勉強会。

さて、7.22はadobeにてspark勉強会でした。

会社を早めに出勤して、そうそうに向かったのですが、若干の遅刻。
やっぱり時間は苦手だなあ。

到着すると、Adobeの方からFlash Playerやpixel Benderなどの紹介がありました。
pixel Benderは是非試してみたいのですが、あいにく僕が持っているのはMacBookなので、まだ試す事はできなさそうです。。
MovieClipだけでなく、動画にもエフェクトがつけれるらしいですし、さらには噂では音にもエフェクトをつけられるという話しを聞いているので、とても興味があるのですが。。

 

Flash Player10は、Dynamic Sound Generationや、縦書きテキストの対応など、とても期待をしております。

ただ、いづれも最先端過ぎるのか、文献が少ないので習得するのは大変そうですね。

あと、FlashのSEO対策は、外部XMLとかも検索対象にしてくれるようだ、という話しを聞けたので、今後FlashはSEOに弱い!という通説が覆りそうで、楽しみです。

 

で、発表会。

はじめは、主催者でもある、yossy@beintaractiveさん。

Spark Projectの今までの経緯と、Actionscriptで疑似スレッドを実現する、ActionScript Thread Library 1.0 (そうめん)の紹介をされていました。

非同期処理を処理の流れ通りに記述できたり、割り込み処理や例外処理など、使いこなすとかなりASの開発が便利になりそうでした。

 

次は、seagirlさんの「Genius Framework」のご紹介。

シンプルで使い勝手が良さそうでした。Flexの方は一度触られてみてはいかがでしょうか?

あとは、コマンドラインでスケルトンコードを作ってくれる機能は、かなり便利なんじゃないかと思っています。

 

つぎは、mutsuさんのFrocessing

テキストの扱いとか、3Dとかが比較的書きやすそうなのと、これで覚えれば本家Processingも使えるようになりそうですので、一度触ってみたいですね。

 

つぎは、arkwさん。

今まで全く考えていなかったような深い、深すぎるフレームについての話しが聞けて、すごく勉強になりました。

 

そして、最近Dynamic Sound Genrerationに興味を持っている僕が特に楽しみにしていた、

zk33さんの、sazameki紹介。

どこかでみたようなおもちゃから繰り出される音には、ただただ感激するのみでした。

勉強になります!

これがspark projectにコミットされているだなんて。すごいですね。

 

あまりにも文献が少ないサウンド系の情報を充実させよう!と思っていらっしゃるようです。

僕も何か力になれればと思うのですが、なかなか壁は高そうです。

 

サイトは、ksakaiさんの発表。

Swfを埋め込む時のタグについてや今後の方向性など、詳しいレベルでご説明いただいて、とても勉強になりました。

 

とってもためになる勉強会で、満足しつつ、2次会へ。

うーん。反省ですわ。。かなり気持ち悪い事を言っていたような気が。。。

しまった。

 

でも楽しかったです。

AIRとしょこたん。

なんか自分のやるべき事が見えた気がしました。

 

AIRでなんかしないとなあ。

 

お断り:

タグとかカテゴリーについては、無視して下さい。

 

 

余計な親切、大きなおせっかい

Flex Builder 3を使ってて、先にimport 文を書いて、その後にコンストラクタにてプロパティを宣言、インスタンス化、などしている時に、
本当に御丁寧にも自動的にFlex Builderがimport文をごそっと削除していただけるという本当に親切すぎてイラッとくる機能がついてて、日々イラッとしてたのですが、当然のごとく、設定をいじれば回避できたのでメモ。

Macだと、
【環境設定】-> 【Flex】-> 【エディタ】-> 【ActionScriptコード】


【整理中に不要なインポートを削除】のチェックをはずす!

これですこし心が優しくなれました。

久々エントリーがこんなのでごめんなさい。。。。

2007年12月25日22:00

  • 0 Comments
  • Filed under: Flex, Flex3
  • preventDefault();

    要するにタイトルにある、preventDefault()があるよ、っていうことを残したかっただけですが、便利ですね。

    例えば、DataGridへデータをドロップするとして、

    <mx:DataGrid dropEnabled=”true” 〜
    とすれば動作はしますが、
    デフォルトのその動作に加えて追加の処理をしたい場合、(このDataGridのdataProviderに新たにデータを追加したい等)
    デフォルトの動作がむしろ邪魔になります。(デフォルトの動作+自分で設定した動作、となり、二重に処理をしてしまう)

    その時に、preventDefaultを記述しておけば、二重動作を防止できます。
    例としてのソースはこんなところでいかがでしょうか?(勢い任せにかいたので、おかしなところがあったらごめんなさい。)

    <mx:Application>
    <mx:Script>
    <![CDATA[
    import mx.collections.XMLListCollection;
    import mx.events.DragEvent;

    [Bindable]
    public var data_c:XMLListCollection;

    private function customDrop(e:DragEvent):void{
    //これでドロップ時のデフォルトの動作を無効にできます。
    e.preventDefault();
    //以下、動作させたい処理

    }

    ]]>
    </mx:Script>
    <mx:DataGrid id=”dg” dataProvider=”{data_c}” dropEnabled=”true” dragDrop=”customDrop(event)”>
    <mx:columns>
    <mx:DataGridColumn …./>
    <mx:DataGridColumn …./>
    <mx:DataGridColumn …./>
    </mx:columns>
    </mx:DataGrid>

    </mx:Application>

    2007年9月9日00:05

  • 0 Comments
  • Filed under: Flex
  • http://www.adobemax2007.jp/

    11月1〜2日、東京であるAdobe Max Japan 2007に行ってきます。

    せっかく平日、週末問わず動ける状況なんだから、行っとかないともったいない、ということで決めました。

    この申し込み画面自体もFlexで使っているのですが、こんな風にFlexでできる事を提示してくれると、Flexの利点とか説明しやすくなるなー、と思ったのでした。

    だいぶんと見た目はいじれそうな予感はするのですが、やっぱりDeveloperがデザインした感があるなあ。。
    タイトルのドロップシャドウとか。。
    その使い方だと読みにくいだけだと思うのですが、いかがでしょうか。

    2007年9月9日01:36

  • 0 Comments
  • Filed under: Adobe Max, Flex
  • サーバーへのXML保存

    ちょいとはまりましたので記録として。

    AS3でXMLを保存するときに、XMLのままでは何なので、Stringに変換し、POSTで送信。

    これをPHP側で保存していたのですが、どうやらサーバーへ送られて、PHPで取得するときには、属性(attribute)の『”』がエスケープされてしまっている。

    確かにセキュリティを考えればいい事なのですが、このままではXMLとして保存できないので、

    PHP側で stripslashesして保存。

    すると無事にXMLらしく保存完了!!

    でも、stripslashesしないといけないということは、セキュリティ上の対策を施すべきかなあ??
    Flexからとわかる識別子をつけるとか。。。。

    2007年9月1日02:11

  • 0 Comments
  • Filed under: Actionscript3, Flex
  • イベント系って。。。

    最近、Flex で色々といじってたり、すこし先にFlashでもAS3を触れそうな状況もあり、色々とAS3を書いているのですが、

    Event系の記述ってどうやってますか?

    Flexなら<mx:Script>に記述しているのですが、AS3だと何をするにもevent, eventで正直ソースがスパゲッティー気味です。。

    取りあえずは外部ファイルに書いて我慢するってとこなんでしょうか??

    いい案あればご教授下さい。。。。
    いい案(ぽいもの)が浮かべばまた書きます。。。。

    2007年8月29日03:34

  • 0 Comments
  • Filed under: Actionscript3, Flex
  • Flex でのCSS命名規則

    詳しいことはわからないが、
    『_』はだめらしい。

    2007年8月25日02:04

  • 0 Comments
  • Filed under: Flex