In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: SiON MML Edtor 2

SiON MML Editor
[USAGE] 
Write MML in the text field and Shift+Enter to play.
All MMLs in all pages are concatenated and play.
Ctrl+Z to undo, Ctrl+Y to redo (codes from psyark's Psycode)
------------------------------------------------------------
Get Adobe Flash player
by yonatan 18 Aug 2011
/**
 * Copyright yonatan ( http://wonderfl.net/user/yonatan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/hJAB
 */

// forked from keim_at_Si's SiON MML Edtor 2 
// SiON MML Editor
// [USAGE] 
//   Write MML in the text field and Shift+Enter to play.
//   All MMLs in all pages are concatenated and play.
//   Ctrl+Z to undo, Ctrl+Y to redo (codes from psyark's Psycode)
//------------------------------------------------------------
package {
    import flash.display.*;
    import flash.events.*;
    import flash.ui.Keyboard;
    
    [SWF(backgroundColor="#ffffff", frameRate="20")]
    public class main extends Sprite {
        function main() {
            stage.scaleMode = "noScale";
            stage.align = "TL";
            stage.stageFocusRect = false;
            addEventListener("addedToStage", _onAddedToStage);
            stage.addEventListener("resize", _onResize);
            stage.addEventListener("keyDown", _onKeyDown);
            driver.addEventListener("error", _onError);
            control = new ControlPanel(this);
            mmlEditor = new MMLEditor(this, 0, 0, _onTextChange);
            pageSelector = new PageSelector(this);
            message = new MessageBox(this);
            searchWindow = new SearchWindow(this);
        }
        
        private function _onAddedToStage(event:Event) : void {
            _updateSize();
            loadCookie();
        }
        
        private function _onResize(event:Event) : void {
            _updateSize();
        }
        
        private function _onKeyDown(event:KeyboardEvent) : void {
            switch (event.keyCode) {
				case Keyboard.ENTER:
                if (event.shiftKey) togglePlay();
                break;
            }
        }

        private function _onTextChange(length:int) : void {
            textLength = length;
            control.updateTrackLabel(false);
        }
        
        private function _onError(e:ErrorEvent) : void {
            message.show(e.text);
        }
        
        private function _updateSize() : void {
            control.setSize(stage.stageWidth, 24);
            mmlEditor.y = 24;
            mmlEditor.setSize(stage.stageWidth, stage.stageHeight - 48);
            pageSelector.y = stage.stageHeight - 24;
            pageSelector.setSize(stage.stageWidth, 24);
        }
    }
}


import flash.display.*;
import flash.geom.Rectangle;
import flash.text.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.net.*;
import flash.utils.*;
import com.bit101.components.*;
import org.si.sion.*;
import org.si.sion.events.*;
import org.si.sion.utils.Translator;
import org.si.sion.sequencer.base.*;


// Global variables
//--------------------------------------------------
var cookieName:String = "savedData";
var driver:SiONDriver = new SiONDriver();
var message:MessageBox;
var mmlEditor:MMLEditor;
var control:ControlPanel;
var pageSelector:PageSelector;
var searchWindow:SearchWindow;
var pageIndex:int = 0;
var soloIndex:int = -1;
var textLength:int = 0;


// Global functions
//--------------------------------------------------
function loadCookie() : void {
    var so:SharedObject = SharedObject.getLocal(cookieName);
    mmlEditor.xml = so.data.mmlxml;
}

function saveCookie() : void {
    var so:SharedObject = SharedObject.getLocal(cookieName);
    so.data.mmlxml = mmlEditor.xml;
    so.flush();
}

function togglePlay() : void {
    if (driver.isPlaying) {
        driver.stop();
        control.cbPlay(false);
    } else {
        saveCookie();
        driver.position = control.position * 1000;
        driver.play(mmlEditor.mml);
        control.cbPlay(true);
    }
}

function selectPage(index:int) : void {
    if (pageIndex != index) {
        control.cbPageChanged(index);
        mmlEditor.cbPageChanged(index);
        pageSelector.cbPageChanged(index);
        pageIndex = index;
    }
}

function setMute(index:int, bool:Boolean) : void {
    mmlEditor.cbMuteChanged(index, bool);
    pageSelector.cbMuteChanged(index, bool);
    control.cbPageChanged(pageIndex);
    soloIndex = -1;
}

function setSolo(index:int, bool:Boolean) : void {
    var i:int, mute:Boolean, imax:int = MMLEditor.FIELD_COUNT;
    for (i=0; i<imax; i++) {
        mute = bool && (i != index);
        mmlEditor.cbMuteChanged(i, mute);
        pageSelector.cbMuteChanged(i, mute);
    }
    soloIndex = (bool) ? index : -1;
    control.cbPageChanged(pageIndex);
}


// Message box
//--------------------------------------------------
class MessageBox extends Window {
    private var _text:Text, _button:PushButton;
    function MessageBox(parent:DisplayObjectContainer=null, title:String="Error") {
        super(parent, 100, 100, title);
        setSize(200, 160);
        _text   = new Text(content, 0, 0, "");
        _text.setSize(200, 120);
        _button = new PushButton(content, 76, 122, "OK", function(e:Event):void{visible = false;});
        _button.setSize(48,16);
        visible = false;
    }
    
    public function show(message:String="") : void {
        _text.text = message;
        visible = true;
    }
}


// Menu window
//--------------------------------------------------
class MenuPopup extends Panel {
    function MenuPopup(parent:DisplayObjectContainer=null) {
        super(parent, 263, 0);
        var y:int = 4;
        
        newButton("clear", clear);
        newButton("load", load);
        newButton("save as xml", saveXML);
        newButton("save as mml", saveMML);
        newButton("translate from TSSCP MML", transTSSCP);
        newButton("show search window", showSearch);
        setSize(200, y+2);
        this.y = -y-4;
        visible = false;
        
        function newButton(label:String, func:Function) : PushButton {
            var newButton:PushButton = new PushButton(content, 4, y, label, func);
            newButton.setSize(193, 16);
            y += 18;
            return newButton;
        }
    }
    
    public function clear(e:Event) : void {
        mmlEditor.mml = "";
        visible = false;
    }
    
    public function load(e:Event) : void {
        var fr:FileReference = new FileReference();
        fr.addEventListener("select", function(e:Event) : void { fr.load(); });
        fr.addEventListener("complete", _onLoaded);
        fr.browse();
        visible = false;
    }
    
    private function _onLoaded(e:Event) : void {
        var text:String = String(e.target.data);
        if (/^<MMLList/.test(text)) mmlEditor.xml = new XML(text);
        else mmlEditor.mml = text;
    }
    
    public function saveXML(e:Event) : void {
        new FileReference().save(mmlEditor.xml, "sionmml.xml");
        visible = false;
    }
    
    public function saveMML(e:Event) : void {
        new FileReference().save(mmlEditor.mml, "sionmml.txt");
        visible = false;
    }
    
    public function transTSSCP(e:Event) : void {
        mmlEditor.mml = Translator.tsscp(mmlEditor.mml, false);
        visible = false;
    }
    
    public function showSearch(e:Event) : void {
        searchWindow.visible = true;
        visible = false;
    }
}


// Search window
//--------------------------------------------------
class SearchWindow extends Window {
    public var input:InputText, execute:PushButton, regexp:CheckBox;
    function SearchWindow(parent:DisplayObjectContainer=null) {
        super(parent, 160, 160, "Search Window");
        input = new InputText(content, 4, 4, "");
        input.setSize(192, 16);
        execute = new PushButton(content, 148, 24, "sreach", _onSearch);
        execute.setSize(48, 16);
        regexp = new CheckBox(content, 30, 26, "use regular expression");
        new PushButton(this, 182, 3, "X", _onClose).setSize(15, 15);
        setSize(200, 60);
        visible = false;
    }
    
    private function _onClose(e:Event) : void {
        visible = false;
    }
    
    private function _onSearch(e:Event) : void {
        mmlEditor.colorSearchResult(input.text, regexp.selected);
    }
}


// Control panel
//--------------------------------------------------
class ControlPanel extends Panel {
    public var playButton:PushButton;
    public var posLabel:Label, posInput:InputText;
    public var muteCheck:CheckBox, soloCheck:CheckBox;
    public var loadLabel:Label, trackLabel:Label;
    
    function ControlPanel(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0) {
        super(parent, xpos, ypos);
        playButton = new PushButton(content, 2, 5, "play", function(e:Event):void { togglePlay(); });
        playButton.setSize(40, 16);
        posLabel = new Label(content, 50, 2, "position");
        posInput = new InputText(content, 90, 5, "0");
        trackLabel = new Label(content, 250, 2, "");
        loadLabel = new Label(content, 300, 2, "");
        posInput.setSize(40, 16);
        muteCheck = new CheckBox(content, 150, 8, "mute", _onMuteClick);
        soloCheck = new CheckBox(content, 200, 8, "solo", _onSoloClick);
        driver.addEventListener(SiONEvent.STREAM, _onStream);
    }
    
    public function get position() : int {
        return int(posInput.text);
    }

    public function updateTrackLabel(isPlaying:Boolean) : void {
        if (isPlaying) trackLabel.text = "track:" + String(driver.trackCount);
        else trackLabel.text = "letters:" + String(textLength);
    }
    public function cbPlay(bool:Boolean) : void {
        playButton.label = (bool) ? "stop" : "play";
        loadLabel.visible = bool;
        updateTrackLabel(bool);
    }
    public function cbPageChanged(index:int) : void {
        muteCheck.selected = mmlEditor.getMute(index);
        soloCheck.selected = (index == soloIndex);
    }
    private function _onStream(e:SiONEvent) : void { loadLabel.text = "load:" + String(driver.processTime) + "[ms]"; }
    private function _onMuteClick(e:Event) : void { setMute(pageIndex, muteCheck.selected); }
    private function _onSoloClick(e:Event) : void { setSolo(pageIndex, soloCheck.selected); }
}


// Pager
//--------------------------------------------------
class PageSelector extends Panel {
    public var pageSelector:Vector.<PushButton> = new Vector.<PushButton>(MMLEditor.FIELD_COUNT);
    public var pageMute:Vector.<Shape> = new Vector.<Shape>(MMLEditor.FIELD_COUNT);
    public var mergedButton:PushButton, menuButton:PushButton, menuPopup:MenuPopup;
    
    function PageSelector(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0) {
        super(parent, xpos, ypos);
        for (var i:int=0; i<MMLEditor.FIELD_COUNT; i++) {
            pageSelector[i] = new PushButton(content, i*50+64, 5, "page"+String(i+1), _onPageSelected);
            pageSelector[i].toggle = true;
            pageSelector[i].setSize(48, 16);
            pageSelector[i].addChild(pageMute[i] = new Shape());
            pageSelector[i].doubleClickEnabled = true;
            pageSelector[i].addEventListener("doubleClick", _onDoubleClick);
            pageMute[i].graphics.beginFill(0x000000, 0.25);
            pageMute[i].graphics.drawRect(0, 0, 48, 16);
            pageMute[i].graphics.endFill();
            pageMute[i].visible = false;
        }
        pageSelector[0].selected = true;
        mergedButton = new PushButton(content, 2, 5, "merged", _onMergedSelected);
        mergedButton.setSize(48, 16);
        menuButton = new PushButton(content, 415, 5, "menu", _onMenu);
        menuButton.setSize(48, 16);
        menuPopup = new MenuPopup(this);
    }

    public function cbPageChanged(index:int) : void {
        for (var i:int=0; i<MMLEditor.FIELD_COUNT; i++) pageSelector[i].selected = (index == i);
    }
    public function cbMuteChanged(index:int, mute:Boolean) : void { 
        if (index < MMLEditor.FIELD_COUNT) pageMute[index].visible = mute;
    }

    private function _onMergedSelected(e:Event) : void {
        mmlEditor.updateMergedMML();
        selectPage(MMLEditor.FIELD_COUNT);
    }
    
    private function _onMenu(e:Event) : void {
        menuPopup.visible = !menuPopup.visible;
    }
    
    private function _onPageSelected(e:Event) : void {
        selectPage(int((e.target.x-39)/50));
    }
    
    private function _onDoubleClick(e:Event) : void {
        var index:int = int((e.target.x-39)/50);
        setMute(index, !mmlEditor.getMute(index));
    }
    
    override public function setSize(w:Number, h:Number) : void {
        super.setSize(w, h);
        if (menuButton) menuButton.x = width - 50;
        if (menuPopup) menuPopup.x = width - 202;
    }
}


// Editor
//--------------------------------------------------
class MMLEditor extends Sprite {
    static public const FIELD_COUNT:int = 5; 
    static public const HELP_HEIGHT:int = 80; 
    public var sion140:Boolean = true;
    private var mmlFields:Vector.<MMLField> = new Vector.<MMLField>(FIELD_COUNT+1);
    private var helpText:TextArea;
	private var activeIndex:int = 0;
    
    function MMLEditor(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, func:Function=null) {
        if (parent) parent.addChild(this);
        this.x = xpos;
        this.y = ypos;
        
        MMLTextField.defaultFormat.size  = 12;
        MMLTextField.defaultFormat.font  = "MS Gothic, Courier, _typewriter, Courier New"; // it's the only monospace font that works for me
        MMLTextField.defaultFormat.color = 0x606060;
        MMLTextField.searchFormat.color = 0xc06060;
        MMLTextField.searchFormat.underline = true;
        MMLTextField.highlightFormat.color = 0x800000;
        for (var i:int=0; i<=FIELD_COUNT; i++) mmlFields[i] = new MMLField(this, (i==FIELD_COUNT), func);
		helpText = new TextArea(this);
		helpText.editable = false;
        mmlFields[0].visible = true;
		setInterval(_updateHelp, 500);
    }
    
    public function cbPageChanged(index:int) : void {
        for (var i:int=0; i<=FIELD_COUNT; i++) mmlFields[i].visible = false;
        mmlFields[index].visible = true;
        mmlFields[index].setFocus();
		activeIndex = index;
    }
    public function cbMuteChanged(index:int, mute:Boolean) : void {
        mmlFields[index].mute = mute;
    }
    
    public function getMute(index:int) : Boolean {
        return mmlFields[index].mute;
    }
    
    public function setSize(width:Number, height:Number) : void {
        for (var i:int=0; i<=FIELD_COUNT; i++) mmlFields[i].setSize(width, height - HELP_HEIGHT);
		helpText.y = mmlFields[0].y + mmlFields[0].height;
		helpText.setSize(width, HELP_HEIGHT);
    }
    
    public function set xml(list:XML) : void {
        if (list) {
            for (var i:int=0; i<FIELD_COUNT; i++) mmlFields[i].text = list.MML[i];
        }
    }
    
    public function get xml() : XML {
        var xml:XML = <MMLList version='1'/>, cont:String;
        for (var i:int=0; i<FIELD_COUNT; i++) {
            cont = "<![CDATA["+ mmlFields[i].text + "]]>";
            xml.appendChild(new XML("<MML field='" + String(i) + "'>" + cont + "</MML>"));
        }
        return xml;
    }
    
    public function set mml(text:String) : void {
        mmlFields[0].text = text;
        for (var i:int=1; i<FIELD_COUNT; i++) mmlFields[i].text = "";
    }
    
    public function get mml() : String {
        var i:int, result:String = "", text:String, rex:RegExp = /;\s*$/;
        for (i=0; i<FIELD_COUNT; i++) {
            text = mmlFields[i].text;
            if (!mmlFields[i].mute && text != "") {
                if (sion140) text = text.replace(/([A-Z]+(=|@?[0-9]*{))/g, "#$1").replace(/#+/g, "#"); //}
					if (rex.test(text)) result += text;
					else result += text + ";\n";
				}
			}
			return result;
		}
		
		public function updateMergedMML() : void {
			mmlFields[FIELD_COUNT].text = mml;
		}
		
		public function colorSearchResult(pattern:String, byRegExp:Boolean=false) : void {
			mmlFields[pageIndex].colorSearchResult(pattern, byRegExp);
		}

		private var _eventGlobalFlags:Vector.<Boolean> = new Vector.<Boolean> (MMLEvent.COMMAND_MAX, true); // global event flag
        private var _userDefinedEventID:Object = {};                    // id map of user-defined event letter set by newMMLEventListener().
		private function _updateHelp():void {
            Parser._setUserDefinedEventID(_userDefinedEventID);
            Parser._setGlobalEventFlags(_eventGlobalFlags);
			var setting:MMLParserSetting = new MMLParserSetting();
			try {
				Parser.prepareParse(setting, mmlFields[activeIndex].text);
				var event:MMLEvent = Parser.parse(0, mmlFields[activeIndex].tf.caretIndex);
			} catch(e:*) {
				helpText.text = "error: " + e.message;
				return;
			}

			helpText.text = "caretIndex " + mmlFields[activeIndex].tf.caretIndex + "\n";
			helpText.text += Parser.matchStart + '\n';
			helpText.text += Parser.matchEnd + '\n';
			helpText.text += 'Event: ' + Parser.eventAtCaret + '\n';
			mmlFields[activeIndex].tf.setTextFormat(MMLTextField.defaultFormat, 0, mmlFields[activeIndex].tf.length);
			if(Parser.eventAtCaret) {
				mmlFields[activeIndex].tf.setTextFormat(MMLTextField.highlightFormat, Parser.matchStart, Parser.matchEnd);
			}
		}
	}


	class MMLField extends Panel {
		private var textField:MMLTextField;
		private var scrollBar:CustomSlider;
		private var funcTextChange:Function;
		
		function MMLField(parent:DisplayObjectContainer, constant:Boolean=false, func:Function=null) {
			super(parent);
			funcTextChange = func;
			scrollBar = new CustomSlider("vertical", content, 0, 0, _onSliderChanged);
			scrollBar.backClick = true;
			textField = new MMLTextField(content, constant);
			textField.addEventListener("change", _onTextChanged);
			textField.addEventListener("scroll", _onTextScroll);
			visible = false;
		}
		
		public function get text() : String { return textField.text; }
		public function set text(mml:String) : void { textField.text = mml || ""; }
		
		public function get mute() : Boolean { return (textField.type == 'dynamic'); }
		public function set mute(bool:Boolean) : void {
			if (textField.constant || bool) {
				textField.type = 'dynamic';
				textField.backgroundColor = 0xc0c0c0;
			} else {
				textField.type = 'input';
				textField.backgroundColor = 0xffffff;
			}
		}
		
		override public function setSize(width:Number, height:Number) : void {
			super.setSize(width, height);
			if (textField) {
				textField.setSize(width - 15, height);
				scrollBar.setSize(15, height);
				scrollBar.x = width - 15;
				scrollBar.setRange(1, textField.maxScrollV, textField.scrollV, textField.numLines - textField.maxScrollV);
			}
		}
		
		public function setFocus() : void {
			stage.focus = textField;
		}
		
		private function _onSliderChanged(e:Event) : void {
			textField.scrollV = scrollBar.value;
			
		}
		
		private function _onTextChanged(e:Event) : void {
			scrollBar.setRange(1, textField.maxScrollV, textField.scrollV, textField.numLines - textField.maxScrollV);
			funcTextChange(textField.text.length);
		}
		
		private function _onTextScroll(e:Event) : void {
			scrollBar.setRange(1, textField.maxScrollV, textField.scrollV, textField.numLines - textField.maxScrollV);
		}
		
		public function colorSearchResult(pattern:String, byRegExp:Boolean=false) : void {
			textField.setTextFormat(MMLTextField.defaultFormat);
			
			var mml:String = textField.text;
			if (pattern != "") {
				if (byRegExp) {
					var res:*, rex:RegExp = new RegExp(pattern, "g");
					while (res = rex.exec(mml)) textField.setTextFormat(MMLTextField.searchFormat, res.index, res.index+res[0].length);
				} else {
					for (var i:int=0; i!=-1;) {
						i = mml.indexOf(pattern, i);
						if (i == -1) break;
						textField.setTextFormat(MMLTextField.searchFormat, i, i+pattern.length);
						i += pattern.length+1;
					}
				}
			}
		}

		public function get tf():MMLTextField { return textField; }
	}


	// Slider with stretching handle
	//--------------------------------------------------
	class CustomSlider extends Slider {
		protected var _handleLength:Number = 64, _isH:Boolean;
		function CustomSlider(orientation:String = "horizontal", parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number =  0, defaultHandler:Function = null) {
			super(orientation, parent, xpos, ypos, defaultHandler);
			_isH = (_orientation == "horizontal");
		}

		public function setRange(min:Number, max:Number, value:Number, range:Number) : void {
			setSliderParams(min, max, value);
			if (visible = (_min < _max)) {
				_handleLength = range / (range + max - min) * ((_isH) ? _width : _height);
				invalidate();
			}
		}
		
		override protected function drawHandle() : void {   
			_handle.graphics.clear();
			_handle.graphics.beginFill(Style.BUTTON_FACE);
			if (_isH) _handle.graphics.drawRect(1, 1, _handleLength - 2, _height - 2);
			else      _handle.graphics.drawRect(1, 1, _width - 2,  _handleLength - 2);
			_handle.graphics.endFill();
			positionHandle();
		}
		
		override protected function onDrag(event:MouseEvent) : void {
			stage.addEventListener(MouseEvent.MOUSE_UP, onDrop);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onSlide);
			if (_isH) _handle.startDrag(false, new Rectangle(0, 0, width - _handleLength, 0));
			else      _handle.startDrag(false, new Rectangle(0, 0, 0, height - _handleLength));
		}
		
		override protected function positionHandle() : void {
			if (_isH) _handle.x = (_value - _min) / (_max - _min) * (_width  - _handleLength);
			else      _handle.y = (_value - _min) / (_max - _min) * (_height - _handleLength);
		}

		override protected function onBackClick(event:MouseEvent) : void {
			if (_isH) {
				_handle.x = mouseX - _height / 2;
				_handle.x = Math.max(_handle.x, 0);
				_handle.x = Math.min(_handle.x, _width - _handleLength);
				_value = _handle.x / (_width - _handleLength) * (_max - _min) + _min;
			} else {
				_handle.y = mouseY - _width / 2;
				_handle.y = Math.max(_handle.y, 0);
				_handle.y = Math.min(_handle.y, _height - _handleLength);
				_value = _handle.y / (_height - _handleLength) * (_max - _min) + _min;
			}
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		override protected function onSlide(event:MouseEvent) : void {
			var oldValue:Number = _value;
			if (_isH) _value = _handle.x / (_width  - _handleLength) * (_max - _min + 1) + _min;
			else      _value = _handle.y / (_height - _handleLength) * (_max - _min + 1) + _min;
			if (_value != oldValue) dispatchEvent(new Event(Event.CHANGE));
		}
	}


	// undo and redo are from psyark's Psycode (modified)
	//--------------------------------------------------
	class MMLTextField extends TextField {
		public var constant:Boolean;
		private var _preventFollowingTextInput:Boolean = false;
		private var _prevText:String = "";
		private var _prevSBI:int;
		private var _prevSEI:int;
		private var _history:Vector.<HistoryItem> = new Vector.<HistoryItem>();
		private var _historyIndex:int;
		private var _ignoreChange:Boolean = false;
		
		static public var defaultFormat:TextFormat = new TextFormat();
		static public var searchFormat:TextFormat = new TextFormat();
		static public var highlightFormat:TextFormat = new TextFormat();
		
		function MMLTextField(parent:DisplayObjectContainer, constant:Boolean) {
			this.constant = constant;
			
			selectable = true; 
			alwaysShowSelection = true;
			mouseEnabled = true;
			type = (constant) ? 'dynamic' : 'input';
			multiline = true;
			wordWrap = false;
			background = true;
			backgroundColor = (constant) ? 0xc0c0c0 : 0xffffff;
			defaultTextFormat = defaultFormat;
			
			if (!constant) {
				addEventListener("change", _onChange);
				addEventListener("textInput", _onTextInput);
				addEventListener("keyDown", _onKeyDown);
			}
			
			parent.addChild(this);
			
			clearHistory();
		}
		
		public function setSize(width:Number, height:Number) : void {
			this.width  = width;
			this.height = height;
		}
		
		public function clearHistory() : void {
			_history.length = 0;
			_historyIndex = 0;
			_prevText = text;
		}
		
		private function _onChange(event:Event) : void {
			var res:*;
			if (_prevText != text) {
				if (_preventFollowingTextInput) {
					res = StringComparator.compare(_prevText, text);
					replaceText(res.l, length - res.r, _prevText.substring(res.l, _prevText.length - res.r).replace(/\r/g, "\n"));
					setSelection(_prevSBI, _prevSEI);
				} else {
					if (!_ignoreChange) {
						res = StringComparator.compare(_prevText, text);
						var item:HistoryItem = new HistoryItem(res.l);
						item.oldText = _prevText.substring(res.l, _prevText.length - res.r);
						item.newText = text.substring(res.l, text.length - res.r);
						_history.length = _historyIndex;
						_history.push(item);
						_historyIndex = _history.length;
					}
					_prevText = text;
					_prevSBI = selectionBeginIndex;
					_prevSEI = selectionEndIndex;
				}
			}
		}
        
		private function _onTextInput(event:Event) : void {
			if (_preventFollowingTextInput) event.preventDefault();
		}
        
		private function _onKeyDown(event:KeyboardEvent) : void {
			_preventFollowingTextInput = false;
			switch (event.keyCode) {
				case Keyboard.BACKSPACE:
				break;
				case 89: // Y
				if (event.ctrlKey) doCtrlY();
				break;
				case 90: // Z
				if (event.ctrlKey) doCtrlZ();
				break;
			}

			function doCtrlZ() : void {
				if (_history.length && _historyIndex > 0) {
					var item:HistoryItem = _history[_historyIndex - 1];
					replaceText(item.index, item.index + item.newText.length, item.oldText.replace(/\r/g, "\n"));
					setSelection(item.index + item.oldText.length, item.index + item.oldText.length);
					_historyIndex--;
					_dispatchIgnorableChangeEvent();
				}
				event.preventDefault();
				_preventFollowingTextInput = true;
			}

			function doCtrlY() : void {
				if (_history.length && _historyIndex < _history.length) {
					var item:HistoryItem = _history[_historyIndex];
					replaceText(item.index, item.index + item.oldText.length, item.newText.replace(/\r/g, "\n"));
					setSelection(item.index + item.newText.length, item.index + item.newText.length);
					_historyIndex++;
					_dispatchIgnorableChangeEvent();
				}
				event.preventDefault();
				_preventFollowingTextInput = true;
			}
		}
		
		private function _dispatchIgnorableChangeEvent():void {
			_ignoreChange = true;
			dispatchEvent(new Event("change"));
			_ignoreChange = false; 
		}
	}

	class HistoryItem {
		public var index:int;
		public var oldText:String;
		public var newText:String;
		
		public function HistoryItem(index:int=0, oldText:String="", newText:String="") {
			this.index   = index;
			this.oldText = oldText;
			this.newText = newText;
		}
	}

	class StringComparator {
		static public function compare(str1:String, str2:String) : * {
			var minLength:int = Math.min(str1.length, str2.length);
			var step:int, l:int, r:int;
			
			for (step=0x1000000; step>minLength;) step>>=1;
			for (l=0; l<minLength;) {
				if (str1.substr(0, l+step) != str2.substr(0, l+step)) {
					if (step == 1) { break; }
					step >>= 1;
				} else {
					l += step;
				}
			}
			l = Math.min(l, minLength);
			minLength -= l;
			
			for (step=0x1000000; step>minLength;) step>>=1;
			for (r=0; r<minLength;) {
				if (str1.substr(-r - step) != str2.substr(-r - step)) {
					if (step == 1) { break; }
					step >>= 1;
				} else {
					r += step;
				}
			}
			r = Math.min(r, minLength);
			
			return {"l":l, "r":r};
		}
	}





	//----------------------------------------------------------------------------------------------------
	// MML parser class
	//  Copyright (c) 2008 keim All rights reserved.
	//  Distributed under BSD-style license (see org.si.license.txt).
	//----------------------------------------------------------------------------------------------------

    import flash.utils.getTimer;
    
    /** MML parser class. */
    class Parser
    {
		// tables
		//--------------------------------------------------
        static private var _keySignitureTable:Array = [
            Vector.<int>([ 0, 0, 0, 0, 0, 0, 0]),
            Vector.<int>([ 0, 0, 0, 1, 0, 0, 0]),
            Vector.<int>([ 1, 0, 0, 1, 0, 0, 0]),
            Vector.<int>([ 1, 0, 0, 1, 1, 0, 0]),
            Vector.<int>([ 1, 1, 0, 1, 1, 0, 0]),
            Vector.<int>([ 1, 1, 0, 1, 1, 1, 0]),
            Vector.<int>([ 1, 1, 1, 1, 1, 1, 0]),
            Vector.<int>([ 1, 1, 1, 1, 1, 1, 1]),
            Vector.<int>([ 0, 0, 0, 0, 0, 0,-1]),
            Vector.<int>([ 0, 0,-1, 0, 0, 0,-1]),
            Vector.<int>([ 0, 0,-1, 0, 0,-1,-1]),
            Vector.<int>([ 0,-1,-1, 0, 0,-1,-1]),
            Vector.<int>([ 0,-1,-1, 0,-1,-1,-1]),
            Vector.<int>([-1,-1,-1, 0,-1,-1,-1]),
            Vector.<int>([-1,-1,-1,-1,-1,-1,-1])
        ];
        
        
        
        
		// valiables
		//--------------------------------------------------
        // settting
        static private var _setting:MMLParserSetting = null;
        
        // MML string
        static private var _mmlString:String = null;
        
        // user defined event map.
        static private var _userDefinedEventID:Object = null;
        
        // system event strings
        static private var _systemEventStrings:Vector.<String> = new Vector.<String>(32);
        static private var _sequenceMMLStrings:Vector.<String> = new Vector.<String>(32);
        
        // flag list of global event
        static private var _globalEventFlags:Vector.<Boolean> = null;
        
        // temporaries
        static private var _freeEventChain:MMLEvent = null;

        static private var _interruptInterval:int     = 0;
        static private var _startTime:int             = 0;
        static private var _parsingTime:int           = 0;
        
        static private var _staticLength:int          = 0;
        static private var _staticOctave:int          = 0;
        static private var _staticNoteShift:int       = 0;
        static private var _isLastEventLength:Boolean = false;
        static private var _systemEventIndex:int      = 0;
        static private var _sequenceMMLIndex:int      = 0;
        static private var _headMMLIndex:int          = 0;
        static private var _cacheMMLString:Boolean    = false;
        
        static private var _keyScale    :Vector.<int> = Vector.<int>([0,2,4,5,7,9,11]);
        static private var _keySigniture:Vector.<int> = _keySignitureTable[0];
        static private var _keySignitureCustom:Vector.<int> = new Vector.<int>(7, true);
        static private var _terminator      :MMLEvent = new MMLEvent();
        static private var _lastEvent       :MMLEvent = null;
        static private var _lastSequenceHead:MMLEvent = null;
        static private var _repeatStac:Array          = [];
        
        
        
        
		// properties
		//--------------------------------------------------
        /** Key signiture for all notes. The letter for key signiture is expressed as /[A-G][+\-#b]?m?/. */
        static public function set keySign(sign:String) : void
        {
            var note:int, i:int, list:Array, shift:String, noteLetters:String = "cdefgab";
            switch(sign) {
				case '':
				case 'C':   case 'Am':                          _keySigniture = _keySignitureTable[0];  break;
				case 'G':   case 'Em':                          _keySigniture = _keySignitureTable[1];  break;
				case 'D':   case 'Bm':                          _keySigniture = _keySignitureTable[2];  break;
				case 'A':   case 'F+m': case 'F#m':             _keySigniture = _keySignitureTable[3];  break;
				case 'E':   case 'C+m': case 'C#m':             _keySigniture = _keySignitureTable[4];  break;
				case 'B':   case 'G+m': case 'G#m':             _keySigniture = _keySignitureTable[5];  break;
				case 'F+':  case 'F#':  case 'D+m': case 'D#m': _keySigniture = _keySignitureTable[6];  break;
				case 'C+':  case 'C#':  case 'A+m': case 'A#m': _keySigniture = _keySignitureTable[7];  break;
				case 'F':   case 'Dm':                          _keySigniture = _keySignitureTable[8];  break;
				case 'B-':  case 'Bb':  case 'Gm':              _keySigniture = _keySignitureTable[9];  break;
				case 'E-':  case 'Eb':  case 'Cm':              _keySigniture = _keySignitureTable[10]; break;
				case 'A-':  case 'Ab':  case 'Fm':              _keySigniture = _keySignitureTable[11]; break;
				case 'D-':  case 'Db':  case 'B-m': case 'Bbm': _keySigniture = _keySignitureTable[12]; break;
				case 'G-':  case 'Gb':  case 'E-m': case 'Ebm': _keySigniture = _keySignitureTable[13]; break;
				case 'C-':  case 'Cb':  case 'A-m': case 'Abm': _keySigniture = _keySignitureTable[14]; break;
				default:
                for (i=0; i<7; i++) { _keySignitureCustom[i] = 0; }
                list = sign.split(/[\s,]/);
                for (i=0; i<list.length; i++) {
                    note = noteLetters.indexOf(list.charAt(0).toLowerCase());
                    if (note == -1) throw errorKeySign(sign);
                    if (list.length > 1) {
                        shift = list.charAt(1);
                        _keySignitureCustom[note] = (shift=='+' || shift=='#') ? 1 : (shift=='-' || shift=='b') ? -1 : 0;
                    } else {
                        _keySignitureCustom[note] = 0;
                    }
                }
                _keySigniture = _keySignitureCustom;
            }
        }
        
        
        /** Parsing progression (0-1). */
        static public function get parseProgress() : Number
        {
            if (_mmlString != null) {
                return _mmlRegExp.lastIndex / (_mmlString.length+1);
            }
            return 0;
        }
        
        
        
        
		// constructor
		//--------------------------------------------------
        /** constructer do nothing. */
        function Parser()
        {
        }
        
        
        
        
		// allocator
		//--------------------------------------------------
        /** @private [internal] Free all events in the sequence. */
        static internal function _freeAllEvents(seq:MMLSequence) : void
        {
            if (seq.headEvent == null) return;
            
            // connect to free list
            seq.tailEvent.next = _freeEventChain;
            
            // update head of free list
            _freeEventChain = seq.headEvent;

            // clear
            seq.headEvent = null;
            seq.tailEvent = null;
        }
        
        
        /** @private [internal] Free event. */
        static internal function _freeEvent(e:MMLEvent) : MMLEvent
        {
            var next:MMLEvent = e.next;
            e.next = _freeEventChain;
            _freeEventChain = e;
            return next;
        }
        
        
        /** @private [internal] allocate event */
        static internal function _allocEvent(id:int, data:int, length:int=0) : MMLEvent
        {
            if (_freeEventChain) {
                var e:MMLEvent = _freeEventChain;
                _freeEventChain = _freeEventChain.next;
                return e.initialize(id, data, length);
            }
            return (new MMLEvent()).initialize(id, data, length);
        }
        
        
        
        
		// settting
		//--------------------------------------------------
        /** @private [internal] Set map of user defined ids. */
        static internal function _setUserDefinedEventID(map:Object) : void
        {
            if (_userDefinedEventID !== map) {
                _userDefinedEventID = map;
                _mmlRegExp = null;
            }
        }
        
        
        /** @private [internal] Set array of global event flags. */
        static internal function _setGlobalEventFlags(flags:Vector.<Boolean>) : void
        {
            _globalEventFlags = flags;
        }
        
        
        
        
		// public operation
		//--------------------------------------------------
        /* Add new event. */
        static public function addMMLEvent(id:int, data:int=0, length:int=0, noteOption:Boolean=false) : MMLEvent
        {
            if (!noteOption) {
                // Make channel data chain
                if (id == MMLEvent.SEQUENCE_HEAD) {
                    _lastSequenceHead.jump = _lastEvent;
                    _lastSequenceHead = _pushMMLEvent(id, data, length);
                    _initialize_track();
                } else
                // Concatinate REST event
                if (id == MMLEvent.REST && _lastEvent.id == MMLEvent.REST) {
                    _lastEvent.length += length;
                } else {
                    _pushMMLEvent(id, data, length);
                    // seqHead.data is the count of global events
                    if (_globalEventFlags[id]) _lastSequenceHead.data++;
                }
            } else {
                // note option event is inserted after NOTE .
                if (_lastEvent.id == MMLEvent.NOTE) {
                    length = _lastEvent.length;
                    _lastEvent.length = 0;
                    _pushMMLEvent(id, data, length);
                } else {
                    // Error when there is no NOTE before SLUR event.
                    throw errorSyntax("* or &");
                }
            }
            
            _isLastEventLength = false;
            return _lastEvent;
        }
        
        
        /** Get MMLEvent id by mml command letter. 
        *  @param mmlCommand letter of MML command.
        *  @return Event id. Returns 0 if not found.
        */
        static public function getEventID(mmlCommand:String) : int
        {
            switch (mmlCommand) {
				case 'c': case 'd': case 'e': case 'f': case 'g': case 'a': case 'b':   return MMLEvent.NOTE;
				case 'r':   return MMLEvent.REST;
				case 'q':   return MMLEvent.QUANT_RATIO;
				case '@q':  return MMLEvent.QUANT_COUNT;
				case 'v':   return MMLEvent.VOLUME;
				case '@v':  return MMLEvent.FINE_VOLUME;
				case '%':   return MMLEvent.MOD_TYPE;
				case '@':   return MMLEvent.MOD_PARAM;
				case '@i':  return MMLEvent.INPUT_PIPE;
				case '@o':  return MMLEvent.OUTPUT_PIPE;
				case '(':   case ')':   return MMLEvent.VOLUME_SHIFT;
				case '&':   return MMLEvent.SLUR;
				case '&&':  return MMLEvent.SLUR_WEAK;
				case '*':   return MMLEvent.PITCHBEND;
				case ',':   return MMLEvent.PARAMETER;
				case '$':   return MMLEvent.REPEAT_ALL;
				case '[':   return MMLEvent.REPEAT_BEGIN;
				case ']':   return MMLEvent.REPEAT_END;
				case '|':   return MMLEvent.REPEAT_BREAK;
				case 't':   return MMLEvent.TEMPO;
            }
            return 0;
        }
        
        
        /** @private [internal] get command letters. */
        static internal function _getCommandLetters(list:Array) : void
        {
            list[MMLEvent.NOTE] = 'c'
            list[MMLEvent.REST] = 'r';
            list[MMLEvent.QUANT_RATIO] = 'q';
            list[MMLEvent.QUANT_COUNT] = '@q';
            list[MMLEvent.VOLUME] = 'v';
            list[MMLEvent.FINE_VOLUME] = '@v';
            list[MMLEvent.MOD_TYPE] = '%';
            list[MMLEvent.MOD_PARAM] = '@';
            list[MMLEvent.INPUT_PIPE] = '@i';
            list[MMLEvent.OUTPUT_PIPE] = '@o';
            list[MMLEvent.VOLUME_SHIFT] = '(';
            list[MMLEvent.SLUR] = '&';
            list[MMLEvent.SLUR_WEAK] = '&&';
            list[MMLEvent.PITCHBEND] = '*';
            list[MMLEvent.PARAMETER] = ',';
            list[MMLEvent.REPEAT_ALL] = '$';
            list[MMLEvent.REPEAT_BEGIN] = '[';
            list[MMLEvent.REPEAT_END] = ']';
            list[MMLEvent.REPEAT_BREAK] = '|';
            list[MMLEvent.TEMPO] = 't';
        }
        
        
        /** @private [internal] get system event string */
        static internal function _getSystemEventString(e:MMLEvent) : String
        {
            return _systemEventStrings[e.data];
        }
        
        
        /** @private [internal] get sequence mml string */
        static internal function _getSequenceMML(e:MMLEvent) : String
        {
            return (e.length == -1) ? "" : _sequenceMMLStrings[e.length];
        }
        

        // push event
        static private function _pushMMLEvent(id:int, data:int, length:int) : MMLEvent
        {
            _lastEvent.next = _allocEvent(id, data, length);
            _lastEvent = _lastEvent.next;
            return _lastEvent;
        }
        

        // register system event string
        static private function _regSystemEventString(str:String) : int
        {
            if (_systemEventStrings.length <= _systemEventIndex) _systemEventStrings.length = _systemEventStrings.length * 2;
            _systemEventStrings[_systemEventIndex++] = str;
            return _systemEventIndex - 1;
        }
        
        
        // register sequence MML string
        static private function _regSequenceMMLStrings(str:String) : int
        {
            if (_sequenceMMLStrings.length <= _sequenceMMLIndex) _sequenceMMLStrings.length = _sequenceMMLStrings.length * 2;
            _sequenceMMLStrings[_sequenceMMLIndex++] = str;
            return _sequenceMMLIndex - 1;
        }
        
        
        
		// regular expression
		//--------------------------------------------------
        static private const REX_WHITESPACE:int = 1;
        static private const REX_SYSTEM    :int = 2;
        static private const REX_COMMAND   :int = 3;
        static private const REX_NOTE      :int = 4;
        static private const REX_SHIFT_NOTE:int = 5;
        static private const REX_USER_EVENT:int = 6;
        static private const REX_EVENT     :int = 7;
        static private const REX_TABLE     :int = 8;
        static private const REX_PARAM     :int = 9;
        static private const REX_PERIOD    :int = 10;
        static private var _mmlRegExp:RegExp = null;
        static private function createRegExp(reset:Boolean) : RegExp
        {
            if (_mmlRegExp == null) {
                // user defined event letters
                var ude:Array = [];
                for (var letter:String in _userDefinedEventID) { ude.push(letter); }
                var uderex:String = (ude.length > 0) ? (ude.sort(Array.DESCENDING).join('|')) : 'a';    // ('A`) I know its an ad-hok solution...
                
                var rex:String;
                rex  = "(\\s+)";                                            // whitespace (res[1])
                rex += "|(#[^;]*)";                                         // system (res[2])
                rex += "|(";                                                // --all-- (res[3])
                rex += "([a-g])([\\-+#]?)";                                 // note (res[4],[5])
                rex += "|(" + uderex + ")";                                 // module events (res[6])
                rex += "|(@[qvio]?|&&|!@ns|[rlqovt^<>()\\[\\]/|$%&*,;])";   // default events (res[7])
                rex += "|(\\{.*?\\}[0-9]*\\*?[\\-0-9.]*\\+?[\\-0-9.]*)";    // table event (res[8])
                rex += ")\\s*(-?[0-9]*)"                                    // parameter (res[9])
                rex += "\\s*(\\.*)"                                         // periods (res[10])
                _mmlRegExp = new RegExp(rex, 'gms');
            }
            
            // reset last index
            if (reset) _mmlRegExp.lastIndex = 0;
            return _mmlRegExp;
        }
        
        
        
        
		// parser
		//--------------------------------------------------
        /** Prepare to parse. 
        *  @param mml MML String.
        *  @return Returns head MMLEvent. The return value of null means no head event.
        */
        static public function prepareParse(setting:MMLParserSetting, mml:String) : void
        {
            // set internal parameters
            _setting   = setting;
            _mmlString = mml;
            _parsingTime = getTimer();
            // create RegExp
            createRegExp(true);
            // initialize
            _initialize();
        }
        
        
        /** Parse mml string. 
        *  @param  interrupt Interrupting interval [ms]. 0 means no interruption. The interrupt appears between each sequence.
        *  @return Returns head MMLEvent. The return value of null means no head event.
        */
		static public var eventAtCaret:MMLEvent;
		static public var matchStart:int;
		static public var matchEnd:int;
        static public function parse(interrupt:int=0, caretIndex:int = -1) : MMLEvent
        {
            var shift:int, note:int, halt:Boolean, rex:RegExp, res:*,
            mml2nn:int = _setting.mml2nn,
            codeC:int = "c".charCodeAt();

			// set interrupting interval
			_interruptInterval = interrupt;
			_startTime         = getTimer();
			
			// regular expression
			rex = createRegExp(false);

			eventAtCaret = null;
			
			// parse
			halt = false;
			res = rex.exec(_mmlString);
			while (res && String(res[0]).length>0) {
				// skip comments
				if (res[REX_WHITESPACE] == undefined) {
					if (res[REX_NOTE]) {
						// note events.
						note  = String(res[REX_NOTE]).charCodeAt() - codeC;
						if (note < 0) note += 7;
						shift = _keySigniture[note];
						switch(String(res[REX_SHIFT_NOTE])) {
							case '+':   case '#':   shift++;    break;
							case '-':               shift--;    break;
						}
						_note(_keyScale[note] + shift + mml2nn, __calcLength(), __period());
					} else 
					if (res[REX_USER_EVENT]) {
						// user defined events.
						if (!String(res[REX_USER_EVENT]) in _userDefinedEventID) throw errorUnknown("REX_USER_EVENT");
						addMMLEvent(_userDefinedEventID[String(res[REX_USER_EVENT])], __param());
					} else
					if (res[REX_EVENT]) {
						// default events.
						switch(String(res[REX_EVENT])) {
							case 'r':   _rest     (__calcLength(), __period());          break;
							case 'l':   _length   (__calcLength(), __period());          break;
							case '^':   _tie      (__calcLength(), __period());          break;
							case 'o':   _octave   (__param(_setting.defaultOctave));     break;
							case 'q':   _quant    (__param(_setting.defaultQuantRatio)); break;
							case '@q':  _at_quant (__param(_setting.defaultQuantCount)); break;
							case 'v':   _volume   (__param(_setting.defaultVolume));     break;
							case '@v':  _at_volume(__param(_setting.defaultFineVolume)); break;
							case '%':   _mod_type (__param());                           break;
							case '@':   _mod_param(__param());                           break;
							case '@i':  _input (__param(0));        break;
							case '@o':  _output(__param(0));        break;
							case '(':   _volumeShift( __param(1));  break;
							case ')':   _volumeShift(-__param(1));  break;
							case '<':   _octaveShift( __param(1));  break;
							case '>':   _octaveShift(-__param(1));  break;
							case '&':   _slur();                    break;
							case '&&':  _slurweak();                break;
							case '*':   _portament();               break;
							case ',':   _parameter(__param());      break;
							case ';':   halt = _end_sequence();     break;
							case '$':   _repeatPoint();             break;
							case '[':   _repeatBegin(__param(2));   break;
							case ']':   _repeatEnd(__param());      break;
							case '|':   _repeatBreak();             break;
							case '!@ns': _noteShift( __param(0));               break;
							case 't':   _tempo(__param(_setting.defaultBPM));   break;
							default:
							throw errorUnknown("REX_EVENT;"+res[REX_EVENT]);
							break;
						}
					} else 
					if (res[REX_SYSTEM]) {
						// system command is only available at the top of the channel sequence.
						if (_lastEvent.id != MMLEvent.SEQUENCE_HEAD) throw errorSyntax(res[0]);
						// add system event
						addMMLEvent(MMLEvent.SYSTEM_EVENT, _regSystemEventString(res[REX_SYSTEM]));
					} else
					if (res[REX_TABLE]) {
						// add table event
						addMMLEvent(MMLEvent.TABLE_EVENT, _regSystemEventString(res[REX_TABLE]));
					} else {
						// syntax error
						throw errorSyntax(res[0]);
					}
				}

				if(res && res.index <= caretIndex && res.index + res[0].length > caretIndex) {
					eventAtCaret = _lastEvent;
					matchStart = res.index;
					matchEnd = matchStart + res[0].length;
				}
				// halt
				if (halt) return null;
				
				// parse next
				res = rex.exec(_mmlString);
			}
			
			// parsing complete
			// check repeating stac
			if (_repeatStac.length != 0) throw errorStacOverflow("[");
			// set last channel's last event.
			if (_lastEvent.id != MMLEvent.SEQUENCE_HEAD) _lastSequenceHead.jump = _lastEvent;

			// calculate parsing time
			_parsingTime = getTimer() - _parsingTime;

			// clear terminator
			var headEvent:MMLEvent = _terminator.next;
			_terminator.next = null;
			return headEvent;


			// internal functions
			//----------------------------------------
			// parse length. The return value of int.MIN_VALUE means abbreviation.
			function __calcLength() : int {
				if (String(res[REX_PARAM]).length == 0) return int.MIN_VALUE;
				var len:int = int(res[REX_PARAM]);
				if (len == 0) return 0;
				var iLength:int = _setting.resolution/len;
				if (iLength<1 || iLength>_setting.resolution) throw errorRangeOver("length", 1, _setting.resolution);
				return iLength;
			}
			
			// parse param.
			function __param(defaultValue:int = int.MIN_VALUE) : int {
				return (String(res[REX_PARAM]).length > 0) ? int(res[REX_PARAM]) : defaultValue;
			}
			
			// parse periods.
			function __period() : int {
				return String(res[REX_PERIOD]).length;
			}
		}
		
        
        
        // initialize before parse
        static private function _initialize() : void
        {
            // free all remains
            var e:MMLEvent = _terminator.next;
            while (e) { e = _freeEvent(e); }
            
            // initialize tempraries
            _systemEventIndex = 0;                                            // system event index
            _sequenceMMLIndex = 0;                                            // sequence mml index
            _lastEvent        = _terminator;                                  // clear event chain
            _lastSequenceHead = _pushMMLEvent(MMLEvent.SEQUENCE_HEAD, 0, 0);  // add first event (SEQUENCE_HEAD).
            if (_cacheMMLString) addMMLEvent(MMLEvent.DEBUG_INFO, -1);
            _initialize_track();
        }
        
        
        // initialize before starting new track.
        static private function _initialize_track() : void
        {
            _staticLength      = _setting.defaultLength;    // initialize l command value
            _staticOctave      = _setting.defaultOctave;    // initialize o command value
            _staticNoteShift   = 0;                         // initialize note shift
            _isLastEventLength = false;                     // initialize l command flag
            _repeatStac.length = 0;                         // clear repeating pointer stac
            _headMMLIndex      = _mmlRegExp.lastIndex;      // mml index of sequence head
        }
        
        
        
        
		// note
		//------------------------------
        // note
        static private function _note(note:int, iLength:int, period:int) : void
        {
            note += _staticOctave*12 + _staticNoteShift;
            if (note < 0) {
                //throw errorNoteOutofRange(note);
                note = 0;
            } else 
            if (note > 127) {
                //throw errorNoteOutofRange(note);
                note = 127;
            }
            addMMLEvent(MMLEvent.NOTE, note, __calcLength(iLength, period));
        }
        
        
        // rest
        static private function _rest(iLength:int, period:int) : void
        {
            addMMLEvent(MMLEvent.REST, 0, __calcLength(iLength, period));
        }
        
        
		// length operation
		//------------------------------
        // length
        static private function _length(iLength:int, period:int) : void
        {
            _staticLength = __calcLength(iLength, period);
            _isLastEventLength = true;
        }
        
        
        // tie
        static private function _tie(iLength:int, period:int) : void
        {
            if (_isLastEventLength) {
                _staticLength += __calcLength(iLength, period);
            } else 
            if (_lastEvent.id == MMLEvent.REST || _lastEvent.id == MMLEvent.NOTE) {
                _lastEvent.length += __calcLength(iLength, period);
            } else {
                throw errorSyntax("tie command");
            }
        }
        
        
        // slur
        static private function _slur() : void
        {
            addMMLEvent(MMLEvent.SLUR, 0, 0, true);
        }
        
        
        // weak slur
        static private function _slurweak() : void
        {
            addMMLEvent(MMLEvent.SLUR_WEAK, 0, 0, true);
        }
        
        
        // portament
        static private function _portament() : void
        {
            addMMLEvent(MMLEvent.PITCHBEND, 0, 0, true);
        }
        
        
        // gate time
        static private function _quant(param:int) : void
        {
            if (param<_setting.minQuantRatio || param>_setting.maxQuantRatio) {
                throw errorRangeOver("q", _setting.minQuantRatio, _setting.maxQuantRatio);
            }
            addMMLEvent(MMLEvent.QUANT_RATIO, param);
        }
        
        
        // absolute gate time
        static private function _at_quant(param:int) : void
        {
            if (param<_setting.minQuantCount || param>_setting.maxQuantCount) {
                throw errorRangeOver("@q", _setting.minQuantCount, _setting.maxQuantCount);
            }
            addMMLEvent(MMLEvent.QUANT_COUNT, param);
        }
        
        
        // calculate length
        static private function __calcLength(iLength:int, period:int) : int
        {
            // set default value
            if (iLength == int.MIN_VALUE) iLength = _staticLength;
            // extension by period
            var len:int = iLength;
            while (period>0) { iLength += len>>(period--); }
            return iLength;
        }
        
        
		// pitch operation
		//------------------------------
        // octave
        static private function _octave(param:int) : void
        {
            if (param<_setting.minOctave || param>_setting.maxOctave) {
                throw errorRangeOver("o", _setting.minOctave, _setting.maxOctave);
            }
            _staticOctave = param;
        }
        
        
        // octave shift
        static private function _octaveShift(param:int) : void
        {
            param *= _setting.octavePolarization;
            _staticOctave += param;
        }
        

        // note shift
        static private function _noteShift(param:int) : void
        {
            _staticNoteShift += param;
        }
        
        
        // volume
        static private function _volume(param:int) : void
        {
            if (param<0 || param>_setting.maxVolume) {
                throw errorRangeOver("v", 0, _setting.maxVolume);
            }
            addMMLEvent(MMLEvent.VOLUME, param);
        }
        
        
        // fine volume
        static private function _at_volume(param:int) : void
        {
            if (param<0 || param>_setting.maxFineVolume) {
                throw errorRangeOver("@v", 0, _setting.maxFineVolume);
            }
            addMMLEvent(MMLEvent.FINE_VOLUME, param);
        }
        
        
        // volume shift
        static private function _volumeShift(param:int) : void
        {
            param *= _setting.volumePolarization;
            if (_lastEvent.id == MMLEvent.VOLUME_SHIFT || _lastEvent.id == MMLEvent.VOLUME) {
                _lastEvent.data += param;
            } else {
                addMMLEvent(MMLEvent.VOLUME_SHIFT, param);
            }
        }
        
        
		// repeating
		//------------------------------
        // repeat point
        static private function _repeatPoint() : void
        {
            addMMLEvent(MMLEvent.REPEAT_ALL, 0);
        }
        
        
        // begin repeating
        static private function _repeatBegin(rep:int) : void
        {
            if (rep < 1 || rep > 65535) throw errorRangeOver("[", 1, 65535);
            addMMLEvent(MMLEvent.REPEAT_BEGIN, rep, 0);
            _repeatStac.unshift(_lastEvent);
        }
        
        
        // break repeating
        static private function _repeatBreak() : void
        {
            if (_repeatStac.length == 0) throw errorStacUnderflow("|");
            addMMLEvent(MMLEvent.REPEAT_BREAK);
            _lastEvent.jump = MMLEvent(_repeatStac[0]);
        }
        
        
        // end repeating
        static private function _repeatEnd(rep:int) : void
        {
            if (_repeatStac.length == 0) throw errorStacUnderflow("]");
            addMMLEvent(MMLEvent.REPEAT_END);
            var beginEvent:MMLEvent = MMLEvent(_repeatStac.shift());
            _lastEvent.jump = beginEvent;   // rep_end.jump   = rep_start
            beginEvent.jump = _lastEvent;   // rep_start.jump = rep_end
            
            // update repeat count
            if (rep != int.MIN_VALUE) {
                if (rep < 1 || rep > 65535) throw errorRangeOver("]", 1, 65535);
                beginEvent.data = rep;
            }
        }
        
        
		// others
		//------------------------------
        // module type
        static private function _mod_type(param:int) : void
        {
            addMMLEvent(MMLEvent.MOD_TYPE, param);
        }
        
        
        // module parameters
        static private function _mod_param(param:int) : void
        {
            addMMLEvent(MMLEvent.MOD_PARAM, param);
        }
        
        
        // set input pipe
        static private function _input(param:int) : void
        {
            addMMLEvent(MMLEvent.INPUT_PIPE, param);
        }
        
        
        // set output pipe
        static private function _output(param:int) : void
        {
            addMMLEvent(MMLEvent.OUTPUT_PIPE, param);
        }
        
        
        // pural parameters
        static private function _parameter(param:int) : void
        {
            addMMLEvent(MMLEvent.PARAMETER, param);
        }
        
        
        // sequence change
        static private function _end_sequence() : Boolean
        {
            if (_lastEvent.id != MMLEvent.SEQUENCE_HEAD) {
                if (_lastSequenceHead.next && _lastSequenceHead.next.id == MMLEvent.DEBUG_INFO) {
                    // memory sequence MMLs id in _lastSequenceHead.next.data
                    _lastSequenceHead.next.data = _regSequenceMMLStrings(_mmlString.substring(_headMMLIndex, _mmlRegExp.lastIndex));
                }
                addMMLEvent(MMLEvent.SEQUENCE_HEAD, 0);
                if (_cacheMMLString) addMMLEvent(MMLEvent.DEBUG_INFO, -1);
                // Returns true when it has to interrupt.
                if (_interruptInterval == 0) return false;
                return (_interruptInterval < (getTimer() - _startTime));
            }
            return false;
        }
        
        
        // tempo
        static private function _tempo(t:int) : void
        {
            addMMLEvent(MMLEvent.TEMPO, t);
        }
        
        
        
        
		// errors
		//--------------------------------------------------
        static public function errorUnknown(n:String) : Error
        {
            return new Error("MMLParser Error : Unknown error #" + n + ".");
        }
        

        static public function errorNoteOutofRange(note:int) : Error
        {
            return new Error("MMLParser Error : Note #" + note + " is out of range.");
        }
        
        
        static public function errorSyntax(syn:String) : Error
        {
            return new Error("MMLParser Error : Syntax error '" + syn + "'.");
        }
        
        
        static public function errorRangeOver(cmd:String, min:int, max:int) : Error
        {
            return new Error("MMLParser Error : The parameter of '" + cmd + "' command must ragne from " + min + " to " + max + ".");
        }


        static public function errorStacUnderflow(cmd:String) : Error
        {
            return new Error("MMLParser Error : The stac of '" + cmd + "' command is underflow.");
        }
        
        
        static public function errorStacOverflow(cmd:String) : Error
        {
            return new Error("MMLParser Error : The stac of '" + cmd + "' command is overflow.");
        }
        
        
        static public function errorKeySign(ksign:String) : Error
        {
            return new Error("MMLParser Error : Cannot recognize '" + ksign + "' as a key signiture.");
        }
    }