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

Score Tracking

Track audio performance with your score (MIDI) file.
Get Adobe Flash player
by potato-attack 30 Jul 2011
/**
 * Copyright potato-attack ( http://wonderfl.net/user/potato-attack )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/oUmB
 */

package
{
  import adobe.utils.CustomActions;
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.BlendMode;
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageQuality;
  import flash.display.StageScaleMode;
  import flash.events.*;
  import flash.events.SampleDataEvent;
  import flash.geom.Point;
  import flash.geom.Rectangle;
  import flash.media.Microphone;
  import flash.media.Sound;
  import flash.media.SoundChannel;
  import flash.utils.ByteArray;
  import flash.utils.getTimer;

  import flash.display.*;
  import flash.text.*;
  import flash.net.*;
  //  import flash.utils.ByteArray;
  import mx.utils.Base64Decoder;

  /**
   * Real-time Sound Visualizer
   *
   * @author Kosuke Suzuki
   */
  public class Main extends Sprite
    {
      //----------------------------------------
      //CLASS CONSTANTS

      private const ZEROS:Point = new Point();
      
      



      //----------------------------------------
      //VARIABLES

      /**
       * マイクロフォン
       */
      private var _mic:Microphone;

      /**
       * 録音用
       */
      private var _records:Vector.<Number>;

      /**
       * 再生用
       */
      private var _sound:Sound;
      private var _soundChannel:SoundChannel;

      /**
       * 録音、再生ヘッダ
       */
      private var _position:int;

      /**
       * 描画用
       */
      private var _canvas:BitmapData;
      private var _slit:BitmapData;
      private var _over:Sprite;
      
      private var _canvas_under:BitmapData;


      private var _pitch:PitchShifter;

      private var _fftFrameSize:int = 4096;
      private var samplingFreq:Number = 44100;      
      
      private var windowValues        :Vector.<Number>;

      private var _constantQfilterbank:FilterBank;
      private var _channels:int = 60; // the number of pitch
      private var _fl:Number = 50.0;  // The lowest frequency
      private var _Q:Number  = 60.0;  // Q value

      private var textfield:TextField = new TextField();
      private var information:TextField = new TextField();


      private var button:Sprite = new Sprite();
      private var buttontext:TextField = new TextField();
      private var fileReference:FileReference;

        private var button2:Sprite = new Sprite();
      private var button2text:TextField = new TextField();

      
      private var midi:ScoreFollow;

      //private var midiPlayer:MIDIPlayer;
      //----------------------------------------
      //STAGE INSTANCES





      //----------------------------------------
      //METHODS

      /**
       * Constructer
       */
      public function Main():void
        {
          
            // prepare constant Q filterbank
            _constantQfilterbank = new FilterBank(samplingFreq, _fftFrameSize, _Q, _fl, _channels);
            
          //Wonderfl.disable_capture();

          stage.align = StageAlign.TOP_LEFT;
          stage.scaleMode = StageScaleMode.NO_SCALE;
          stage.quality = StageQuality.LOW;

          _mic = Microphone.getMicrophone();
          _mic.rate = 44;
          _mic.setSilenceLevel(0);
          _mic.setUseEchoSuppression(true);

          _sound = new Sound();

          _canvas = new BitmapData(stage.stageWidth, stage.stageHeight/2, false, 0x0000ff);
          _slit = new BitmapData(1, stage.stageHeight/2, false, 0x000000);
          addChild( new Bitmap(_canvas) );
          
          //_over = addChild( new Sprite() ) as Sprite;
          //_over.graphics.beginFill(0x0);
          //_over.graphics.drawRect(0, 0, 100, 100);
          //_over.graphics.endFill();
          //
          //_over.blendMode = BlendMode.INVERT; // invert the background color
          //
        
          _canvas_under = new BitmapData(stage.stageWidth, stage.stageHeight / 2, false, 0x000077);
          var _canvas_under_bitmap:Bitmap = new Bitmap(_canvas_under);
          _canvas_under_bitmap.y = stage.stageHeight / 2;
          addChild(_canvas_under_bitmap);
          
          windowValues            = new Vector.<Number>(_fftFrameSize);
          //windowValuesFactored    = new Vector.<Number>(fftFrameSize);

          //var invFftFrameSize2:Number = 2.0 / (fftFrameSize2 * osamp
          var PI:Number        = Math.PI;
          var invFftFrameSizePI2:Number = PI * 2 / _fftFrameSize;
          for (var k:int = 0, t:Number = 0.0; k < _fftFrameSize; ++k, t += invFftFrameSizePI2)
            {
              var window: Number = -.5 * Math.cos(t) + .5;
              windowValues[k] = window;
              //windowValuesFactored[k] = window * invFftFrameSize2;
            }
          _pitch = new PitchShifter(_fftFrameSize, 4, samplingFreq); // frame shift = 2048 / 4

          button.x = 5;
          button.y = 5;
          button.mouseChildren = false;
          button.buttonMode = true;
          button.graphics.lineStyle(1, 0xBBBBBB);
          button.graphics.beginFill(0xEEEEEE);
          button.graphics.drawRoundRect(0, 0, 100, 20, 5, 5);
          button.graphics.endFill();
          addChild(button);
          buttontext = new TextField();
          buttontext.width = 100;
          buttontext.height = 20;
          buttontext.htmlText = "<p align='center'><font face='_sans'>Open SMF</span></p>";
          button.addChild(buttontext);
          fileReference = new FileReference();
          fileReference.addEventListener(Event.SELECT, onSelect);
          fileReference.addEventListener(Event.COMPLETE, onComplete);
          button.addEventListener(MouseEvent.CLICK, onClick);

          button2.x = 200;
          button2.y = 5;
          button2.mouseChildren = false;
          button2.buttonMode = true;
          button2.graphics.lineStyle(1, 0xBBBBBB);
          button2.graphics.beginFill(0xEEEEEE);
          button2.graphics.drawRoundRect(0, 0, 200, 20, 5, 5);
          button2.graphics.endFill();
          addChild(button2);
          button2text = new TextField();
          button2text.width = 200;
          button2text.height = 20;
          button2text.htmlText = "<p align='center'><font face='_sans'>Load Accompaniment (disabled)</span></p>";
          button2.addChild(button2text);          
          
        }
      private function onClick(event:MouseEvent):void
        {
          fileReference.browse([new FileFilter("MIDIシーケンス(mid)", "*.mid")]);
        }
      
      private function onSelect(event:Event):void
        {
          fileReference.load();
        }
      
      private function onComplete(event:Event):void
        {
                    //読み込むファイルのアドレス情報を作成
        var request:URLRequest = new URLRequest("http://dl.dropbox.com/u/13027309/Mitou/mean_ch.dat");
        //URLLoaderのインスタンスを作成
        var loader:URLLoader = new URLLoader();
        //読み込み完了後の処理を作成
        loader.addEventListener(Event.COMPLETE, txt2Vector);
        
        //var loaderinfo:LoaderInfo = loader.con
        var mean:Vector.<Number> = new Vector.<Number>();
        
        function txt2Vector(event:Event):void 
        {
            var testarray:Array = loader.data.split("\n");
            var testdata:Vector.<Number> = new Vector.<Number>(12);
            for (var i:int = 0; i < 12; i++)
            {
                testdata[i] = testarray[i];
            }
            //trace(testdata);
            mean = testdata;
            
            trace("Read Chromagram of Score COMPLETE!");
            midi = new ScoreFollow(fileReference.data, _fftFrameSize, samplingFreq, mean,"http://dl.dropbox.com/u/13027309/Mitou/covmat_ch.dat");
            
            midi.MakeChromagramOfScore_DP();
            
            // Draw Chromagram Of Score
            var bitmap_chromagram:BitmapData = DrawChromagramOfScore(midi.chromagram_sco, stage.stageWidth, stage.stageHeight / 2);
              _canvas_under.copyPixels(bitmap_chromagram, bitmap_chromagram.rect, new Point(0,0));
            
            _startRecord();
        }
        //読み込み失敗時の簡易処理を作成
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,trace);
        loader.addEventListener(IOErrorEvent.IO_ERROR,trace);        
        //読み込みを開始
        loader.load(request);
        //trace(mean);
        //_setTune();
        }
      
      // test function
      private function _setTune():void
        {
            trace("test");
        }

      /**
       * 録音開始
       */
      private function _startRecord():void
        {
          trace("_startRecord");
          
        //          _over.width = 0;
          
          _position = 0;
          //_records = new Vector.<Number>(44100 * 5);
          _records = new Vector.<Number>(_fftFrameSize);
          _mic.addEventListener(SampleDataEvent.SAMPLE_DATA, _micSampleDataHandler);
        }

      private var gFFTworksp    :Vector.<Number>; // FFT spectrum stack

      private var _magn:Number, _real:Number, _imag:Number; // variables for FFT
      private var _spectrum_temppower : Vector.<Number>;

      private var _canvasPosition:int = 0; // Position on Canvas

      private function _micSampleDataHandler(e:SampleDataEvent):void
        {
          var sw:int = stage.stageWidth;
          var sh:int = stage.stageHeight;

          var datas:ByteArray = e.data;
          gFFTworksp      = new Vector.<Number>(2 * _fftFrameSize + 2, true);

          while (datas.bytesAvailable)
            {
              var data:Number = _records[_position] = datas.readFloat();

              if (++_position == _records.length)
                {
                  _canvasPosition = _canvasPosition + 1;

                  for (var k:int = 0, n:int = 1; k < _fftFrameSize; ++k, ++n)
                    {
                      gFFTworksp[n] = _records[k] * windowValues[k];
                      gFFTworksp[++n] = 0.0;
                    }

                    //delete _records;
                  _pitch.realft(gFFTworksp, _fftFrameSize, -1);
                  _position = 0;
                  _spectrum_temppower = new Vector.<Number> ( _fftFrameSize / 2 );
                  for (k = 0; k < _fftFrameSize/2; ++k)
                    {
                      /* de-interlace FFT buffer */
                      _real = gFFTworksp[n = 1 + (k << 1)];
                      _imag = gFFTworksp[n + 1];
                      /* compute magnitude and phase */
                      _magn = 2.0 * Math.sqrt(_real * _real + _imag * _imag);

                      _spectrum_temppower[k] = _magn;
                    }
                    
                    // push spectrum to chromagram:ScoreFollow
                    var _tempchroma:Vector.<Number> = midi.spectrum2chroma(_spectrum_temppower, _constantQfilterbank);
                    midi.pushchroma(_tempchroma);
                    
                    // tracking by Dynamic Time Warping
                    midi.tracking(_tempchroma);
                    
                  // plot spectrogram
                    var x:int = _canvasPosition % sw;
                    _canvas.copyPixels(_slit, _slit.rect, new Point(x + 1, 0));
                  //for (var y:Number = 0; y < _fftFrameSize / 2; ++y)
                    //{
                      //_canvas.setPixel(x, sh - y,  Number( "0x" + _Number2RGB( Math.log(_spectrum_temppower[y]) / Math.LN10, 3.0, -1.5 ).toString(16) ) );
                    //}
                    var pixelchroma:BitmapData = DrawChroma(_tempchroma, 1, stage.stageHeight/2);
                    _canvas.copyPixels(pixelchroma, pixelchroma.rect, new Point(x, 0));
                }
              /*
              var x:Number = _position / _records.length * sw;
              _canvas.copyPixels(_slit, _slit.rect, new Point(x + 1, 0)); // erase previous wave at the next time

              var y:Number = sh * 0.5 - data * 1000;
              _canvas.setPixel(x, y, 0x00CC0000); // plot the point
               */
            }
        }

      /**
       *   Spectrum to Color RGB
       */
      //private function onLoadDemo(event:MouseEvent):void
      //{
      //var loader:URLLoader = new URLLoader();
      //loader.addEventListener(Event.COMPLETE, onDemoLoaded);
      //loader.dataFormat = URLLoaderDataFormat.BINARY;
      //loader.load(new URLRequest("http://dl.dropbox.com/u/13027309/clarinet_quintet_1_all.mid"));
      //}
      //private function onDemoLoaded(event:Event):void
      //{
      //midi = new SMFSequence(event.currentTarget.data);
      //textfield.text = midi.toString();
      //}
      /**
       * 再生開始
       */
      private function _startSound():void
        {
          trace("_startSound");

          _position = 0;
          _sound.addEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
          _soundChannel = _sound.play();
        }

      private function _soundSampleDataHandler(e:SampleDataEvent):void
        {
          _over.width = stage.stageWidth * (_position / _records.length);
          _over.height = stage.stageHeight;

          for (var i:int = 0; i < 2048; ++i)
            {
              var data:Number = _records[_position];

              e.data.writeFloat(data);
              e.data.writeFloat(data);

              if (++_position == _records.length)
                {
                  _sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, _soundSampleDataHandler);
                  _startRecord();
                  return;
                }
            }
        }
        
        private function DrawChroma(chroma:Vector.<Number>, width:int, height:int):BitmapData
        {
            //var width:int = height / 12;
            var bitmap_chroma:BitmapData = new BitmapData(width, height);
            var stream:ByteArray = new ByteArray();
            var unit:int = Math.floor(height / 12);
            var rect:Rectangle = new Rectangle(0, 0, width, unit*12);
            
            var i:int = 0;
            for (var index:int = 0; index < 12; index++)
            {
                var rgb:uint = _Number2RGB(chroma[index], 1.0, 0.0);
                
                while (i < 4 * width * unit * (index+1))
                {
                    var alpha:uint = 255;
                    var red  :uint = Math.floor(rgb / 16 / 16 / 16 / 16);
                    var green:uint = Math.floor((rgb - red * 16 * 16 * 16 * 16) / 16 / 16);
                    var blue :uint = rgb - red * 16 * 16 * 16 * 16 - green * 16 * 16;
                    
                    stream[i++] = alpha;
                    stream[i++] = red;
                    stream[i++] = green;
                    stream[i++] = blue;
                }
            }
            
            bitmap_chroma.setPixels(rect, stream);
            //for (var y:int = 0; y < 12; y++)
            //{
                //bitmap_chroma.fillRect(new Rectangle(0, unit*y, width, unit), Number( "0x" + _Number2RGB(chroma[y], 1, 0 ).toString(16) ) );
                //for (var x:int = 0; x < width; x++)
                //{
                    //bitmap_chroma.setPixel(x, y,  Number( "0x" + _Number2RGB(chroma[y], 1, 0 ).toString(16) ) );
                //}
            //}
            
            return bitmap_chroma;
        }
        
        private function DrawChromagramOfScore(chromagram:Vector.<Vector.<Number>>, width:int, height:int):BitmapData
        {
            var bitmap_chromagram:BitmapData = new BitmapData(width, height);
            
            for (var index:int = 0; index < chromagram.length; index++)
            {
                var bitmap_chroma:BitmapData = DrawChroma(chromagram[index], 1, height);
                bitmap_chromagram.copyPixels(bitmap_chroma, bitmap_chroma.rect, new Point(index,0));
            }
            return bitmap_chromagram;
        }

    }
}

class FilterBank
{
    private var filter:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    private var filter_real:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    private var filter_imag:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    
    public var channels:Number;
    
    public function FilterBank(samplingFreq:Number, fftFrameSize:Number, Q:Number, lowestFreq:Number, channels:Number):void 
    {
        this.channels = channels;
        var fc:Number;
        // prepare constant-Q filterbank
        for (var m:int = 0; m < channels; ++m)
        {
            filter.push(new Vector.<Number>(fftFrameSize/2));
            filter_real.push(new Vector.<Number>(fftFrameSize/2));
            filter_imag.push(new Vector.<Number>(fftFrameSize/2));
            for (var n:int = 0; n< fftFrameSize / 2; ++n)
            {
                fc = lowestFreq * Math.pow(2, (m-1)/12);
                filter[m][n] = Math.exp( - (n - fc) * (n - fc) * Q * Q / 2 / fc / fc );
                // phase (by tachibana) but dubious ???
                filter_imag[m][n] = filter[m][n] * Math.sin(Math.PI * (fc - n) * fftFrameSize / samplingFreq);
                filter_real[m][n] = filter[m][n] * Math.cos(Math.PI * (fc - n) * fftFrameSize / samplingFreq);
            }
        }        
    }
    
    public function readfilter():Vector.<Vector.<Number>>
    {
        return filter;
    }
    public function readfilter_real():Vector.<Vector.<Number>>
    {
        return filter_real;
    }
    
    public function readfilter_imag():Vector.<Vector.<Number>>
    {
        return filter_imag;
    }
}

class ScoreFollow
{
    private var fftFrameSize:Number;
    private var samplingFreq:Number;
    
    private var chromagram_per:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    public var chromagram_sco:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    
    private var trellis:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    
    private var clarinet:ChromaTemplate;
    private var score:SMFSequence;
    
    public function ScoreFollow(data:ByteArray, fftFrameSize:Number, samplingFreq:Number, mean:Vector.<Number>, covmat:String):void
    {
        this.score = new SMFSequence(data);
        this.fftFrameSize = fftFrameSize;
        this.samplingFreq = samplingFreq;
        //spectrogram ;
        
        trace(this.score.tracks.toString());
        
        clarinet = new ChromaTemplate(mean, covmat, this);
        //clarinet = new ChromaTemplate("C:\Users\Kosuke\ Suzuki\Dropbox\Public\Mitou\mean_ch.dat",
        //"C:\Users\Kosuke\ Suzuki\Dropbox\Public\Mitoucovmat_ch.dat");
        
        // Make Chromagram of Score for Tracking
        //while (clarinet.finish == false)
        //{
            //
        //}
        //MakeChromagramOfScore_DP();
    }
        
    public function MakeChromagramOfScore_DP():void
    {
        var time_unit:Number = fftFrameSize / samplingFreq;
        
        var frame:int = 0; // frame index : frame * time_unit = sec
        var index:int = 0; // MIDI event index
        
        var ListNoteOn:Vector.<SMFEvent> = new Vector.<SMFEvent>();
        var listNoteOnEvent:Function = function(smfevent:SMFEvent, index:int, smftrack:Vector.<SMFEvent>):Boolean
        {
            if (smfevent.type == 0x90)
            {
                return true;
            }
            
            return false;
        };
        ListNoteOn = score.tracks[1].sequence.filter(listNoteOnEvent);
        
        var previous_onset:int = 0; // Onset time of previous event
        
        var lastindex:int = ListNoteOn.length-1;
        //trace(score.tracks[1].sequence[lastindex].time);
        var lastframe:int = ListNoteOn[lastindex].time * 60 / score.tempo / score.division / time_unit;
        
        for (frame = 0; frame < lastframe; frame++)
        {
            var tempchroma:Vector.<Number> = new Vector.<Number>();
            tempchroma = clarinet.rotate_mean(ListNoteOn[index].note % 12);
            // Normalization
            var zero:Vector.<Number> = new <Number>[0,0,0,0,0,0,0,0,0,0,0,0];
            var norm:Number = distance(tempchroma, zero);
            for (var k:int = 0; k < 12; k++)
            {
                tempchroma[k] /= norm + 0.001;
            }
            chromagram_sco.push(tempchroma);
            if ( frame * time_unit > ListNoteOn[index].time * 60 / score.tempo / score.division )
            {
                index++;
            }
        }
        //trace(chromagram_sco)
    }
    
    public function spectrum2chroma(power_spectrum:Vector.<Number>, filter:FilterBank):Vector.<Number>
    {
        var wavelet:Vector.<Number> = new Vector.<Number>(filter.channels);
        var chroma :Vector.<Number> = new Vector.<Number>(12);
        
        for (var m:int = 0; m < filter.channels; m++)
        {
            for (var n:int = 0; n < fftFrameSize / 2; n++)
            {
                wavelet[m] += filter.readfilter()[m][n] * power_spectrum[n];
            }
        }
        
        for (m = 0; m < filter.channels; m++)
        {
            chroma[m % 12] += wavelet[m];
        }
        
        // Normalization
        var zero:Vector.<Number> = new <Number>[0,0,0,0,0,0,0,0,0,0,0,0];
        var norm:Number = distance(chroma, zero);
        for (var k:int = 0; k < 12; k++)
        {
            chroma[k] /= norm + 0.001;
        }
        
        
        return chroma;
    }

    public function pushchroma(chroma:Vector.<Number>):void 
    {
        chromagram_per.push(chroma);
        //trace(spectrogram);
    }
    
    public function tracking(tempchroma:Vector.<Number>):void
    {
        var index:int = chromagram_per.length - 1;
        var temptrellis:Vector.<Number> = new Vector.<Number>(chromagram_sco.length);
        
        for (var k:int = 0; k < chromagram_sco.length; k++)
        {
            temptrellis[k] = distance(tempchroma, chromagram_sco[k]);
            trellis.push(temptrellis);
        }
        if (index == 0)
        {
            for (k=1; k < chromagram_sco.length; k++)
            {    
                trellis[index][k] += trellis[index][k - 1];
            }
        }
        else
        {
            trellis[index][0] += trellis[index - 1][0];// k=0
            for (k=1; k < chromagram_sco.length; k++)  // k=[1:N]
            {    
                trellis[index][k] = Math.min(trellis[index][k] + trellis[index][k - 1]
                                            ,trellis[index][k] + trellis[index - 1][k]
                                            ,trellis[index][k] + trellis[index - 1][k - 1]);
            }
        }
        trace(seakmin(trellis[index]));
    }

    public function seakmin(v:Vector.<Number>):Vector.<Number>
    {
        var answer:Vector.<Number> = new <Number> [v[0],0];// answer[0] is minimal value and answer[1] is its index
        if (v.length != 1)
        {
            for (var i:int = 1; i < v.length; i++)
            {
                if (v[i] < answer[0])
                {
                    answer[1] = i;
                    answer[0] = v[i];
                }
            }
        }
        
        return answer;
    }
    
    public function distance(v1:Vector.<Number>, v2:Vector.<Number>):Number
    {
        if (v1.length != v2.length)
        {
            return -1;
        }
        
        var length:int = v1.length;
        
        var distance:Number = 0;
        
        for (var i:int = 0; i < length; i++)
        {
            distance += (v1[i] - v2[i]) * (v1[i] - v2[i]);
        }
        
        return Math.sqrt(distance);
    }
    
}

class ChromaTemplate
{
    public var mean  :Vector.<Number> = new Vector.<Number>(12);
    public var covmat:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
        
    private var chroma_of_score : Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    
    public function ChromaTemplate(mean:Vector.<Number>, covmatfile:String, scorefollow:ScoreFollow)
    {
        this.mean = mean;
        //読み込むファイルのアドレス情報を作成
        //var request_cov:URLRequest = new URLRequest(covmatfile);
        //URLLoaderのインスタンスを作成
        //var loader_cov:URLLoader = new URLLoader();
        //読み込み完了後の処理を作成
        //loader_cov.addEventListener(Event.COMPLETE,traceData_cov);
        //
        //function traceData_cov(event:Event):void {
            //var testarray:Array = loader_cov.data.split("\n");
            //var covdata:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
            //
            //for (var j:int = 0; j < 12; j++)
            //{
                //var temparray:Array = testarray[j].split(" ");
                //var tempdata:Vector.<Number> = new Vector.<Number>(12);
                //for (var i:int = 0; i < 12; i++)
                //{
                    //tempdata[i] = temparray[i];
                //}
                //
                //covdata[j] = tempdata;
            //}
            //
            //trace(covdata[2]);
            //
            //this.covmat = covdata;
        //}
        //
        //読み込み失敗時の簡易処理を作成
        //loader_cov.addEventListener(SecurityErrorEvent.SECURITY_ERROR,trace);
        //loader_cov.addEventListener(IOErrorEvent.IO_ERROR,trace);
        //
        //読み込みを開始
        //loader_cov.load(request_cov);
        
    }
    
    public function rotate_mean(shift:int):Vector.<Number>
    {
        var rotated_mean:Vector.<Number> = new Vector.<Number>(12);
        
        for (var i:int = 0; i < 12-shift; i++)
        {
            rotated_mean[i + shift] = this.mean[i];
        }
        for (var j:int = 0; j < shift; j++)
        {
            rotated_mean[j] = this.mean[12 - shift + j];
        }
        
        return rotated_mean;
    }
}



import flash.utils.ByteArray;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.events.*;


/*
 * class Standard MIDI File
 */
class SMFSequence
{

  public var format:int;
  public var numTracks:int;
  public var division:int;
  public var tempo:int = 0;
  public var title:String = "";
  public var artist:String = "";
  public var signature_n:int;
  public var signature_d:int;
  public var length:int;

  public var tracks:Vector.<SMFTrack> = new Vector.<SMFTrack>();

  function SMFSequence(bytes:ByteArray)
    {
      bytes.position = 0;

      while(bytes.bytesAvailable > 0)
        {
          var type:String = bytes.readMultiByte(4, "us-ascii");
          switch(type)
            {
            case "MThd":    //ヘッダ
              bytes.position += 4;    //ヘッダのデータ長は常に00 00 00 06なのでスルー
              format = bytes.readUnsignedShort();
              numTracks = bytes.readUnsignedShort();
              division = bytes.readUnsignedShort();
              trace("division is ", division);
              break;
            case "MTrk":    //トラック
              var len:uint = bytes.readUnsignedInt();
              var temp:ByteArray = new ByteArray();
              bytes.readBytes(temp, 0, len);
              var track:SMFTrack = new SMFTrack(this, temp);
              tracks.push(track);
              length = Math.max(length, track.length);
              break;
            default:
              return;
            }
        }
    }

  public function toString():String
    {
      var text:String = "format : "+format+" | numTracks : "+numTracks+" | division : "+division+"\n";
      text += "タイトル : "+title+" | 著作権表示 : "+artist+"\n";
      text += "拍子 : "+signature_d+"分の"+signature_n+"拍子 | BPM : "+tempo+" | length : "+length+"\n";

      text += "\n";

      for(var i:int = 0; i < tracks.length; i++)
        {
          text += "トラック"+i+" : "+tracks[i].toString() + "\n";
        }

      return text;
    }
}

class SMFTrack
{
  public var parent:SMFSequence;
  public var sequence:Vector.<SMFEvent> = new Vector.<SMFEvent>();
  public var length:int;

  function SMFTrack(parent:SMFSequence, bytes:ByteArray)
    {
      this.parent = parent;

      var event:SMFEvent;
      var temp:int;
      var len:int;

      var type:int;
      var channel:int;

      var time:int;
      /*
            var readVariableLength:Function = function(time:uint = 0):uint
            {
                var temp:uint = bytes.readUnsignedByte();
                if(temp & 0x80) {return readVariableLength(time + (temp & 0x7F));}
                else {return time + (temp & 0x7F);}
            }
       */
      var readVariableLength:Function = function(time:uint = 0):uint
        {
          var temp:uint = bytes.readUnsignedByte();
          if(temp & 0x80) {return readVariableLength((time << 7) + (temp & 0x7F));}
          else {return (time << 7) + (temp & 0x7F);}
        }

    main : while(bytes.bytesAvailable > 0)
      {
        event = new SMFEvent();
        event.delta_time = readVariableLength();
        time += event.delta_time;
        event.time = time;

        temp = bytes.readUnsignedByte();

        if(temp == 0xFF)
          {
            event.type = bytes.readUnsignedByte();
            len = readVariableLength();

            switch(event.type)
              {
              case 0x02:    //作者
                event.artist = bytes.readMultiByte(len, "Shift-JIS");
                parent.artist = event.artist;
                break;
              case 0x03:    //タイトル
                event.title = bytes.readMultiByte(len, "Shift-JIS");
                parent.title = event.title;
                break;
              case 0x2F:    //トラック終了
                break main;
              case 0x51:    //テンポ
                event.tempo = bytes.readUnsignedByte()*0x10000 + bytes.readUnsignedShort();
                if(parent.tempo == 0) {
                  parent.tempo = 60000000 / event.tempo;
                }
                //trace("tempo is ", parent.tempo);
                break;
              case 0x58:    //拍子
                parent.signature_n = bytes.readUnsignedByte();
                parent.signature_d = Math.pow(2, bytes.readUnsignedByte());
                bytes.position += 2;
                break;
              default:
                bytes.position += len;
                break;
              }
          }
        else if(temp == 0xF0 || temp == 0xF7)    //Sysx
          {
            event.type = temp;
            len = readVariableLength();
            event.sysx = new ByteArray();
            bytes.readBytes(event.sysx, 0, len);
          }
        else {
          if(temp & 0x80) {
            type = temp & 0xF0;
            channel = temp & 0x0F;
          }
          else {
            bytes.position--;
          }

          event.type = type;
          event.channel = channel;

          switch(type)
            {
            case 0x80:    //ノートオフ
              event.note = bytes.readUnsignedByte();
              event.velocity = bytes.readUnsignedByte();
              break;
            case 0x90:    //ノートオン
              event.note = bytes.readUnsignedByte();
              event.velocity = bytes.readUnsignedByte();
              break;
            case 0xA0:    //ポリフォニックキープレッシャー
              event.note = bytes.readUnsignedByte();
              event.value = bytes.readUnsignedByte();
              break;
            case 0xB0:    //コントロールチェンジ
              event.cc = bytes.readUnsignedByte();
              event.value = bytes.readUnsignedByte();
              break;
            case 0xC0:    //パッチチェンジ
              event.value = bytes.readUnsignedByte();
              break;
            case 0xD0:    //チャンネルプレッシャー
              event.value = bytes.readUnsignedByte();
              break;
            case 0xE0:    //ピッチベンド
              event.lsb = bytes.readUnsignedByte();
              event.msb = bytes.readUnsignedByte();
              break;
            }
        }
        sequence.push(event);
      }
      length = time;
    }

  public function toString():String
    {
      var text:String = length + "\n";

      for(var i:int = 0; i < sequence.length; i++)
        {
          if(sequence[i].toString() == "") {continue;}
          text += sequence[i].toString();
          text += sequence[i].time * 60 / parent.tempo / parent.division ;
          text += " ";
        }

      return text;
    }
}

dynamic class SMFEvent
{
  public var delta_time:uint;    //相対時間
  public var time:uint;    //絶対時間
  public var type:int;
  
  public function toString():String
    {
      var text:String = "";
      //text = type.toString(16);
      //*
      switch(type)
        {
        case 0x90:    // Note Event (?)
          if(this.velocity == 0) {break;}

          //switch(this.note % 12)
            //{
            //case  0: text += "ド"; break;
            //case  1: text += "ド#"; break;
            //case  2: text += "レ"; break;
            //case  3: text += "ミb"; break;
            //case  4: text += "ミ"; break;
            //case  5: text += "ファ"; break;
            //case  6: text += "ファ#"; break;
            //case  7: text += "ソ"; break;
            //case  8: text += "ソ#"; break;
            //case  9: text += "ラ"; break;
            //case 10: text += "シb"; break;
            //case 11: text += "シ"; break;
            //}
          //text += " "+this.velocity;
          break;
        case 0xB0:
          text += "CC#" + this.cc +" "+this.value + " ";
          break;
        case 0xC0:
          text += "楽器変更 " + this.value + " ";
          break;
        case 0xF0:
        case 0xF7:
          text += "Sysx : ";
          for(var i:int = 0; i < this.sysx.length; i++) {
            text += this.sysx[i].toString(16)+" ";
          }
          break;
        }
      
            if(type == 0x90 && this.velocity != 0)
            {
                switch(this.note % 12)
                {
                case  0: text += "c"; break;
                case  1: text += "c+"; break;
                case  2: text += "d"; break;
                case  3: text += "d+"; break;
                case  4: text += "e"; break;
                case  5: text += "f"; break;
                case  6: text += "f+"; break;
                case  7: text += "g"; break;
                case  8: text += "g+"; break;
                case  9: text += "a"; break;
                case 10: text += "a+"; break;
                case 11: text += "b"; break;
                }
                
            }
            
            return text;
    }
}

/****************************************************************************
 *
 * NAME: PitchShifter.as
 * VERSION: 1.0
 * HOME URL: http://iq12.com/
 * KNOWN BUGS: none
 *
 * SYNOPSIS: Routine for doing pitch shifting while maintaining
 * duration using the Short Time Fourier Transform.
 *
 * DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
 * (one octave down) and 2. (one octave up). A value of exactly 1 does not change
 * the pitch. numSampsToProcess tells the routine how many samples in indata[0...
 * numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
 * numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
 * data in-place). fftFrameSize defines the FFT frame size used for the
 * processing. Typical values are 1024, 2048 and 4096. It may be any value <=
 * MAX_FRAME_LENGTH but it MUST be a power of 2. osamp is the STFT
 * oversampling factor which also determines the overlap between adjacent STFT
 * frames. It should at least be 4 for moderate scaling ratios. A value of 32 is
 * recommended for best quality. sampleRate takes the sample rate for the signal
 * in unit Hz, ie. 44100 for 44.1 kHz audio. The data passed to the routine in
 * indata[] should be in the range [-1.0, 1.0), which is also the output range
 * for the data, make sure you scale the data accordingly (for 16bit signed integers
 * you would have to divide (and multiply) by 32768).
 *
 * COPYRIGHT 1999-2006 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
 *
 *                         The Wide Open License (WOL)
 *
 * Permission to use, copy, modify, distribute and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice and this license appear in all source copies.
 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
 * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
 *
 *****************************************************************************/

/****************************************************************************
 *
 * This code was converted to AS3/FP10 by Arnaud Gatouillat <fu [AT] iq12 [DOT] com>
 * from C# code by Michael Knight ( madmik3 at gmail dot com. )
 * http://sites.google.com/site/mikescoderama/
 *
 *****************************************************************************/

/****************************************************************************
 *
 * The functions `realft' and `four1' are based on those in Press, W.H., et al.,
 * Numerical Recipes in C: the Art of Scientific Computing (Cambridge Univ. Press,
 * 1989;  2nd ed., 1992).
 *
 *****************************************************************************/

class PitchShifter
{
  private var gInFIFO        :Vector.<Number>;
  private var gOutFIFO    :Vector.<Number>;
  private var gFFTworksp    :Vector.<Number>;
  private var gLastPhase    :Vector.<Number>;
  private var gSumPhase    :Vector.<Number>;
  private var gOutputAccum:Vector.<Number>;
  private var gAnaFreq    :Vector.<Number>;
  private var gAnaMagn    :Vector.<Number>;
  private var gSynFreq    :Vector.<Number>;
  private var gSynMagn    :Vector.<Number>;

  private var freqPerBin:Number, expct:Number;
  private var gRover:int, inFifoLatency:int, stepSize:int, fftFrameSize2:int;

  private var fftFrameSize:int, osamp:int, sampleRate:Number;

  /* pre-computed values for speed */
  private var windowValues        :Vector.<Number>;
  private var windowValuesFactored:Vector.<Number>;
  private var invPI:Number, invFftFrameSizePI2:Number, osampPI2:Number, invOsampPI2FreqBin:Number;

  private var PI:Number        = Math.PI
    private var TWOPI:Number    = 2 * Math.PI

      public function PitchShifter(fftFrameSize:int, osamp:int, sampleRate:Number)
        {
          this.fftFrameSize    = fftFrameSize;
          this.osamp            = osamp;
          this.sampleRate        = sampleRate;

          gInFIFO            = new Vector.<Number>(fftFrameSize);
          gOutFIFO        = new Vector.<Number>(fftFrameSize, true);
          gFFTworksp        = new Vector.<Number>(2 * fftFrameSize + 2, true);
          gLastPhase        = new Vector.<Number>(fftFrameSize / 2 + 1, true);
          gSumPhase        = new Vector.<Number>(fftFrameSize / 2 + 1, true);
          gOutputAccum    = new Vector.<Number>(2 * fftFrameSize, true);
          gAnaFreq        = new Vector.<Number>(fftFrameSize, true);
          gAnaMagn        = new Vector.<Number>(fftFrameSize, true);
          gSynFreq        = new Vector.<Number>(fftFrameSize, true);
          gSynMagn        = new Vector.<Number>(fftFrameSize, true);

          /* set up some handy variables */
          fftFrameSize2= fftFrameSize / 2;
          stepSize = fftFrameSize / osamp;
          freqPerBin = sampleRate / Number(fftFrameSize);
          expct = 2.0 * PI * Number(stepSize) / Number(fftFrameSize);
          inFifoLatency = fftFrameSize - stepSize;

          invPI = 1 / PI;
          invFftFrameSizePI2 = PI * 2 / fftFrameSize;
          osampPI2 = osamp / ( 2 * PI );
          invOsampPI2FreqBin = 1 / ( freqPerBin * osampPI2);

          windowValues            = new Vector.<Number>(fftFrameSize);
          windowValuesFactored    = new Vector.<Number>(fftFrameSize);

          var invFftFrameSize2:Number = 2.0 / (fftFrameSize2 * osamp);
          for (var k:int = 0, t:Number = 0.0; k < fftFrameSize; ++k, t += invFftFrameSizePI2)
            {
              var window: Number = -.5 * Math.cos(t) + .5;
              windowValues[k] = window;
              windowValuesFactored[k] = window * invFftFrameSize2;
            }
        }

  public function pitchShift(pitchShift:Number, numSampsToProcess:int, indata:Vector.<Number>):void
    {
      var magn:Number, phase:Number, tmp:Number, window:Number, real:Number, imag:Number, t:Number;
      var i:int, k:int, qpd:int, index:int, n:int;

      var outdata:Vector.<Number> = indata;
      if (gRover == 0) gRover = inFifoLatency;

      /* main processing loop */
      for (i = 0; i < numSampsToProcess; ++i)
        {
          /* As long as we have not yet collected enough data just read in */
          gInFIFO[gRover] = indata[i];
          outdata[i] = gOutFIFO[gRover - inFifoLatency];
          ++gRover;

          /* now we have enough data for processing */
          if (gRover >= fftFrameSize)
            {
              gRover = inFifoLatency;

              /* do windowing and re,im interleave */
              for (k = 0, n = 1; k < fftFrameSize; ++k, ++n)
                {
                  gFFTworksp[n] = gInFIFO[k] * windowValues[k];
                  gFFTworksp[++n] = 0.0;
                }
              /* ***************** ANALYSIS ******************* */
              /* do transform */
              realft(gFFTworksp, fftFrameSize, -1);
              /* this is the analysis step */
              for (k = 0; k <= fftFrameSize2; ++k)
                {
                  /* de-interlace FFT buffer */
                  real = gFFTworksp[n = 1 + (k << 1)];
                  imag = gFFTworksp[n + 1];

                  /* compute magnitude and phase */
                  magn = 2.0 * Math.sqrt(real * real + imag * imag);
                  phase = Math.atan2(imag, real);

                  /* compute phase difference */
                  tmp = phase - gLastPhase[k];
                  gLastPhase[k] = phase;

                  /* subtract expected phase difference */
                  tmp -= k * expct;

                  /* map delta phase into +/- Pi interval */
                  qpd = int(tmp * invPI);
                  if (qpd >= 0)    qpd += qpd & 1;
                  else            qpd -= qpd & 1;
                  tmp -= PI * Number(qpd);

                  /* get deviation from bin frequency from the +/- Pi interval */
                  tmp *= osampPI2;

                  /* compute the k-th partials' true frequency */
                  tmp = (k + tmp) * freqPerBin;

                  /* store magnitude and true frequency in analysis arrays */
                  gAnaMagn[k] = magn;
                  gAnaFreq[k] = tmp;

                }
              /* ***************** PROCESSING ******************* */
              /* this does the actual pitch shifting */
              for (var zero:int = 0; zero < fftFrameSize; ++zero)
                {
                  gSynMagn[zero] = 0.0;
                  gSynFreq[zero] = 0.0;
                }

              for (k = 0, n = pitchShift > 1.0 ? int(fftFrameSize2 / pitchShift) : fftFrameSize2; k <= n; ++k)
                {
                  index = int(k * pitchShift);
                  gSynMagn[index] += gAnaMagn[k];
                  gSynFreq[index] = gAnaFreq[k] * pitchShift;
                }
              /* ***************** SYNTHESIS ******************* */
              /* this is the synthesis step */
              for (k = 0; k <= fftFrameSize2; ++k)
                {
                  /* get magnitude and true frequency from synthesis arrays */
                  magn = gSynMagn[k];

                  /* subtract bin mid frequency */
                  /* get bin deviation from freq deviation */
                  /* take osamp into account */
                  /* add the overlap phase advance back in */
                  /* accumulate delta phase to get bin phase */
                  phase = (gSumPhase[k] += (gSynFreq[k] - Number(k) * freqPerBin) * invOsampPI2FreqBin + Number(k) * expct);

                  /* get real and imag part and re-interleave */
                  gFFTworksp[n = 1 + (k << 1)] = magn * Math.cos(phase);
                  gFFTworksp[n + 1] = magn * Math.sin(phase);
                }

              /* zero negative frequencies */
              for (k = fftFrameSize + 3, n = 1 + (fftFrameSize << 1); k < n; ++k)
                {
                  gFFTworksp[k] = 0.0;
                }
              /* do inverse transform */
              realft(gFFTworksp, fftFrameSize, 1);

              /* do windowing and add to output accumulator */
              for (k = 0, n = 1; k < fftFrameSize; ++k, ++n, ++n)
                {
                  gOutputAccum[k] += windowValuesFactored[k] * gFFTworksp[n];
                }
              for (k = 0; k < stepSize; ++k)
                {
                  gOutFIFO[k] = gOutputAccum[k];
                }

              //memmove(gOutputAccum, gOutputAccum + stepSize, fftFrameSize * sizeof(Number));
              /* shift accumulator */
              /* move input FIFO */
              for (k = 0, n = stepSize; k < inFifoLatency; ++k, ++n)
                {
                  gOutputAccum[k] = gOutputAccum[n];
                  gInFIFO[k] = gInFIFO[n];
                }
              for ( ;  k < fftFrameSize; ++k, ++n)
                {
                  gOutputAccum[k] = gOutputAccum[n];
                }
            }
        }
    }

  //private function realft( data:Vector.<Number>, n:int, isign:int ):void
  public function realft( data:Vector.<Number>, n:int, isign:int ):void
    {
      var i:int, i1:int, i2:int, i3:int, i4:int, n2p3:int;
      var c1:Number = 0.5, c2:Number, h1r:Number, h1i:Number, h2r:Number, h2i:Number;
      var wr:Number, wi:Number, wpr:Number, wpi:Number, wtemp:Number, theta:Number;

      theta = PI/n;
      if (isign == 1)
        {
          c2 = -0.5;
          four1(data, n, 1);
        }
      else
        {
          c2 = 0.5;
          theta = -theta;
        }
      wtemp = Math.sin(0.5 * theta);
      wpr = -2.0 * wtemp * wtemp;
      wpi = Math.sin(theta);
      wr = 1.0 + wpr;
      wi = wpi;
      n2p3 = 2 * n + 3;
      for (i = 2; i <= n / 2; ++i)
        {
          i4 = 1 + (i3 = n2p3 - (i2 = 1 + ( i1 = i + i - 1)));
          h1r =  c1 * (data[i1] + data[i3]);
          h1i =  c1 * (data[i2] - data[i4]);
          h2r = -c2 * (data[i2] + data[i4]);
          h2i =  c2 * (data[i1] - data[i3]);
          data[i1] =    h1r + wr * h2r - wi * h2i;
          data[i2] =    h1i + wr * h2i + wi * h2r;
          data[i3] =    h1r - wr * h2r + wi * h2i;
          data[i4] = -h1i + wr * h2i + wi * h2r;
          wr = (wtemp = wr) * wpr - wi * wpi + wr;
          wi = wi * wpr + wtemp * wpi + wi;
        }
      if (isign == 1)
        {
          data[1] = (h1r = data[1]) + data[2];
          data[2] = h1r - data[2];
        }
      else
        {
          data[1] = c1 * ((h1r = data[1]) + data[2]);
          data[2] = c1 * (h1r - data[2]);
          four1(data, n, -1);
          data=data;
        }
    }

  private function four1(data:Vector.<Number>, nn:int, isign:int):void
    {
      var n:int, mmax:int, m:int, j:int, istep:int, i:int;
      var wtemp:Number, wr:Number, wpr:Number, wpi:Number, wi:Number, theta:Number;
      var tempr:Number, tempi:Number;
      var j1:int, i1:int;
      n = nn << 1;
      j = 1;
      for (i = 1; i < n; i += 2)
        {
          if (j > i)
            {
              j1 = j + 1;
              i1 = i + 1;
              tempr = data[j];    data[j] = data[i];        data[i] = tempr;
              tempr = data[j1];    data[j1] = data[i1];    data[i1] = tempr;
            }
          m = n >> 1;
          while (m >= 2 && j > m)
            {
              j -= m;
              m >>= 1;
            }
          j += m;
        }
      mmax = 2;
      while (n > mmax)
        {
          istep = 2 * mmax;
          theta = TWOPI / (isign * mmax);
          wtemp = Math.sin(0.5 * theta);
          wpr = -2.0 * wtemp * wtemp;
          wpi = Math.sin(theta);
          wr = 1.0;
          wi = 0.0;
          for (m = 1; m < mmax; m += 2)
            {
              for (i = m; i <= n; i += istep)
                {
                  i1 = i +1;
                  j1 = 1+ (j = i + mmax);
                  tempr = wr*data[j]     - wi*data[j1];
                  tempi = wr*data[j1]  + wi*data[j];
                  data[j]     = data[i]     - tempr;
                  data[j1]    = data[i1]    - tempi;
                  data[i]  += tempr;
                  data[i1] += tempi;
                }
              wr = (wtemp = wr) * wpr - wi * wpi + wr;
              wi = wi * wpr + wtemp * wpi + wi;
            }
          mmax = istep;
        }
    }

}

function _Number2RGB(_value:Number, max_value:Number, min_value:Number):uint
{
    if (_value > max_value)
    {
        _value = max_value;
    }
    else if (_value < min_value)
    {
        _value = min_value;
    }

    _value = (_value - min_value) / (max_value - min_value);
    var h:Number = 240.0 * ( 1 - _value % 1 ) ; // normalize between 0 and 240
    var s:Number = 1.0;
    var v:Number = 1.0;
    var rgb:uint = 0;
    var hi:uint = Math.floor(h / 60.0) % 6;
    var f:Number = h / 60.0 - hi;
    var vv:uint = Math.round(255 * v);
    var pp:uint = Math.round(255 * v * ( 1 - s ));
    var qq:uint = Math.round(255 * v * ( 1 - f * s ));
    var tt:uint = Math.round(255 * v * ( 1 - (1 - f) * s ));
    if ( vv > 255 ) vv = 255;
    if ( pp > 255 ) pp = 255;
    if ( qq > 255 ) qq = 255;
    if ( tt > 255 ) tt = 255;
    switch (hi) {
    case 0: rgb = (vv << 16) | (tt << 8) | pp; break;
    case 1: rgb = (qq << 16) | (vv << 8) | pp; break;
    case 2: rgb = (pp << 16) | (vv << 8) | tt; break;
    case 3: rgb = (pp << 16) | (qq << 8) | vv; break;
    case 4: rgb = (tt << 16) | (pp << 8) | vv; break;
    case 5: rgb = (vv << 16) | (pp << 8) | qq; break;
    }
    // var _RGBst:uint = Number("0x" + temp_value.toString(16));
    //return _RGBst;
    return rgb;
}

import flash.utils.*;

function wait(count:uint ):void
{
    var start:uint = getTimer();
    while (getTimer() - start < count)
    {
    }
 }