Fast Fourier Transform With Microphone Input Data in AS3 - actionscript-3

Is it possible to get the source of adobes flash.media.SoundMixer class ?
If it is, where can i find / get it ?
I waht to "clone" the .computeSpectrum() function to transform a raw sound wave ( byteArray ) from Microphone input into a frequency spectrum.
I've found a couple of examples like this one -> http://pierrickpluchon.fr/blog/as3-how-to-plug-your-microphone-with-a-soundspectrum-in-flash-player-10-1/
All other methos i've found are pretty much the same.
The problem is that there is always a Sound() playing, what i DON'T want. ( I don't want any loopback )
But if i'm not playing a sound, i can't use the SoundMixer.computeSpectrum() function to transform my ByteArray that comes from the Microphone to a frequency spectrum by turning the FFTMode to true ( computeSpectrum(myByteArray,true) )
Also if you know any other method to get the Frequency Spectrum from the Raw Sound Wave, please let me know.
UPDATE
my code:
var bytes:ByteArray = new ByteArray();
var mic:Microphone = Microphone.getMicrophone();
mic.rate = 44;
// mic.gain = 100; // gain
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
function onSampleData( event:SampleDataEvent ):void {
graphics.clear();
graphics.lineStyle(1, 0xFF0000);
for( var i:uint = 0; i < 256; i++ ) {
var num:Number = event.data.readFloat() * 100 + 100; // -Math.abs( )
if( i == 0 ) {
graphics.moveTo( i, num );
} else {
graphics.lineTo( i, num );
}
}
}

"..Also if you know any other method to get the Frequency Spectrum from the Raw Sound Wave, please let me know."
Well Joe Beuckman beat me to it and gave you the link to Gerry Beauregard's FFT code. That's the best AS3 one I've seen so far since I found it two years ago. From the comments I see you were wondering how to implement... Well to see implementation code you need to see another page on his blog:
http://gerrybeauregard.wordpress.com/2010/08/06/real-time-spectrum-analysis/
To test that code yourself you first have to save the classes shown in the link here: http://gerrybeauregard.wordpress.com/2010/08/03/an-even-faster-as3-fft/
Save each package's code respectively as FFT2.as and FFTElement.as
Now in your document class put the code from: http://gerrybeauregard.wordpress.com/2010/08/06/real-time-spectrum-analysis/
However in that code you must also add some lines importing the other saved .as classes
import __AS3__.vec.Vector;
import flash.display.Sprite;
import flash.events.*;
import flash.media.Microphone;
import flash.text.*;
import flash.utils.*;
import FFT2;
import FFTElement;
Now it should run without errors and show the same thing as screenshot on his blog. The online demo used to work for me but not today so I say screenshot just so you know what to expect when it works fine.
Hope it helps. VC:One

FFT means the Fast Fourier Transform. That is exactly the algorithm that transforms the raw sound wave values into the frequency space. You should be able to find (or port) an implementation of the FFT in AS3, and that does what you ask.

Related

AS3 best way to mass crop tiles from a tilesheet?

Okay so I'm trying to create a program that reads a map from a csv file and then draw each tile using a tilesheet. Reading in the map works fine and I could draw certain tiles depending on the value read in but only if I embedded the images. Obviously this is impractical when it comes to having >20 different tiles; embedding them all just wouldn't be smart.
This is my code for drawing the tiles from the tilesheet.
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;
public class Tile extends Sprite
{
[Embed(source="../bin/lib/TileSheet.png")]
private var BitmapClass:Class;
private var tileBitmap:Bitmap = new BitmapClass();
var tileSize = 25;
var tileSheetLength = 20;
var sheetColumns:int = tileBitmap.bitmapData.width / tileSize;
var pt:Point = new Point(0, 0);
var bmp:Bitmap = new Bitmap(new BitmapData(tileSize, tileSize, true, 0));
public function Tile(collide:Boolean, id:int)
{
Draw(id);
}
private function Draw(id:int):void
{
var col:int = id % sheetColumns;
var row:int = Math.floor(id / sheetColumns);
var rect:Rectangle = new Rectangle(col * tileSize, row * tileSize, tileSize, tileSize);
bmp.bitmapData.copyPixels (tileBitmap.bitmapData, rect, pt, null, null, true);
this.addChild(bmp);
}
public function Update():void
{
}
}
}
'
So what I need help with is optimising this code so that I can run it around 1,900 times rather than the 910-911 times it can handle right now before just closing without errors. If there is a better way of doing this please let me know and any constructive criticism is always appreciated!
You have a Tile class which has a BitmapClass instance. Perhaps that should be a static property (belonging to the class, not every instance) to begin with. My guess is you're using the memory for the whole tile sheet every since time you instantiate a single tile which you probably don't want to do.
Another thing I'm noticing is you're creating a new BitmapData for each tile, when in fact you probably just need the tile data (it's id/coordinates) so you can copy pixels into the final BitmapData which gets displayed on stage. Perhaps you need to a class to manage resources(embedded bitmaps) and another to manage the different Tile instance(which should hold render data and references to pixels, but shouldn't store the actual data) and copying to the main buffer.
Also, it's a good idea to use BitmapData's lock() and unlock() functions for performance when doing multiple pixel operations on an image.
Have a look at Lee Brimelow's Sprite Sheet tutorials (part 1,2 and especially 3). They're really easy to follow and useful.
Also, it might be worth having a look at the have a look at the GPU accelerated IsoHill
library.
I've used IsoHill for a project before and it's quite fast, but it's best to get comfortable with the basics first, otherwise this might seem a bit much.

Saving customized movieclip as an image to local disk (diy generator)

dropbox.com/s/77euop1luqjreos/FINAL.fla
Ok i just gave up with this already. I cant think of any way to save the image created by a user. Its hard to explain but please check out the fla file of my work. Basically its a diy generator. The only thing missing is a save function. Ive read filereference but its always in a document class. My code is in the timeline. Please help I'm really stuck.
edit: I got a download button that is working now!! But it only saves a small part of the movieclip: Imgur
In order to create images, you need to access the pixel data of the MovieClip object. The data can be obtained by rendering a MovieClip into a BitmapData object and using this data, you can write your own encoder to convert it to any image format you’d like. Writing such encoder is not a trivial task and requires understanding of the image format algorithm, or you can use pre-written libraries. You can download the PNGEncoder and JPGEncoder , which is part of as3corelib, an open source project library.
Using the JPGEncoder, we can convert DisplayObject into ByteArray, suitable for saving into file. If using the JPGEncoder, it’ll look like this:
import com.adobe.images.JPGEncoder;
var jpgEncoder:JPGEncoder = new JPGEncoder(quality);
//remember bitmapData here is just an example (do not try to compile this code without declare this particular variable)
var byteArray:ByteArray = jpgEncoder.encode(bitmapData);
With the PNGEncoder, it’ll look like this:
import com.adobe.images.PNGEncoder;
//remember bitmapData here is just an example (do not try to compile this code without declare this particular variable)
var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
Saving Into User’s Hard Drive
Using the FileReference.save() function, we can prompt the user to save the file with the following call.
var fileReference:FileReference=new FileReference();
//in case of JPGEncoder
fileReference.save(byteArray, ".jpg");
With the two combined, here’s an example how to use:
//remember to import
import flash.net.FileReference;
import com.adobe.images.JPGEncoder; //or import com.adobe.images.PNGEncoder;
import flash.utils.ByteArray;
import flash.display.BitmapData;
//where mc_canvas will be your MovieClip instance name
var bitmapData:BitmapData = new BitmapData(mc_canvas.width, mc_canvas.height);
bitmapData.draw(mc_canvas);
var jpgEncoder:JPGEncoder = new JPGEncoder(quality_slider.value);
var byteArray:ByteArray = jpgEncoder.encode(bitmapData);
//if you want to use PNGEncoder
//var byteArray:ByteArray = PNGEncoder.encode(bitmapData);
var fileReference:FileReference = new FileReference();
fileReference.save(byteArray, ".jpg");

1120 Access of undefined property Ibar & Ipc

stop();
import flash.display.*;
this.stop();
this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, PL_LOADING);
function PL_LOADING(event: ProgressEvent): void {
var pcent: Number = event.bytesLoaded / event.bytesTotal * 100;
lbar.scaleX = pcent / 100;
lpc.text = int(pcent) + "%";
if (pcent == 100) {
this.gotoAndStop(2);
}
}
You'll do well to enable "Permit Debugging", however, the issue is on lines 14 & 15. It means you don't have an object in memory by those names. If you're working in the Flash IDE, and these are symbols in your library, add them to the stage, the and issue will be resolved.
Well, this code structure looks a bit disorganized. I'm not sure whether a lot of these changes will matter (since I currently don't have access to flash), but here is how I would typically write this:
stop();
import flash.display.*;
//no need for this.stop() if you've already stopped
this.loaderinfo.addEventListener(ProgressEvent.PROGRESS,PL_LOADING);
function PL_LOADING(e:ProgressEvent):void{
//possibly part of the problem is that the var keyword was on the wrong line
var pcent:Number = e.bytesLoaded/e.bytesTotal*100;
ibar.scaleX=pcent/100;
ipc.text=String(int(pcent)+"%");
//typically you want to make it clear that it's a string when dealing with text fields
if(pcent==100){
gotoAndStop(2);
}
}
Small changes like these as well as thoughtful organization could save your code. If you're still having problems with your code just notify me and I'll try to help you out.

ActionScript : Sound from ByteArray has lag

In my application, I use the microphone to record and get the result in ByteArray, then, I convert it in playable Sound by using the WavSound class from org.as3wavsound.
Record and play work correctly except a huge lag at the launching of the sound ( Easily 2 secondes ).
My code is something like this :
import org.as3wavsound.WavSound;
import org.bytearray.micrecorder.encoder.WaveEncoder;
import org.bytearray.micrecorder.MicRecorder;
/* ... */
var wavEncoder:WaveEncoder = new WaveEncoder( 0.5 );
var recorder:MicRecorder = new MicRecorder( wavEncoder );
recorder.record();
/* ... */
recorder.stop();
var sound:WavSound = new WavSound( recorder.output );
/* ... */
sound.play();
Thanks a lot to help me understand what's wrong in it.
Looks like this is a known issue with the as3wavsound library: Delay When Playing Sound using as3wavsound
The answer on that post tells you to decrease the MAX_BUFFERSIZE in WavSoundPlayer to 2048.

Accurate BPM event listener in AS3

I'm trying to sync animation to music at a specific BPM. I've tried using the Timer but it isn't accurate when dealing with small intervals in milliseconds. I did some reading and found an alternate method that uses a small silent audio file and the SOUND_COMPLETE event as a Timer.
I used 167ms long sound file with this code.
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
public class BetterTimer extends EventDispatcher
{
private var silentSound:Sound;
public function BetterTimer(silentSoundUrl:String):void {
super();
silentSound = new Sound( new URLRequest(silentSoundUrl) );
silentSound.addEventListener(Event.COMPLETE, start);
}
public function start():void {
this.timerFired( new Event("start") );
}
private function timerFired(e:Event):void {
dispatchEvent( new Event("fire") );
var channel:SoundChannel = silentSound.play();
channel.addEventListener(Event.SOUND_COMPLETE, timerFired, false, 0, true);
}
}
}
This still doesn't stay on beat. Is the Flash Player capable of accuracy with sound?
You can also use the new Sound API with the SampleDataEvent and basically play your MP3 manually using Sound.extract(). In that case you know the latency up front and can even count up to the sample when your (delayed) event should happen.
This is what we do in the AudioTool and it works very well.
This is very tricky to get right! There's a small lib called BeatTimer that tries to do this. I haven't tried this code myself, but if it does what it claims it should be exactly what you need.
Setting the frame rate so that the event interval is a multiple of the frame rate might help (for example, 167ms equals 6 fps; 12, 18, 24 etc. are then also ok).
If I understood correctly, better solution would be to use the enterframe event. Instead of determining the position of the animation by counting the events, calculate it using elapsed time (getTimer or sound position). This would also make the animation work on slower computers that have lag.
I was looking through the popforge library's AudioBuffer and tried using one of the approach. That's the create a sync sound. The following is what i did.
var syncSamples:ByteArray = new ByteArray();
syncSamples.length = (2646000 / _bpm) << 1; /*44100*60=2646000*/
SoundFactory.fromByteArray(syncSamples, Audio.MONO, Audio.BIT16, Audio.RATE44100, soundInit);
The ms delay is pretty close, eg: at 120 BPM, it's between 509 - 512ms. The question is, am I going in the right direction?