Advertisement
spanvega

Untitled

Mar 10th, 2018
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. Copyright (c) 2009, Adobe Systems Incorporated
  3. All rights reserved.
  4.  
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are
  7. met:
  8.  
  9. * Redistributions of source code must retain the above copyright notice,
  10. this list of conditions and the following disclaimer.
  11.  
  12. * Redistributions in binary form must reproduce the above copyright
  13. notice, this list of conditions and the following disclaimer in the
  14. documentation and/or other materials provided with the distribution.
  15.  
  16. * Neither the name of Adobe Systems Incorporated nor the names of its
  17. contributors may be used to endorse or promote products derived from
  18. this software without specific prior written permission.
  19.  
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21. IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32.  
  33.  
  34. package com.adobe.audio.format
  35. {
  36.     import flash.utils.ByteArray;
  37.     import flash.utils.Endian;
  38.     import flash.utils.IDataOutput;
  39.    
  40.    
  41.     /**
  42.      *  Helper class to write WAV formated audio files.  The class
  43.      *  expects audio input data in a byte array with samples represented
  44.      *  as floats.  
  45.      *
  46.      *  <p>The default compressed code is set to PCM.  The class
  47.      *  resamples and formats the audio samples according to the
  48.      *  class properties.  The resampling geared for performance and
  49.      *  not quality, for best quality use sampling rates that divide/multiple
  50.      *  into the desired output <code>samplingRate</code>.
  51.      *
  52.      *  For more information about the WAVE file format see:
  53.      *  http://ccrma.stanford.edu/courses/422/projects/WaveFormat/</p>
  54.      *  
  55.      *  @langversion ActionScript 3.0
  56.      *  @playerversion Flash 10.0
  57.      */
  58.     public class WAVWriter
  59.     {
  60.        
  61.         //-------------------------------------------------------------------
  62.         // Variables
  63.         //-------------------------------------------------------------------
  64.        
  65.         /**
  66.          *  @private
  67.          *  Used for resampling channels where input channels > output channels
  68.          */
  69.         private var tempValueSum:Number = 0;
  70.         /**
  71.          *  @private
  72.          *  Used for resampling channels where input channels > output channels
  73.          */
  74.         private var tempValueCount:int = 0;
  75.        
  76.         //-------------------------------------------------------------------
  77.         // Properties
  78.         //-------------------------------------------------------------------
  79.        
  80.         /**
  81.          *  The sampling rate, in Hz, for the data in the WAV file.
  82.          *
  83.          *  @default 44100
  84.          */
  85.         public var samplingRate:Number = 44100;
  86.        
  87.         /**
  88.          *  The audio sample bit rate.  Has to be set to 8, 16, 24, or 32.
  89.          *
  90.          *  @default 16
  91.          */    
  92.         public var sampleBitRate:int = 16; // ie: 16 bit wav file
  93.        
  94.         /**
  95.          *  The number of audio channels in the WAV file.
  96.          *
  97.          *  @default 2
  98.          */
  99.         public var numOfChannels:int = 2;
  100.        
  101.         /**
  102.          *  @private
  103.          *  The WAV header compression code value.  The default is the PCM
  104.          *  code.
  105.          *
  106.          *  @default 1
  107.          */
  108.         private var compressionCode:int = 1;
  109.        
  110.         //-------------------------------------------------------------------
  111.         // Methods
  112.         //-------------------------------------------------------------------
  113.        
  114.         /**
  115.          *  @private
  116.          *  Create WAV header bytes
  117.          */
  118.         private function header(dataOutput:IDataOutput, fileSize:Number):void
  119.         {
  120.             dataOutput.writeUTFBytes("RIFF");
  121.             dataOutput.writeUnsignedInt(fileSize); // Size of whole file
  122.             dataOutput.writeUTFBytes("WAVE");
  123.             // WAVE Chunk
  124.             dataOutput.writeUTFBytes("fmt ");   // Chunk ID
  125.             dataOutput.writeUnsignedInt(16);    // Header Chunk Data Size
  126.             dataOutput.writeShort(compressionCode); // Compression code - 1 = PCM
  127.             dataOutput.writeShort(numOfChannels); // Number of channels
  128.             dataOutput.writeUnsignedInt(samplingRate); // Sample rate
  129.             dataOutput.writeUnsignedInt(samplingRate * numOfChannels * sampleBitRate / 8); // Byte Rate == SampleRate * NumChannels * BitsPerSample/8      
  130.             dataOutput.writeShort(numOfChannels * sampleBitRate / 8); // Block align == NumChannels * BitsPerSample/8
  131.             dataOutput.writeShort(sampleBitRate); // Bits Per Sample
  132.         }
  133.        
  134.         /**
  135.          *  Resample the <code>dataInput</code> audio data into the WAV format.
  136.          *  Writing the output to the <code>dataOutput</code> object.
  137.          *
  138.          *  <p>The <code>dataOutput.endian</code> will be set to <code>Endian.LITTLE_ENDIAN</code>
  139.          *  with the header and data written out on the data stream. The <code>dataInput</code>
  140.          *  will set the position = 0 and read all bytes in the <code>ByteArray</code> as samples.
  141.          *
  142.          *  
  143.          *  </p>
  144.          *
  145.          *  @param dataOutput The IDataOutput object that you want the WAV formated bytes to be written to.
  146.          *  @param dataInput    The audio sample data in float format.
  147.          *  @param inputSamplingRate The sampling rate of the <code>dataInput</code> data.
  148.          *  @param inputNumChannels The number of audio changes in <code>dataInput</code> data.
  149.          *     
  150.          */
  151.         public function processSamples(dataOutput:IDataOutput, dataInput:ByteArray, inputSamplingRate:int, inputNumChannels:int = 1):void
  152.         {
  153.             if (!dataInput || dataInput.bytesAvailable <= 0) // Return if null
  154.                 throw new Error("No audio data");
  155.            
  156.             // 16 bit values are between -32768 to 32767.
  157.             var bitResolution:Number = (Math.pow(2, sampleBitRate)/2)-1;
  158.             var soundRate:Number = samplingRate / inputSamplingRate;
  159.             var dataByteLength:int = ((dataInput.length/4) * soundRate * sampleBitRate/8);
  160.             // data.length is in 4 bytes per float, where we want samples * sampleBitRate/8 for bytes
  161.             var fileSize:int = 32 + 8 + dataByteLength;
  162.             // WAV format requires little-endian
  163.             dataOutput.endian = Endian.LITTLE_ENDIAN;  
  164.             // RIFF WAVE Header Information
  165.             header(dataOutput, fileSize);
  166.             // Data Chunk Header
  167.             dataOutput.writeUTFBytes("data");
  168.             dataOutput.writeUnsignedInt(dataByteLength); // Size of whole file
  169.            
  170.             // Write data to file
  171.             dataInput.position = 0;
  172.             var tempData:ByteArray = new ByteArray();
  173.             tempData.endian = Endian.LITTLE_ENDIAN;
  174.            
  175.             // Write to file in chunks of converted data.
  176.             while (dataInput.bytesAvailable > 0)
  177.             {
  178.                 tempData.clear();
  179.                 // Resampling logic variables
  180.                 var minSamples:int = Math.min(dataInput.bytesAvailable/4, 8192);
  181.                 var readSampleLength:int = minSamples;//Math.floor(minSamples/soundRate);
  182.                 var resampleFrequency:int = 100;  // Every X frames drop or add frames
  183.                 var resampleFrequencyCheck:int = (soundRate-Math.floor(soundRate))*resampleFrequency;
  184.                 var soundRateCeil:int = Math.ceil(soundRate);
  185.                 var soundRateFloor:int = Math.floor(soundRate);
  186.                 var jlen:int = 0;
  187.                 var channelCount:int = (numOfChannels-inputNumChannels);
  188.                 /*
  189.                 trace("resampleFrequency: " + resampleFrequency + " resampleFrequencyCheck: " + resampleFrequencyCheck
  190.                 + " soundRateCeil: " + soundRateCeil + " soundRateFloor: " + soundRateFloor);
  191.                 */
  192.                 var value:Number = 0;
  193.                 // Assumes data is in samples of float value
  194.                 for (var i:int = 0;i < readSampleLength;i+=4)
  195.                 {
  196.                     value = dataInput.readFloat();
  197.                     // Check for sanity of float value
  198.                     if (value > 1 || value < -1)
  199.                         throw new Error("Audio samples not in float format");
  200.                    
  201.                     // Special case with 8bit WAV files
  202.                     if (sampleBitRate == 8)
  203.                         value = (bitResolution * value) + bitResolution;
  204.                     else
  205.                         value = bitResolution * value;
  206.                    
  207.                     // Resampling Logic for non-integer sampling rate conversions
  208.                     jlen = (resampleFrequencyCheck > 0 && i % resampleFrequency < resampleFrequencyCheck) ? soundRateCeil : soundRateFloor;
  209.                     for (var j:int = 0; j < jlen; j++)
  210.                     {
  211.                         writeCorrectBits(tempData, value, channelCount);
  212.                     }
  213.                 }
  214.                 dataOutput.writeBytes(tempData);
  215.             }
  216.         }
  217.        
  218.         /**
  219.          *  @private
  220.          *  Change the audio sample to the write resolution
  221.          */
  222.         private function writeCorrectBits(outputData:ByteArray, value:Number, channels:int):void
  223.         {
  224.             // Handle case where input channels > output channels.  Sum values and divide values
  225.             if (channels < 0)
  226.             {
  227.                 if (tempValueCount+channels == 1)
  228.                 {
  229.                     value = int(tempValueSum/tempValueCount);
  230.                     tempValueSum = 0;
  231.                     tempValueCount = 0;
  232.                     channels = 1;
  233.                 }
  234.                 else
  235.                 {
  236.                     tempValueSum += value;
  237.                     tempValueCount++;
  238.                     return;
  239.                 }
  240.             }
  241.             else
  242.             {
  243.                 channels++;
  244.             }
  245.             // Now write data according to channels
  246.             for (var i:int = 0;i < channels; i++)
  247.             {
  248.                 if (sampleBitRate == 8)
  249.                     outputData.writeByte(value);
  250.                 else if (sampleBitRate == 16)
  251.                     outputData.writeShort(value);
  252.                 else if (sampleBitRate == 24)
  253.                 {
  254.                     outputData.writeByte(value & 0xFF);
  255.                     outputData.writeByte(value >>> 8 & 0xFF);
  256.                     outputData.writeByte(value >>> 16 & 0xFF);
  257.                 }
  258.                 else if (sampleBitRate == 32)
  259.                     outputData.writeInt(value);
  260.                 else
  261.                     throw new Error("Sample bit rate not supported");
  262.             }
  263.         }
  264.        
  265.     }
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement