2009
1213

FlashとWiiリモコンでテルミンを作るサンプル

先日の大阪てらこで発表しようとして完成できなかったWiiリモコンのテルミンをちゃんと作りました。

機能は以下のとおり。
Aボタンを押し続けてる間、音が出ます。
前後に傾けると音程が変わり、左右に傾けるとリングモジュレーションというエフェクトがかかるようになっています。
Bボタンを押し続けてる間、音程とエフェクトの強さがロックされます。

Wiiリモコンの代わりにマウスで操作できるものも用意しました。
クリックすると音がでます。
マウスを上下に移動すると音程が変わり、左右に移動するとエフェクトのかかり具合が変わります。

WiiFlashについて

WiiリモコンとFlashの通信のためにWiiFlashというライブラリを使っています。これを使うと簡単にWiiリモコンと通信が出来るのですが、ある日ソフトウェアアップデートでJavaが最新版になるとMacでちゃんと動かなくなりました。(最初の1分くらいは普通に動いてその後フリーズ)

Saqoosha氏の教えてくれたOSCを使う方法なら回避できそうだけど、いろいろと作り替える必要があるので、とりあえずWiiFlashを使う方法を書いておきます。
ちなみにOSCを使う場合は、OSCulatorていうソフトとfloscていうソフトとflsocと通信するためのAS3クラスを使うと良いみたい。

【参考】
http://saqoosha.net/2009/10/26/1781/
http://akamatsu.org/aka/?p=670

WiiFlashで簡単にWiiリモコンを入力インターフェイスとして使う

WiiFlashでWiiリモコンに接続するのはすごく簡単です。これだけ。

var wiimote:Wiimote = new Wiimote();
wiimote.connect();

Wiiリモコンのボタンのイベントを取得するにはorg.wiiflash.events.ButtonEventに定義されているイベントを利用します。例えばAボタンならこんな感じです。

//Aボタンが押されたとき
wiimote.addEventListener( ButtonEvent.A_PRESS, _onAPress );
//Aボタンが離されたとき
wiimote.addEventListener( ButtonEvent.A_RELEASE, _onARelease );

Wiiリモコンの加速度センサー(3軸の傾きを検出できるセンサー)の値を取得するには org.wiiflash.events.WiimoteEventのUPDATEイベントを利用します。
傾きはWiimoteEventrollpitchyawの3つのプロパティで取得できます。

//Aボタンが押されたとき
wiimote.addEventListener( WiimoteEvent.UPDATE, _onUpdate );

private function _onUpdate( i_event: WiimoteEvent ):void {
	trace( i_event.target.roll );
	trace( i_event.target.pitch );
	trace(  i_event.target.yaw );
}

Wiiリモコンが振られたことを検出するときは、UPDATEイベントを利用して、上記のプロパティの値が大きく変化するのを監視する必要があります。

簡単にWiiリモコンの加速度センサーの値を取得するだけのサンプルをこちらからダウンロードできます。 wii_remote.zip (60KB)

テルミンのサンプル

てらこで最後まで作れなかったテルミンを完成させたのでソースを置いておきます。
theremin.zip (68KB)
普通にアプリとして書き出したものも置いておきます。(Mac&Win)
theremin_app.zip (7.6MB)

※Wiiリモコンと接続するためにはWiiFlashServerというソフトを起動しておく必要があります。
WiiFlashのサイトの左にあるメニューの「Download」からダウンロードできます。
Windowsの場合、解凍したファイルの「Servers」というフォルダにある「WiiFlashServer 0.4.5.exe」というファイルを開けばサーバーが起動します。Macの場合は「WiiFlashServerJ_2008_12_21.zip」を解凍して「WiiFlashServerJ.app」を起動すれば使えるのですが、バグがあり、数分使っていると固まります。

音の生成

ソースには「Theremin.as」と「SampleGenerator.as」の2つのクラスがあります。

SampleGeneratorが音を生成するためのクラスです。
toneというプロパティに0〜1の値を設定すると周波数が110(A2:真ん中から2オクターブ下のラ)から880(A5:真ん中から1オクターブ上のラ)まで変化します。
modulationというプロパティに0〜1の値を設定するとリング変調というエフェクトがかかり具合が調整でき、0だと全くエフェクトがかからないようになります。
リング変調は元の波形に別の波形を掛け合わせるもので、このサンプルでは20Hzのサイン波を2回掛け合わせたものを基本の波形に掛け合わせています。高速なトレモロエフェクトみたいな感じです。
以下がサンプル生成部分のソースです。


public static const SAMPLE_RATE:uint = 44100;	//サンプルレート
public static const PI2:Number = Math.PI * 2;	//2π。負荷軽減のため定数に
public static const BUFFER_SIZE:uint = 2048;	//バッファサイズ(2048〜8192)
public static const FREQUENCY:uint = 110;		//基本の周波数(一番低い音)
public static const MOD_FREQUENCY:uint = 20;	//リング変調の周波数


private var _tone:Number = 0;					//設定された音程の指数
private var __tone:Number = 0;				//実際の音程の指数
private var _modulation:Number = 0;			//設定されたリング変調の強さ
private var __modulation:Number = 0;			//実際のリング変調の強さ
private var _phase:Number = 0;				//位相
private var _modPhase:Number = 0;			//リング変調の位相


/*--------------------------------------------------
* サンプルの生成
--------------------------------------------------*/

private function _onSampleData( i_event:SampleDataEvent ):void  {
	
	var amp:Number, mod:Number;
	
	//バッファ処理の各サンプルごとに__toneの値を_toneの値まで近づけて滑らかに
	var toneOffset:Number = 0;
	if ( __tone != _tone ) {
		toneOffset = ( _tone - __tone ) / BUFFER_SIZE;
	}
	
	//バッファ処理の各サンプルごとに__modulationの値を_modulationの値まで近づけて滑らかに
	var modulationOffset:Number = 0;
	if ( __modulation != _modulation ) {
		modulationOffset = ( _modulation - __modulation ) / BUFFER_SIZE;
	}
	
	//バッファ
	for ( var c:uint=0; c<BUFFER_SIZE; c++ ) {

		__tone += toneOffset;
		__modulation += modulationOffset;

		//__toneが0の場合はFREQUENCYそのまま、1の場合は8倍になるようにして位相の増分を計算
		_phase += PI2 * ( FREQUENCY * Math.pow( 8, __tone ) ) / SAMPLE_RATE;
		
		//基本の波形
		amp = Math.sin( _phase );
		
		//リング変調。
		_modPhase += PI2 * ( MOD_FREQUENCY ) / SAMPLE_RATE;
		mod = Math.sin(_modPhase);
		
		//リング変調の値を掛け合わせる。_modulationは変調の強さ。(modを2回かけてエフェクトを強調)
		amp = amp + ( ( ( amp *  mod * mod ) - amp ) * _modulation );
		
		//
		i_event.data.writeFloat(amp);	// 左チャネルの音
		i_event.data.writeFloat(amp);	// 右チャネルの音
		
	}
	
}

Wiiリモコンからコントロール

Thereminクラスから上記のSampleGeneratorクラスのインスタンス(サンプル中の変数名:gen)を生成して、Wiiリモコンの前後の傾き(pitch)を音程(tone)にアサインし、左右の傾き(roll)をリング変調のかかり具合(modulation)にアサインしています。

//加速度センサーの値に変化があったとき
private function _onUpdated( i_event:WiimoteEvent ):void {
	//Bボタンが押されている場合は音程を変化させない
	if ( _wiimote.b ) return;
	
	//音程。前後に傾ければ音程が変わる。
	//だいたい-1.5〜1.5の値が返ってくるのでそれを0〜1の数値に変換
	gen.tone = ( i_event.target.pitch * -1 + 1.5 ) / 3;
	
	//モジュレーションの強さ。左右に傾ければ強くなる
	gen.modulation = Math.abs(i_event.target.roll);
}

コメント

Comments
+2009.12.15 by cp

JAVAのアップデートでおかしくなったけど
Rosettaを使って開くにチェックを入れたら問題なくwiiflash使えるようになったよ。
また新しいアプリ楽しみにしています!

トラックバック

TrackBacks

TrackBack URL : http://www.starryworks.co.jp/mt/mt-tb.cgi/116