確率でトリガーするMIDIシーケンサー

09.06.21 Sun 23:44
Category: max/msp

morphseq

たまに音楽制作で使っているMax/MSPで作ったMIDIシーケンサーを、スクリーンキャプチャで動画にしてみました。(ブログ上だと画面が小さいのですが、vimeoのロゴの横のボタンを押すとフルスクリーンで見れます。またvimeoのページに飛んでもらえばHDでも見れます。)

動画ではMax/MSPから、Ableton Liveのサンプラーをトリガーしてます。
簡単に説明すると、32ステップのシーケンサーで、縦のスライダーが各ステップでMIDIをトリガーする確率になります。スライダーがマックスのときは必ずトリガーされ、半分だったら50%の確率でトリガーされます。
そのシーケンサーを左右で2機搭載しており、下のクロスフェーダーで切り替えられます。クロスフェーダーを真ん中にすると、ちょうど中間のパターンになる感じです。例えば、左のスライダーがマックスで、右のスライダーがゼロ、クロスフェーダーが真ん中だと、50%の確率でトリガーされます。このようにクロスフェードすることで、シーケンスのモーフィングみたいな効果が得られます。

メインのパッチは下の画像のようになってます。けっこうスッキリしているのは、ほとんどの計算をmaxのJavaScriptで処理してるためです。

morphseq3

OpenCV 顔認識

09.06.07 Sun 23:01
Category: processing

OpenCV のフェイス・トラッキングの実験を Processing でやってみました。
macbook のカメラからリアルタイムに顔を追跡して、曲線が顔を覆います。
線はスプライン曲線を Eric Natzke の Ribbon の要領で太さを持たせ、バネの仕組みで動かしてます。

制作途中、突然動かなくなって焦ったんですが、昼間すごく天気が良くて、逆光で顔を認識できてなかったのが原因でした。(笑)

Vimeo にアップロードしたら再圧縮で汚くなってしまったので、別で Quicktime 版もアップしております。
face_tracking_ribbon.mov

Catmull-Rom スプライン曲線

09.03.24 Tue 01:34
Category: actionscript

spline curve

スプライン曲線とは、与えられた複数の点を通る滑らかな曲線のことです。スプライン曲線を描くには、点と点の間を補完していくことになりますが、Catmull-Rom 補完とはその方法の一つになります。

Catmull-Romスプライン曲線

詳しい説明は上記ページに書かれていますが、これを as3 で書くとこうなります。

public function catmullRom(p0:Number,p1:Number,p2:Number,p3:Number,t:Number):Number
{
	var v0:Number = (p2 - p0) * 0.5;
	var v1:Number = (p3 - p1) * 0.5;
	return (2*p1 - 2*p2 + v0 + v1)*t*t*t +
		(-3*p1 + 3*p2 - 2*v0 - v1)*t*t + v0*t + p1;
}

t を 0〜1 に変化させることで、p1〜p2 間が補完されます。実際に曲線を描くには、曲線を分割(サンプルでは20分割)して擬似的な曲線(短い直線の集合)として描いていきます。分割数を1にすれば折れ線になります。

以下のサンプルは、赤い点をドラッグすれば曲線も変化します。

サンプル - Catmull-Rom スプライン曲線

package {
	import __AS3__.vec.Vector;

	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	[SWF(width="520", height="390", backgroundColor="#ffffff")]
	public class spline extends Sprite
	{
		private var points:Array;

		public function spline()
		{
			if(stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event=null):void
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			setup();
		}

		private function setup():void
		{
			points = new Array();
			var numPoints:uint = 6;//点の数
			for(var i:uint=0; i<numPoints; i++)
			{
				var point:Sprite = new Sprite();
				point.x = Math.round(Math.random() * stage.stageWidth);
				point.y = Math.round(Math.random() * stage.stageHeight);
				point.graphics.beginFill(0xff3366);
				point.graphics.drawCircle(0, 0, 3);
				point.graphics.endFill();
				point.buttonMode = true;
				point.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownListener);
				addChild(point);
				points.push(point);
			}

			setPoints();
		}

		private function setPoints():void
		{
			var v:Vector.<Point> = new Vector.<Point>();
			for(var i:uint; i<points.length; i++)
			{
				var point:Sprite = Sprite(points[i]);
				v[i] = new Point(point.x, point.y);
			}
			graphics.clear();
			drawSpline(v);
		}

		private function drawSpline(v:Vector.<Point>):void
		{
			if(v.length<2) return;
			v.splice(0,0,v[0]);
			v.push(v[v.length-1]);

			var numSegments:uint = 20;//曲線分割数(補完する数)
			for(var i:uint=0; i<v.length-3; i++)
			{
				var p0:Point = v[i];
				var p1:Point = v[i+1];
				var p2:Point = v[i+2];
				var p3:Point = v[i+3];
				splineTo(p0, p1, p2, p3, numSegments);
			}
		}

		private function splineTo(p0:Point, p1:Point, p2:Point,
			p3:Point, numSegments:uint):void
		{
			graphics.lineStyle(1, 0x666666);
			graphics.moveTo(p1.x, p1.y);
			for(var i:uint=0; i<numSegments; i++)
			{
				var t:Number = (i+1)/numSegments;
				graphics.lineTo(
					catmullRom(p0.x, p1.x, p2.x, p3.x, t),
					catmullRom(p0.y, p1.y, p2.y, p3.y, t)
				);
			}
		}

		public function catmullRom(p0:Number, p1:Number, p2:Number,
			p3:Number, t:Number):Number
		{
		    var v0:Number = (p2 - p0) * 0.5;
		    var v1:Number = (p3 - p1) * 0.5;
		    return (2*p1 - 2*p2 + v0 + v1)*t*t*t +
				(-3*p1 + 3*p2 - 2*v0 - v1)*t*t + v0*t + p1;
		}

		private function mouseDownListener(e:MouseEvent):void
		{
			var point:Sprite = Sprite(e.target);
			point.startDrag();
			point.addEventListener(MouseEvent.MOUSE_UP, mouseUpListener);
			addEventListener(Event.ENTER_FRAME, enterFrameListener);
		}

		private function mouseUpListener(e:MouseEvent):void
		{
			var point:Sprite = Sprite(e.target);
			point.stopDrag();
			point.removeEventListener(MouseEvent.MOUSE_UP, mouseUpListener);
			removeEventListener(Event.ENTER_FRAME, enterFrameListener);
		}

		private function enterFrameListener(e:Event):void
		{
			setPoints();
		}

	}
}
©2014 l00oo.oo00l blog | powered by WordPress with Barecity