/** * Hello Signals(AS3Signals required!!) * -drag your mouse to play * @author civet */ package { import flash.filters.BlurFilter; import flash.display.*; import flash.events.*; import frocessing.color.ColorHSV; import org.si.sion.*; import org.si.sion.utils.*; import com.bit101.components.*; [SWF(frameRate="30")] public class HelloSignals extends Sprite { public var mouseDown:NativeSignal; public var mouseUp:NativeSignal; public var mouseMove:NativeSignal; private var shape:Shape; private var circles:Array = []; private var currentCircle:ColorCircle; private var colorHSV:ColorHSV = new ColorHSV(); public function HelloSignals() { this.addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event):void { mouseDown = new NativeSignal(this.stage, MouseEvent.MOUSE_DOWN, MouseEvent); mouseUp = new NativeSignal(this.stage, MouseEvent.MOUSE_UP, MouseEvent); mouseMove = new NativeSignal(this.stage, MouseEvent.MOUSE_MOVE, MouseEvent); mouseDown.add(onMouseDown); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; shape = new Shape(); this.addChild(shape); this.addEventListener(Event.ENTER_FRAME, onEnterFrame); initSound(); } private function onMouseDown(e:Event):void { if(e.currentTarget != e.target && !(e.target is ColorCircle)) return; colorHSV.h += 6; colorHSV.h %= 360; var circle:ColorCircle = new ColorCircle(); circle.x = mouseX; circle.y = mouseY; circle.draw(4, colorHSV.value); this.addChild(circle); currentCircle = circle; mouseUp.addOnce(onMouseUp); mouseMove.add(onMouseMove); } private function onMouseMove(e:Event):void { shape.graphics.clear(); shape.graphics.lineStyle(2, currentCircle.color); shape.graphics.moveTo(currentCircle.x, currentCircle.y); shape.graphics.lineTo(mouseX, mouseY); } private function onMouseUp(e:Event):void { mouseMove.remove(onMouseMove); shape.graphics.clear(); var dx:Number = mouseX - currentCircle.x; var dy:Number = mouseY - currentCircle.y; var r:Number = Math.sqrt(dx*dx+dy*dy); currentCircle.draw(r, currentCircle.color); circles.push(currentCircle); //noteOn var length:Number = r/10; if(length == 0) return; var note:int = 60 + int((mouseX-stage.stageWidth*.5)/10); driver.noteOn(note, voice, length, 0); } private function onEnterFrame(e:Event):void { var i:int = circles.length; while(i--) { var circle:ColorCircle = circles[i]; if(circle.isDead) { circles.splice(i, 1); this.removeChild(circle); } else circle.fadeOut(); } } private var driver:SiONDriver; private var voice:SiONVoice; private var presetVoice:SiONPresetVoice; private var categoryList:ComboBox; private var voiceList:ComboBox; private function initSound():void { driver = new SiONDriver(); driver.play(); presetVoice = new SiONPresetVoice(); voice = new SiONVoice(5, 0); categoryList = new ComboBox(this); for each(var category:Array in presetVoice.categolies) categoryList.addItem( category[ "name" ] ); categoryList.addEventListener(Event.SELECT, onCategorySelect); voiceList = new ComboBox(this, 100, 0); voiceList.setSize(150, 20); voiceList.addEventListener(Event.SELECT, onVoiceSelect); categoryList.selectedIndex = 0; } private function onCategorySelect(e:Event):void { voiceList.removeAll(); var voices:Array = presetVoice[ categoryList.selectedItem ]; var length:uint = presetVoice[ categoryList.selectedItem ].length; for(var i:int = 0; i < length; ++i) voiceList.addItem( voices[i].name ) voiceList.selectedIndex = 0; } private function onVoiceSelect(e:Event):void { voice = presetVoice[ categoryList.selectedItem ][ voiceList.selectedIndex ]; } } } import flash.display.Sprite; class ColorCircle extends Sprite { private var _isDead:Boolean; private var _radius:Number; private var _color:uint; public function ColorCircle() { } public function draw(radius:Number, color:uint):void { _radius = radius; _color = color; this.graphics.clear() this.graphics.beginFill(_color); this.graphics.drawCircle(0, 0, _radius); this.graphics.endFill(); } public function fadeOut():void { if(_radius < 2) { _isDead = true; } else { _radius -= 2; this.draw(_radius, _color); } } public function get isDead():Boolean { return _isDead; } public function get color():uint { return _color; } public function get radius():Number { return _radius; } } /** * a part of RobertPenner's AS3Signals * http://github.com/robertpenner/as3-signals */ interface IDeluxeSignal { function get valueClasses():Array; function get numListeners():uint; function add(listener:Function, priority:int = 0):Function; function addOnce(listener:Function, priority:int = 0):Function; function remove(listener:Function):Function; } import flash.events.Event; import flash.events.IEventDispatcher; interface INativeDispatcher { function get eventType():String; function get eventClass():Class; function get target():IEventDispatcher; function dispatch(event:Event):Boolean; } import flash.errors.IllegalOperationError; import flash.events.Event; import flash.events.IEventDispatcher; /** * The NativeSignal class provides a strongly-typed facade for an IEventDispatcher. * A NativeSignal is essentially a mini-dispatcher locked to a specific event type and class. * It can become part of an interface. */ class NativeSignal implements IDeluxeSignal, INativeDispatcher { protected var _target:IEventDispatcher; protected var _eventType:String; protected var _eventClass:Class; protected var listenerBoxes:Array; /** * Creates a NativeSignal instance to dispatch events on behalf of a target object. * @param target The object on whose behalf the signal is dispatching events. * @param eventType The type of Event permitted to be dispatched from this signal. Corresponds to Event.type. * @param eventClass An optional class reference that enables an event type check in dispatch(). Defaults to flash.events.Event if omitted. */ public function NativeSignal(target:IEventDispatcher, eventType:String, eventClass:Class = null) { _target = target; _eventType = eventType; _eventClass = eventClass || Event; listenerBoxes = []; } public function get eventType():String { return _eventType; } public function get eventClass():Class { return _eventClass; } public function get valueClasses():Array { return [_eventClass]; } public function get numListeners():uint { return listenerBoxes.length; } public function get target():IEventDispatcher { return _target; } public function set target(value:IEventDispatcher):void { _target = value; } public function add(listener:Function, priority:int = 0):Function { registerListener(listener, false, priority); return listener; } public function addOnce(listener:Function, priority:int = 0):Function { registerListener(listener, true, priority); return listener; } public function remove(listener:Function):Function { var listenerIndex:int = indexOfListener(listener); if (listenerIndex == -1) return listener; var listenerBox:Object = listenerBoxes.splice(listenerIndex, 1)[0]; // For once listeners, execute is a wrapper function around the listener. _target.removeEventListener(_eventType, listenerBox.execute); return listener; } public function removeAll():void { for (var i:int = listenerBoxes.length; i--; ) { remove(listenerBoxes[i].listener as Function); } } public function dispatch(event:Event):Boolean { if (!(event is _eventClass)) throw new ArgumentError('Event object '+event+' is not an instance of '+_eventClass+'.'); if (event.type != _eventType) throw new ArgumentError('Event object has incorrect type. Expected <'+_eventType+'> but was <'+event.type+'>.'); return _target.dispatchEvent(event); } protected function registerListener(listener:Function, once:Boolean = false, priority:int = 0):void { // function.length is the number of arguments. if (listener.length != 1) throw new ArgumentError('Listener for native event must declare exactly 1 argument.'); var prevListenerIndex:int = indexOfListener(listener); if (prevListenerIndex >= 0) { // If the listener was previously added, definitely don't add it again. // But throw an exception in some cases, as the error messages explain. var prevlistenerBox:Object = listenerBoxes[prevListenerIndex]; if (prevlistenerBox.once && !once) { throw new IllegalOperationError('You cannot addOnce() then add() the same listener without removing the relationship first.'); } else if (!prevlistenerBox.once && once) { throw new IllegalOperationError('You cannot add() then addOnce() the same listener without removing the relationship first.'); } // Listener was already added, so do nothing. return; } var listenerBox:Object = { listener:listener, once:once, execute:listener }; if (once) { var signal:NativeSignal = this; // For once listeners, create a wrapper function to automatically remove the listener. listenerBox.execute = function(event:Event):void { signal.remove(listener); listener(event); }; } listenerBoxes[listenerBoxes.length] = listenerBox; _target.addEventListener(_eventType, listenerBox.execute, false, priority); } protected function indexOfListener(listener:Function):int { for (var i:int = listenerBoxes.length; i--; ) { if (listenerBoxes[i].listener == listener) return i; } return -1; } } Hello Signals