Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 390
  • Last Modified:

recording audio through flash

Is there a way that I can record audio that my swf file produces and save it as a wav or mp3?  Ideally I would like to make an swf file I can embed on the web page that would capture all the audio that the other swf files on the page produce.
0
ForLoop5
Asked:
ForLoop5
  • 7
  • 6
1 Solution
 
dgofmanCommented:
I created this util to record sound to WAV and play WAV from Flash Player

var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onLoaderComplete);
urlLoader.load(new URLRequest(fileName));

function onLoaderComplete(e:Event):void {
      var urlLoader:URLLoader = e.target as URLLoader;
      urlLoader.removeEventListener(Event.COMPLETE, onLoaderComplete);
      var wavSound:Sound = new Wave().decode(urlLoader.data);
      wavSound.play();
}

Wave.as
package
{
	import flash.events.Event;
	import flash.events.SampleDataEvent;
	import flash.media.Sound;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class Wave
	{
		private static const RIFF:String = "RIFF";	
		private static const WAVE:String = "WAVE";	
		private static const FMT:String = "fmt ";	
		private static const DATA:String = "data";	

		private var _channel:WavSoundChannel;
		private var _bytes:ByteArray = new ByteArray();
		private var _buffer:ByteArray = new ByteArray();
		private var _volume:Number;
	
		public function Wave(volume:Number=1){
			_volume = volume;
		}

		/**
		 * 
		 * @param samples
		 * @param channels
		 * @param bits
		 * @param rate
		 * @return 
		 * 
		 */		
		public function encode(samples:ByteArray, channels:int=2, bits:int=16, rate:int=44100):ByteArray
		{
			var data:ByteArray = create( samples );
			
			_bytes.length = 0;
			_bytes.endian = Endian.LITTLE_ENDIAN;
			
			_bytes.writeUTFBytes(Wave.RIFF);
			_bytes.writeInt(data.length + 44);
			_bytes.writeUTFBytes(Wave.WAVE);
			_bytes.writeUTFBytes(Wave.FMT);

			// write fmt data
			_bytes.writeInt(16); // --------------------------------------- Subchunk1Size. 16 for PCM
			_bytes.writeShort(1); // -------------------------------------- formatValues other than 1 indicate some form of compression.
			_bytes.writeShort(channels); // ------------------------------- channels
			_bytes.writeInt(rate); // ------------------------------------- sample rate
			_bytes.writeInt(rate * channels * ( bits >> 3 )); //----------- ByteRate == SampleRate * channels * BitsPerSample / 8 
			_bytes.writeShort(channels * ( bits >> 3 )); //---------------- BlockAlign == channels * BitsPerSample / 8
			_bytes.writeShort(bits);
			_bytes.writeUTFBytes(Wave.DATA);
			_bytes.writeInt(data.length);// --------------------------------Subchunk2Size == NumSamples * channels * BitsPerSample/8
			_bytes.writeBytes(data);
			_bytes.position = 0;
			return _bytes;
		}

		protected function create(bytes:ByteArray):ByteArray
		{
			_buffer.endian = Endian.LITTLE_ENDIAN;
			_buffer.length = 0;
			bytes.position = 0;

			while( bytes.bytesAvailable ) 
				_buffer.writeShort( bytes.readFloat() * (0x7fff * _volume));
			return _buffer;
		}

		public function decode(wavData:ByteArray):Sound{
			var info:Object = getInfo(wavData);
			if (info['fmt '] && info['data']) {
				_channel = decodedChannel(info);

				var player:Sound = new Sound();
				player.addEventListener(SampleDataEvent.SAMPLE_DATA, onSamplesCallback);
				return player;
			} else {
				throw new Error('invalid wav file');
			}
		}
		
		private function onSamplesCallback(event:SampleDataEvent):void{
			if(isNaN(_channel.phase)){
				event.target.removeEventListener(SampleDataEvent.SAMPLE_DATA, onSamplesCallback);
			}else{
				_channel.write(event.data);
			}
		}

		protected function getInfo(bytes:ByteArray):Object {
			bytes.position = 0;
			bytes.endian = Endian.LITTLE_ENDIAN;
			
			if (bytes.readUTFBytes(4) == 'RIFF') {
				bytes.readInt();
				bytes.readUTFBytes(4);//type
			} else {
				bytes.position = 0;
			}
			
			var obj:Object = new Object();
			while (bytes.position < bytes.length) {
				var currentName:String = bytes.readUTFBytes(4);
				var current:int = bytes.readInt();

				var tmpByte:ByteArray = new ByteArray();
				bytes.readBytes(tmpByte, 0, current);
				
				if (current % 2 == 1) {
					bytes.readByte();
				}
				obj[currentName] = tmpByte;
			}
			return obj;
		}

		protected function decodedChannel(info:Object):WavSoundChannel {
			var bytes:ByteArray = info['fmt '] as ByteArray;
			bytes.position = 0;
			bytes.endian = Endian.LITTLE_ENDIAN;
			bytes.readShort();
			var channels:int = bytes.readShort();
			var sampleRate:int = bytes.readInt();
			var byteRate:int = bytes.readInt();
			var blockAlign:int = bytes.readShort();
			var bitRate:int = bytes.readShort();

			bytes = info['data'] as ByteArray;
			bytes.position = 0;
			bytes.endian = Endian.LITTLE_ENDIAN;

			var length:int = bytes.length / (bitRate / 8) / channels;
			var left:Vector.<Number> = new Vector.<Number>(length, false);
			var right:Vector.<Number> = new Vector.<Number>(length, false);
			if (channels == 2) {
				if (bitRate == 16) {
					for (var i:uint = 0; i < length; ++i) {
						left[i] = bytes.readShort() / 32767;
						right[i] = bytes.readShort() / 32767;
					}
					
				}
			}
			return new WavSoundChannel(left, right);
		}
	}
}

import flash.media.SoundTransform;
import flash.utils.ByteArray;

class WavSoundChannel {

	// works the same as SoundChannel.soundTransform
	private var _soundTransform:SoundTransform;

	// current phase of the sound, basically matches a single current sample frame for each WavSound
	private var _phase:Number;
	private var _left:Vector.<Number>;
	private var _right:Vector.<Number>;

	/**
	 * Constructor: pre-calculates starting phase (and performs some validation for this).
	 */
	public function WavSoundChannel(left:Vector.<Number>, right:Vector.<Number>, volume:Number=1) {
		_left = left;
		_right = right;
		_phase = 0;
		_soundTransform = new SoundTransform(volume);
	}

	public function write(outputStream:ByteArray):void {
		if(isNaN(_phase)) //completed
			return;

		// the master samples buffer in which all seperate Wavsounds are mixed into, always stereo at 44100Hz and bitrate 16
		var bufferSize:uint = 8192;
		var sampleBufferLeft:Vector.<Number> = new Vector.<Number>(bufferSize, false);
		var sampleBufferRight:Vector.<Number> = new Vector.<Number>(bufferSize, false);
		
		// calculate volume and panning
		var volume: Number = (_soundTransform.volume / 1);
		var volumeLeft: Number = volume * (1 - _soundTransform.pan) / 2;
		var volumeRight: Number = volume * (1 + _soundTransform.pan) / 2;
		// channel settings
		var needRightChannel:Boolean = true;
		var hasRightChannel:Boolean = true;
		
		// extra references to avoid excessive getter calls in the following 
		// for-loop (it appeares CPU is being hogged otherwise)
		var samplesLeft:Vector.<Number> = _left;
		var samplesRight:Vector.<Number> = _right;
		
		var i:int;
		var leftPeakRecord:Number = 0;
		var rightPeakRecord:Number = 0;

		for (i = 0; i < bufferSize; i++) {				
			// write (transformed) samples to buffer
			var sampleLeft:Number = samplesLeft[_phase] * volumeLeft;
			sampleBufferLeft[i] += sampleLeft;
			leftPeakRecord += sampleLeft;
			var channelValue:Number = ((needRightChannel && hasRightChannel) ? samplesRight[_phase] : samplesLeft[_phase]);
			var sampleRight:Number = channelValue * volumeRight;
			sampleBufferRight[i] += sampleRight;
			rightPeakRecord += sampleRight;
			
			// check playing and looping state
			if (++_phase >= _left.length) {
				_phase = NaN;
				break;
			}
		}
		
		// write all mixed samples to the sound's outputstream
		for (i = 0; i < bufferSize; i++) {
			outputStream.writeFloat(sampleBufferLeft[i]);
			outputStream.writeFloat(sampleBufferRight[i]);
		}
	}
	
	public function get phase():Number{
		return _phase;
	}
}

Open in new window

0
 
ForLoop5Author Commented:
dgofman does that record sound playing from the same swf? Or all sound outpur? or does it record the mic?
0
 
dgofmanCommented:
Does that record sound playing from the same swf?  - Yes

Or all sound output? - I provided in and out API for WAV format

Or does it record the mic? - My code it's not for recording but you can record and pass WAV format stream
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
ForLoop5Author Commented:
Anyway I can pay you to integrate this into one of my widgets?
0
 
dgofmanCommented:
Let's starts from your current implementation can you attach your project?
0
 
dgofmanCommented:
You don't need to pay me here is existing example

http://www.bytearray.org/?p=1858
0
 
ForLoop5Author Commented:
Here is simple example of 4 buttons that play sounds when clicked.  It wont allow me to attach the .fla file for some reason.  
GreenButton.addEventListener(MouseEvent.CLICK, fl_ClickToPlayStopSound);

function fl_ClickToPlayStopSound(evt:MouseEvent):void
{

		
		 var mySound1:one=new one();
        	 mySound1.play();
			 
			 

}



OrangeButton.addEventListener(MouseEvent.CLICK, fl_ClickToPlayStopSound2);



function fl_ClickToPlayStopSound2(evt:MouseEvent):void
{

 var mySound2:two=new two();
        	 mySound2.play();

}



BlueButton.addEventListener(MouseEvent.CLICK, fl_ClickToPlayStopSound3);




function fl_ClickToPlayStopSound3(evt:MouseEvent):void
{

 var mySound3:three=new three();
        	 mySound3.play();

}



RedButton.addEventListener(MouseEvent.CLICK, fl_ClickToPlayStopSound4);




function fl_ClickToPlayStopSound4(evt:MouseEvent):void
{

 var mySound4:four=new four();
        	 mySound4.play();

}

Open in new window

rec.swf
0
 
dgofmanCommented:
You can attach FLA if you will save as CS4 format
0
 
ForLoop5Author Commented:
Attached is the fla.  
rec.fla
0
 
ForLoop5Author Commented:
Should I try something else?
0
 
dgofmanCommented:
I will check tomorrow
0
 
ForLoop5Author Commented:
I used the example link you sent me and modified the ui and created a record button and it records the mic and saves it to wav nicely.  but Im really interested in being able to record the sounds the flash file plays and saving them to wav or mp3.  So if you seen my example file it has 4 sounds in it.  They are stored in the library.  So I will be playing them locally and not calling them with a urlRequest

So if I were to play the sound through a sound channel I use the code below

var mySound1a:SoundChannel;
var s:Sound = new black1();
mySound1a = s.play();

And these lines of code look to create the Wave encoder object and then output the file as "recorded.wav"

new WaveEncoder()                  
_file.save(mySound1a.output, "recorded.wav");

Would I need to put the "new WaveEncoder()"   inside these parentheses "mySound1a = s.play(new WaveEncoder());"      when I play the sound?
                  
0
 
dgofmanCommented:
Hi ForLoop5,
Sorry I was busy, but I am happy to know you are trying to solve problem yourself.
That is better because you need to understand a code. So, let me try to answer on your questions.
1)      Yes the link what I am providing is encoding RAW bytes to  WAV 16 bits using bit rate 44100
2)      But Flash Player cannot play any WAV file that reason why you have to decode WAV to RAW.
The first you need to load WAV file

var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onLoaderComplete);
urlLoader.load(new URLRequest(fileName));
Next step on onLoaderComplete we need to decode

private function onLoaderComplete(e:Event):void {
      var urlLoader:URLLoader = e.target as URLLoader;
      urlLoader.removeEventListener(Event.COMPLETE, onLoaderComplete);
      var wavSound:Sound = new Wave().decode(urlLoader.data);

Now you can play
      wavSound.play();
}
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 7
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now