Guest User

Untitled

a guest
Apr 15th, 2018
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package
  2. {
  3.     import flash.display.Bitmap;
  4.     import flash.display.Sprite;
  5.     import flash.filesystem.File;
  6.     import flash.net.FileFilter;
  7.     import flash.net.URLLoader;
  8.     import flash.media.Sound;
  9.     import flash.events.*;
  10.     import flash.net.URLRequest;
  11.     import flash.display.BitmapData;
  12.     import flash.utils.*;
  13.     import flash.geom.Rectangle;
  14.     import flash.text.*;
  15.    
  16.     /**
  17.      * ...
  18.      * @author Luke Davies
  19.      */
  20.     public class Main extends Sprite
  21.     {
  22.        
  23.         /*                      
  24.                                _(\_/)
  25.                              ,((((^`\
  26.                             ((((  (6 \
  27.                           ,((((( ,    \
  28.       ,,,_              ,(((((  /"._  ,`,
  29.      ((((\\ ,...       ,((((   /    `-.-'
  30.      )))  ;'    `"'"'""((((   (    
  31.     (((  /            (((      \
  32.      )) |                      |
  33.     ((  |        .       '     |
  34.     ))  \     _ '      `t   ,.')
  35.     (   |   y;- -,-""'"-.\   \/
  36.     )   / ./  ) /         `\  \
  37.        |./   ( (           / /'
  38.        ||     \\          / /
  39.        ||      \\       _//'||
  40.        ||       ))     |_/  ||
  41.        \_\     |_/          ||
  42.        `'"                  \_\
  43.        
  44.        
  45.        LUKE i changed this stuff so that now it processes the file in chunks. It reads each chunk and does the fft on it and then calls the code to draw the
  46.        thing, but since it all happens at once you're only going to see the last chunk. If you want to see the whole file then you will need to first of all
  47.        have the chunk processing stuff (processMusic()) process a chunk and then add the processed data onto the end of a big array of data for the whole file,
  48.        which should not be too tricky, and then change the code to draw the spectrum to draw the whole thing.
  49.        
  50.        */
  51.  
  52.         private var m_file:File;
  53.         private var m_sound:Sound;
  54.        
  55.         private var m_buf:Vector.<Number> = null;
  56.         private var m_writePos:uint = 0;
  57.         private var m_fft:FFT2;                     // FFT object
  58.         private var m_tempRe:Vector.<Number>;       // Temporary buffer - real part
  59.         private var m_tempIm:Vector.<Number>;       // Temporary buffer - imaginary part
  60.         private var m_mag:Vector.<Number>;          // Magnitudes (at each of the frequencies below)
  61.         private var m_freq:Vector.<Number>;         // Frequencies (for each of the magnitudes above)
  62.         private var m_win:Vector.<Number>;
  63.         private var done:Boolean = false;
  64.        
  65.         private const SAMPLE_RATE:Number = 44100;
  66.         private const LOGN:uint = 9;                // Log2 FFT length
  67.         private const N:uint = 1 << LOGN;
  68.         private const BUF_LEN:uint = N;
  69.        
  70.         public var chunkCount:int = 0;
  71.        
  72.         public var manyMags:Array = new Array();
  73.        
  74.         private var m_tickTextAdded:Boolean = false;
  75.        
  76.         private var m_timer:Timer = new Timer(11.6);
  77.        
  78.         public function Main():void
  79.         {
  80.            
  81.             // Set up the FFT
  82.             m_fft = new FFT2();
  83.             m_fft.init(LOGN);
  84.             m_tempRe = new Vector.<Number>(N);
  85.             m_tempIm = new Vector.<Number>(N);
  86.             m_mag = new Vector.<Number>(N / 2);
  87.             addEventListener(Event.ENTER_FRAME, onEnterFrame);
  88.             //m_smoothMag = new Vector.<Number>(N/2);
  89.  
  90.             // Vector with frequencies for each bin number. Used
  91.             // in the graphing code (not in the analysis itself).                  
  92.             m_freq = new Vector.<Number>(N / 2);
  93.             var i:int;
  94.             for ( i = 0; i < N/2; i++ )
  95.                 m_freq[i] = i*SAMPLE_RATE/N;
  96.                        
  97.             // Hanning analysis window
  98.             m_win = new Vector.<Number>(N);
  99.             for ( i = 0; i < N; i++ )
  100.                 m_win[i] = (4.0/N) * 0.5*(1-Math.cos(2*Math.PI*i/N));
  101.                                
  102.             // Create a buffer for the input audio
  103.             m_buf = new Vector.<Number>(BUF_LEN);
  104.             for ( i = 0; i < BUF_LEN; i++ )
  105.                 m_buf[i] = 0.0;
  106.            
  107.             m_file = File.userDirectory;
  108.             var fileFilter:FileFilter = new FileFilter("MP3s", "*.mp3");
  109.             m_file.browse([fileFilter]);
  110.             m_file.addEventListener(Event.SELECT, loadFile);
  111.         }
  112.        
  113.         private function onEnterFrame(event:Event)
  114.         {
  115.             if (done)
  116.             {
  117.                 trace(m_timer.currentCount);
  118.                 drawSpectrum(manyMags[m_timer.currentCount], m_freq);
  119.             }
  120.            
  121.         }
  122.        
  123.         private function loadFile(e:Event):void
  124.         {
  125.             m_sound = new Sound(new URLRequest(m_file.url));
  126.             m_sound.addEventListener(Event.COMPLETE, processMusic);
  127.         }
  128.            
  129.         private function processMusic(e:Event):void
  130.         {
  131.             trace(m_sound.length);
  132.             var sampleLength:Number = Math.floor((m_sound.length / 1000) * SAMPLE_RATE);
  133.             trace(sampleLength);
  134.             var stereoData:ByteArray = new ByteArray();
  135.             var samples = m_sound.extract(stereoData, sampleLength);
  136.             var soundData:ByteArray = new ByteArray();
  137.             //trace(soundData.length);
  138.             stereoData.position = 0;
  139.             while(stereoData.bytesAvailable > 0)
  140.             {
  141.                 var firstChannel:Number = stereoData.readFloat();
  142.                 var secondChannel:Number = stereoData.readFloat();
  143.                 var sum: Number = firstChannel + secondChannel;
  144.                 var average:Number = sum / 2;
  145.                 soundData.writeFloat(average);
  146.             }
  147.        
  148.             soundData.position = 0;
  149.             for (var i:uint = 0; i < soundData.length; i += 4) // increment by 4 because a float is 32 bits (4 bytes)
  150.             {
  151.                 m_buf[m_writePos] = soundData.readFloat();
  152.                 m_writePos = (m_writePos + 1);
  153.                 if (m_writePos >= BUF_LEN)
  154.                 {
  155.                     var percent = (i / soundData.length) * 100;
  156.                     chunkCount++;
  157.                     trace(percent + "%" + " : " + chunkCount);
  158.                    
  159.                    
  160.                     m_writePos = 0;
  161.                     updateSpectrum();
  162.                 }
  163.             }
  164.            
  165.             // do one final update for the unfinished chunk here - have to zero out the remained of m_buf though otherwise you'll have weird data at the end
  166.             // without this you'll lose anywhere from the last 0 to 2048 samples which won't be very noticable but this is easy enough
  167.             if (m_writePos > 0)
  168.             {
  169.                 for ( ; m_writePos < BUF_LEN - 1; ++m_writePos )
  170.                 {
  171.                     m_buf[m_writePos] = 0;
  172.                 }
  173.                 updateSpectrum();
  174.             }
  175.            
  176.             m_sound.play();
  177.             m_timer.start();
  178.             done = true;
  179.         }
  180.        
  181.         private function updateSpectrum():void
  182.         {
  183.             // Copy data from circular microphone audio
  184.             // buffer into temporary buffer for FFT, while
  185.             // applying Hanning window.
  186.             var i:int;
  187.             var pos:uint = m_writePos;
  188.             for ( i = 0; i < N; i++ )
  189.             {
  190.                     m_tempRe[i] = m_win[i]*m_buf[pos];
  191.                     pos = (pos+1)%BUF_LEN;
  192.             }
  193.            
  194.             // Zero out the imaginary component
  195.             for ( i = 0; i < N; i++ )
  196.                     m_tempIm[i] = 0.0;
  197.            
  198.             // Do FFT and get magnitude spectrum
  199.             m_fft.run( m_tempRe, m_tempIm );
  200.             for ( i = 0; i < N/2; i++ )
  201.             {
  202.                     var re:Number = m_tempRe[i];
  203.                     var im:Number = m_tempIm[i];
  204.                     m_mag[i] = Math.sqrt(re*re + im*im);
  205.             }
  206.            
  207.             // Convert to dB magnitude
  208.             const SCALE:Number = 20/Math.LN10;            
  209.             for ( i = 0; i < N/2; i++ )
  210.             {
  211.                     // 20 log10(mag) => 20/ln(10) ln(mag)
  212.                     // Addition of MIN_VALUE prevents log from returning minus infinity if mag is zero
  213.                     m_mag[i] = SCALE*Math.log( m_mag[i] + Number.MIN_VALUE );
  214.             }
  215.             manyMags.push(m_mag);
  216.             // Draw the graph
  217.             //drawSpectrum( m_mag, m_freq );
  218.         }
  219.        
  220.         private function drawSpectrum(
  221.                                 mag:Vector.<Number>,
  222.                             freq:Vector.<Number> ):void
  223.         {
  224.                 // Basic constants
  225.                 const MIN_FREQ:Number = 0;                                      // Minimum frequency (Hz) on horizontal axis.
  226.                 const MAX_FREQ:Number = 4000;                           // Maximum frequency (Hz) on horizontal axis.
  227.                 const FREQ_STEP:Number = 500;                           // Interval between ticks (Hz) on horizontal axis.
  228.                 const MAX_DB:Number = -0.0;                                     // Maximum dB magnitude on vertical axis.
  229.                 const MIN_DB:Number = -60.0;                            // Minimum dB magnitude on vertical axis.
  230.                 const DB_STEP:Number = 10;                                      // Interval between ticks (dB) on vertical axis.
  231.                 const TOP:Number  = 50;                                         // Top of graph
  232.                 const LEFT:Number = 60;                                         // Left edge of graph
  233.                 const HEIGHT:Number = 300;                                      // Height of graph
  234.                 const WIDTH:Number = 500;                                       // Width of graph
  235.                 const TICK_LEN:Number = 10;                                     // Length of tick in pixels
  236.                 const LABEL_X:String = "Frequency (Hz)";        // Label for X axis
  237.                 const LABEL_Y:String = "dB";                            // Label for Y axis
  238.                
  239.                 // Derived constants
  240.                 const BOTTOM:Number = TOP+HEIGHT;                                       // Bottom of graph
  241.                 const DBTOPIXEL:Number = HEIGHT/(MAX_DB-MIN_DB);        // Pixels/tick
  242.                 const FREQTOPIXEL:Number = WIDTH/(MAX_FREQ-MIN_FREQ);// Pixels/Hz
  243.  
  244.                 //-----------------------                      
  245.                
  246.                 var i:uint;
  247.                 var numPoints:uint;
  248.                
  249.                 numPoints = mag.length;
  250.                 if ( mag.length != freq.length )
  251.                         trace( "mag.length != freq.length" );
  252.                
  253.                 graphics.clear();
  254.  
  255.                 // Draw a rectangular box marking the boundaries of the graph
  256.                 graphics.lineStyle( 1, 0x000000 );
  257.                 graphics.drawRect( LEFT, TOP, WIDTH, HEIGHT );
  258.                 graphics.moveTo(LEFT, TOP+HEIGHT);
  259.  
  260.                 //--------------------------------------------
  261.  
  262.                 // Tick marks on the vertical axis                    
  263.                 var y:Number;
  264.                 var x:Number;
  265.                 for ( var dBTick:Number = MIN_DB; dBTick <= MAX_DB; dBTick += DB_STEP )
  266.                 {
  267.                         y = BOTTOM - DBTOPIXEL*(dBTick-MIN_DB);
  268.                         graphics.moveTo( LEFT-TICK_LEN/2, y );
  269.                         graphics.lineTo( LEFT+TICK_LEN/2, y );
  270.                         if ( m_tickTextAdded == false )
  271.                         {
  272.                                 // Numbers on the tick marks
  273.                                 var t:TextField = new TextField();
  274.                                 t.text = int(dBTick).toString();
  275.                                 t.width = 0;
  276.                                 t.height = 20;
  277.                                 t.x = LEFT-20;
  278.                                 t.y = y - t.textHeight/2;
  279.                                 t.autoSize = TextFieldAutoSize.CENTER;
  280.                                 addChild(t);
  281.                         }
  282.                 }
  283.                
  284.                 // Label for vertical axis
  285.                 if ( m_tickTextAdded == false )
  286.                 {
  287.                         t = new TextField();
  288.                         t.text = LABEL_Y;
  289.                         t.x = LEFT-50;
  290.                         t.y = TOP + HEIGHT/2 - t.textHeight/2;
  291.                         t.height = 20;
  292.                         t.width = 50;
  293.                         //t.rotation = -90;
  294.                         addChild(t);
  295.                 }
  296.                
  297.                 //--------------------------------------------
  298.  
  299.                 // Tick marks on the horizontal axis
  300.                 for ( var f:Number = MIN_FREQ; f <= MAX_FREQ; f += FREQ_STEP )
  301.                 {
  302.                         x = LEFT + FREQTOPIXEL*(f-MIN_FREQ);
  303.                         graphics.moveTo( x, BOTTOM - TICK_LEN/2 );
  304.                         graphics.lineTo( x, BOTTOM + TICK_LEN/2 );
  305.                         if ( m_tickTextAdded == false )
  306.                         {
  307.                                 t = new TextField();
  308.                                 t.text = int(f).toString();
  309.                                 t.width = 0;
  310.                                 t.x = x;
  311.                                 t.y = BOTTOM+7;
  312.                                 t.autoSize = TextFieldAutoSize.CENTER;
  313.                                 addChild(t);
  314.                         }
  315.                 }
  316.                
  317.                 // Label for horizontal axis
  318.                 if ( m_tickTextAdded == false )
  319.                 {
  320.                         t = new TextField();
  321.                         t.text = LABEL_X;
  322.                         t.width = 0;
  323.                         t.x = LEFT+WIDTH/2;
  324.                         t.y = BOTTOM+30;
  325.                         t.autoSize = TextFieldAutoSize.CENTER;
  326.                         addChild(t);
  327.                 }
  328.                
  329.                 m_tickTextAdded = true;
  330.  
  331.                 // -------------------------------------------------                  
  332.                 // The line in the graph
  333.  
  334.                 // Ignore points that are too far to the left
  335.                 for ( i = 0; i < numPoints && freq[i] < MIN_FREQ; i++ )
  336.                 {
  337.                 }
  338.  
  339.                 // For all remaining points within range of x-axis                    
  340.                 var firstPoint:Boolean = true;
  341.                 for ( /**/; i < numPoints && freq[i] <= MAX_FREQ; i++ )
  342.                 {
  343.                         // Compute horizontal position
  344.                         x = LEFT + FREQTOPIXEL*(freq[i]-MIN_FREQ);
  345.                
  346.                         // Compute vertical position of point
  347.                         // and clip at top/bottom.
  348.                         y = BOTTOM - DBTOPIXEL*(mag[i]-MIN_DB);
  349.                         if ( y < TOP )
  350.                                 y = TOP;
  351.                         else if ( y > BOTTOM )
  352.                                 y = BOTTOM;
  353.  
  354.                         // If it's the first point                            
  355.                         if ( firstPoint )
  356.                         {
  357.                                 // Move to the point
  358.                                 graphics.moveTo(x,y);
  359.                                 firstPoint = false;
  360.                         }
  361.                         else
  362.                         {
  363.                                 // Otherwise, draw line from the previous point
  364.                                 graphics.lineTo(x,y);
  365.                         }
  366.                 }
  367.         }                      
  368.     }
  369.        
  370.         /*
  371.         var file:File;
  372.         var loader:URLLoader;
  373.         var sound:Sound;
  374.         var waveForm:BitmapData;
  375.         var samples:Array;
  376.     }
  377.        
  378.         private var m_buf:Vector.<Number> = null;
  379.         private var m_writePos:uint = 0;
  380.        
  381.         private var m_fft:FFT2;                                         // FFT object
  382.         private var m_tempRe:Vector.<Number>;           // Temporary buffer - real part
  383.         private var m_tempIm:Vector.<Number>;           // Temporary buffer - imaginary part
  384.         private var m_mag:Vector.<Number>;                      // Magnitudes (at each of the frequencies below)
  385.         private var m_freq:Vector.<Number>;                     // Frequencies (for each of the magnitudes above)
  386.         private var m_win:Vector.<Number>;
  387.        
  388.         private const LOGN:uint = 11;                           // Log2 FFT length
  389.         private const N:uint = 1 << LOGN;
  390.         private const BUF_LEN:uint = N;
  391.        
  392.         public function Main():void
  393.         {
  394.             waveForm = new BitmapData(800,100,true);
  395.             file = File.userDirectory;
  396.             var fileFilter:FileFilter = new FileFilter("MP3s", "*.mp3");
  397.             file.browse([fileFilter]);
  398.             file.addEventListener(Event.SELECT, loadFile);
  399.            
  400.             var i:uint;
  401.                        
  402.             // Set up the FFT
  403.             m_fft = new FFT2();
  404.             m_fft.init(LOGN);
  405.             m_tempRe = new Vector.<Number>(N);
  406.             m_tempIm = new Vector.<Number>(N);
  407.             m_mag = new Vector.<Number>(N/2);
  408.                         //m_smoothMag = new Vector.<Number>(N/2);
  409.  
  410.                         // Vector with frequencies for each bin number. Used
  411.                         // in the graphing code (not in the analysis itself).                  
  412.             m_freq = new Vector.<Number>(N/2);
  413.             for ( i = 0; i < N/2; i++ )
  414.                 m_freq[i] = i*SAMPLE_RATE/N;
  415.                        
  416.                         // Hanning analysis window
  417.             m_win = new Vector.<Number>(N);
  418.             for ( i = 0; i < N; i++ )
  419.                 m_win[i] = (4.0/N) * 0.5*(1-Math.cos(2*Math.PI*i/N));
  420.                                
  421.                         // Create a buffer for the input audio
  422.             m_buf = new Vector.<Number>(BUF_LEN);
  423.             for ( i = 0; i < BUF_LEN; i++ )
  424.                 m_buf[i] = 0.0;
  425.                
  426.            
  427.            
  428.         }
  429.        
  430.         private function updateSpectrum():void
  431.         {
  432.                 // Copy data from circular microphone audio
  433.                 // buffer into temporary buffer for FFT, while
  434.                 // applying Hanning window.
  435.                 var i:int;
  436.                 var pos:uint = m_writePos;
  437.                 for ( i = 0; i < N; i++ )
  438.                 {
  439.                         m_tempRe[i] = m_win[i]*m_buf[pos];
  440.                         pos = (pos+1)%BUF_LEN;
  441.                 }
  442.                
  443.                 // Zero out the imaginary component
  444.                 for ( i = 0; i < N; i++ )
  445.                         m_tempIm[i] = 0.0;
  446.                
  447.                 // Do FFT and get magnitude spectrum
  448.                 m_fft.run( m_tempRe, m_tempIm );
  449.                 for ( i = 0; i < N/2; i++ )
  450.                 {
  451.                         var re:Number = m_tempRe[i];
  452.                         var im:Number = m_tempIm[i];
  453.                         m_mag[i] = Math.sqrt(re*re + im*im);
  454.                 }
  455.                
  456.                 // Convert to dB magnitude
  457.                 const SCALE:Number = 20/Math.LN10;            
  458.                 for ( i = 0; i < N/2; i++ )
  459.                 {
  460.                                     // 20 log10(mag) => 20/ln(10) ln(mag)
  461.                                     // Addition of MIN_VALUE prevents log from returning minus infinity if mag is zero
  462.                         m_mag[i] = SCALE*Math.log( m_mag[i] + Number.MIN_VALUE );
  463.                 }
  464.         }
  465.        
  466.         public function loadFile(e:Event):void
  467.         {
  468.             sound = new Sound(new URLRequest(file.url));
  469.             //sound.load();
  470.             sound.addEventListener(Event.COMPLETE, playMusic);
  471.         }
  472.        
  473.         public function playMusic(e:Event):void
  474.         {
  475.             var sampleLength:Number = Math.floor((sound.length / 1000) * SAMPLE_RATE);
  476.             var iunno:ByteArray = new ByteArray();
  477.             sound.extract(iunno, sampleLength);
  478.             iunno.position = 0;
  479.             //var len:uint = iunno.length/4;
  480.             for (var i:uint = 0; i < iunno.length; i++)
  481.             {
  482.                 m_buf[m_writePos] = iunno.readFloat();
  483.                 m_writePos = (m_writePos + 1) % BUF_LEN;               
  484.             }
  485.            
  486.             sound.play();
  487.         }
  488.        
  489.        
  490.     }
  491.     */
  492.    
  493. }
Add Comment
Please, Sign In to add comment