iPhoneでFlashの画面を操作する

LINEで送る
Pocket

以前、名古屋の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上で操作する。

というところです。

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

Mac版Flash CS4のflパッケージへのパス

LINEで送る
Pocket

久しぶりのブログ記事がメモレベルですみません。

Flash BuilderとFlashとを共存させたい場合、Flash Builder側にもflパッケージの場所を教えてあげたい場合があると思うのですが、なかなかこれが忘れやすいところにありますので、メモ代わりに残しておきます。

ちなみに、Snow Leopard, Flash CS4の環境です。
Application/Flash CS4/Common/Configuration/以下です。(Flash CS4の位置はインストールした場所により異なるでしょう)

.swcの中身は今イチ解らなかったのですが、
コンポーネント類 .swc : Components/以下
コンポーネント類のソース:Component Source/ActionScvript 3.0/以下

です。
もしかしたらもっと簡単に使えるようになる方法があるのかな、とも思いますが、ソースもみれるのはこれはこれでいい事があるかもしれないので残しておきます。

イージング系:libs/projects/Flash/src/以下

Flash OOP勉強会「FlashとDIYで作る、自作マルチタッチディスプレイ」

LINEで送る
Pocket

2009年2月25日に開催された、第31回Flash OOP 勉強会に行ってきました。

�׋���̕��i

場所:

サイバーエージェントビル1F セミナースペース

4万円ほどで作れるマルチタッチディスプレイということで、マルチタッチのデバイスを自作して、ActionScriptをUIとして使っていました。
iPhoneとかで最近マルチタッチの話題が増えてきていたので、どの様にしてマルチタッチの機能を実現しているのか、実際の制作時の話しを含めて聞きたかったので行ってきました。

実現方法は、sakusan様のブログに説明していらっしゃいましたのでご興味のあるかた是非どうぞ。

簡単にはWebカメラで映像を受け取り、tbetaいうソフトが解析してsocketでAS3にタッチの情報を送る、という仕組みの様です。
AS3でタッチイベントを扱いやすくするためにMulti-Touchライブラリを自作されており、
・TouchManagerクラス:Touchを管理するクラス
・TouchEventクラス:触ったときに発生するイベント
・Fingerクラス:触った座標(0〜1の相対座標)、touchを一意にするためのIDを所有するクラス

を持っていて、TouchEventクラスのインスタンスがfingerを持っているので、Touchイベントが発生したときにイベントハンドラ内部で
e.finger.id
e.finger.x
e.finger.y
と記述することで触られた点を知る事ができるというものでした。(e = TouchEvent)

実際に触る時間がいっぱいあったので触ってみたのですが、

�f�B�X�v���C

でかい。

タッチ可能な領域が大きいということは、iPhoneの様にはいかず、タッチする人数が多くなる可能性があり、コンテンツを作るときに気にしないといけない問題が沢山あるのでどのようにタッチイベントの制御を行えばユーザーが意図した動きにるように作れるのかというのは結構難しい問題であるな、と感じました。
finger.idとタッチイベントが発生した座標をとって、或る程度の範囲内なら同じ人物の動作とみなすという判定が必要になるのかな?実際に作ったわけではないので想像でしかありませんが。

後は、このマルチタッチのデバイスを作ること自体が結構むずかしそうな気がしたので、どこかの段階でハードウェア屋さんと協力して新しいデバイスを次々と作る事ができると面白い展開があるのかも?とか想像していました。

このデバイスをみたり触ったりしているときに、感触を再現することができれば面白いなあなんて思ったのですが、これって音圧とか使うと少しは再現できたりするのかな?この辺の研究は一度やってみたいです。

この様なマルチタッチのデバイス+コンテンツを業務時間外で作り上げる力にはただひたすら感心するのみでした。本当にご苦労様でした。これからも面白いコンテンツを見せていただける事を楽しみにしています。
ってかうらやましいっす!

補足2:
サイバーエージェントさんって、こういうのも作ってたんですね。すてき。

��

Spark 勉強会 #5で話して来ました。

LINEで送る
Pocket

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

先日、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勉強会。

LINEで送る
Pocket

さて、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でなんかしないとなあ。

 

お断り:

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

 

 

今さらエイリアン展

LINEで送る
Pocket

えっと、今更なのですが、先日未来館にて開催されていた、エイリアン展に行ってきました。

ようするにエイリアンについての展示なのですが、さすが未来館というだけあって、見せ方がすごい。

これなのですが、大きな台(卓球台よりでかい)に上からプロジェクターを複数台使い、画面を作ります。

で、台の上に映しだされているボタンをタッチすると、実際にタッチしたことになり、新しいコンテンツを開くことができます。

※上下逆さまでごめんなさい。

職員さんをつかまえて強引に仕組みを聞いてみたのですが、

なんでも、この仕組みは、台に静電気センサーを仕込み、複数同時タッチに対応しているようです。

ちなみに、静電気センサーは調べたところ、15万くらい?でした。

静電気センサーについては、こちらが詳しいです。

株式会社 キーエンス様サイト

 

さらに最後には、「宇宙空間にメッセージを送ろう!」という事で、トラックボールを使ったりして、メッセージの組み合わせを選ぶことができます。

 

で、写真を撮って、メッセージと同時に大画面に表示されます。

ちと恥ずかしいね。

 

Flashでやるなら、Gainer(Funnel?)と絡めたりするんでしょうね。

ここまで大がかりなものを作る事ができたら楽しいだろうなー。

[astro filereference] astroでのFileReference

LINEで送る
Pocket

いやーすごいですね!astro!

ローカルへのファイル保存が可能だなんて!

実際は、FileReferenceはローカルファイルを読み込んで直接操作できるみたいですが、ひとまず今回は保存です。

 

サンプルはこちら。

(Flashサンプル。赤丸をクリックすると、保存ダイアログが現れて、適当な名前を入力してボタンを押すと、保存。)

注意点としては、同じファイル名で上書き保存しようとすると例外をはくらしいです。

(これはもしかすると僕のサンプルが悪いだけかもです。。)

corelibのJPGEncoderを使って、stageを画像として保存しています。

ようは、FileReferenceにsaveというメソッドができて、それを使うと保存できるよ、ということです。

ちなみに、保存できる形式は、

String, XML, ByteArrayらしいです。

今回のサンプルは、ByteArrayを使って保存しています。

 

ちなみにソースはこんなのです。

 

package
{
import com.adobe.images.*;
import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.utils.ByteArray;
public class main extends MovieClip
{
private var jpg:JPGEncoder = new JPGEncoder(100);
private var container:Sprite;
private var bmpdata:BitmapData;
private var btn:Sprite;
private var fr:FileReference;
public function main()
{
init();
}

private function init():void
{
//保存ダイアログを出すためのボタン。
btn = new Sprite();
btn.graphics.beginFill(0xff0000, 1);
btn.graphics.drawCircle( 0, 0, 10);
btn.graphics.endFill();
addChild(btn);
btn.width = btn.height = 10;
btn.x = btn.y = 320;
btn.addEventListener(MouseEvent.CLICK, onSave);
fr = new FileReference();
}
private function onSave(e:MouseEvent):void
{
bmpdata = new BitmapData(400, 400, true);
bmpdata.draw(stage);
var ba:ByteArray = new ByteArray();
// stageをBitmap化したものを、ByteArrayに変換。
ba = jpg.encode(bmpdata);
// 保存ダイアログを出す。
fr.save(ba, “astroSavedFile.jpg”);
}
}
}
いや、ほんとにastroはDynamic Sound Generationといい、すごい進化してますね。

 

[astro Dynamic Sound Generation] マウスで音程を変えるサンプル

LINEで送る
Pocket

またまたDynamic Sound Generationです。

これは、mouseXの値をもとに、音程を変えるというサンプルです。

ちなみに、音のもとになるのはぜんかいのと同じ矩形波を使っています。

ソースは後ほど。

サンプル(音が鳴り、そしてボリューム等の調整はできないです)。

[astro Dynamic Sound Genration] 矩形波で遊んでみた。

LINEで送る
Pocket

今回は色々とサンプルをつくってみながら書いてみます。

波形には色々とあるようですが、今回は、矩形波をいじってみました。

基本的なのは、これ。

ちなみに、512ってのはおまじないと思って下さい。

※サンプルFlash(音がなります。しかも制御できません。)

基本的な矩形波

 

で、矩形の周期を半分にすると、こうなります。

※サンプルFlash(こちらも音がなります。もちろん制御はできないです。)

半分周期の矩形波

 

二つを聴き比べると、二つ目(周期が短い方)が音が高いですよね。

どうやら、周期が短いほど音が高くなる、という仕組みらしいです。

 

と、いうことは、この周期を徐々に短くしていくと、どうなるんでしょう?

※サンプルFlash(音がなり、制御不能。今までと同様ですね。)

一応、「徐々に音が高く」なりましたよね?

 

うんうん。

ということは、これらをうにょうにょすると、宇宙っぽくできるかな?Perfumeっぽい音が出せるかな?○タヤスタカ的な音をasだけで出す事ができるのかな?

 

次は他のタイプの波形をいじってみようと思います。

 

あ、それぞれのサンプルASも.txtとしてリンク貼っておくのでよかったらいじって下さいね。(ごめんなさい。コメントつけれてないです)

  1. サンプル1(普通の矩形波)
  2. サンプル2(半分の矩形波)
  3. サンプル3(周期を動かしたやつ)

[flash astro]Dynamic Sound Generation 2.

LINEで送る
Pocket

またまたですが、Flash Player10 astroのDynamic Sound Generationです。

ボタンを押すと、音が流れます。

パルス波の長さを時間で変えています。

注意:音を止める方法がないので、音を消したい場合はリロードして下さい。

 

これがasだけでできるってのが素晴らしい!!

今、個人的にはこの辺の機能が楽しいなあ。

 

コードはこんなです。

main.as

<code>

package
{
import flash.net.*;
import flash.display.*;
import flash.media.*;
import flash.events.*;
[SWF(backgroundColor=”0xeeeeee”, frameRate=”50″, stageHeight=”200″)]
public class main extends Sprite
{
private var snd:Sound;
private var square:Sprite;
private var sh:Number = 200;
private var btn1:Sprite;
private var btn2:Sprite;
private var btn3:Sprite;
private var btn4:Sprite;
private var btn5:Sprite;
private var btn6:Sprite;
public function main()
{
initBtn();
}
private function initBtn():void
{
btn = new Sprite();
drawBtn(btn);
btn.buttonMode = true;
addChild(btn);
btn.width = btn.height = 20;
btn.x = 0;
btn.y = 0;
btn.addEventListener(MouseEvent.CLICK, click1);
}
private function drawBtn(sp:Sprite):void
{
sp.graphics.beginFill(0xff0000,1);
sp.graphics.drawRect(0, 0, 20, 20);
sp.graphics.endFill();
}
private function click1(e:MouseEvent):void
{
init();
doSamplesCallbackHandler(1);
}
private function init():void
{
snd = new Sound();
if( snd.hasEventListener(“samplesCallback”)) snd.removeEventListener(“samplesCallback”, samplesCallbackHandler);
snd.addEventListener(“samplesCallback”, samplesCallbackHandler);
snd.play();
}
private function samplesCallbackHandler(e:SamplesCallbackEvent):void
{
doSamplesCallbackHandler(1);
}
private var rate:Number = 44100;
private var freq:Number = 440;
private var phase:Number = 0;
private var count:Number = 1;
/**
* generate wave data.
*/
private function doSamplesCallbackHandler(type:int):void
{
//Voice.beep1();
var freq:Number = 220;
for( var i:uint=0; i < 512; i++ )
{
phase += freq/(rate);
var arrange:Number = 1;
var a:Number = 1;
if( i%2==0 ) a = 1;
arrange = a*count;
var phaseAngle:Number = phase * arrange;
var sample:Number = Math.sin(phaseAngle);
//ここで波形をつくってます。
sample = beep1(i);
//左右チャンネルともに同じ波形。
snd.samplesCallbackData.writeFloat(sample);
snd.samplesCallbackData.writeFloat(sample);
}
delim++;
if( delim > 256 ) delim = 0;
}
private var delim:Number = 0;
/**
* generate beep1
* @param i:uint wave counter.
* @return Number
*/
private function beep1(i:uint):Number
{
var res:Number =0;
//delim++;
//if( delim > 256 ) delim = 0;
//if( i < 256 ) res = 50;
//else res = 0;
if( i < delim ) res = 50;
else res = 0;
return res;
}
}
}

</code>