Good morning!
I'm trying to create a visual waveform for an MP3. The code I've included is called on successful load of the MP3. I intend to extract just a few important samples from the sound to create the waveform, rather than extract the entire sound into a bytearray. Even on a good machine, extracting an entire song can cause flash to freeze up for 3-5 seconds (or longer!). For my purposes, this isn't feasible.
Unfortunately, the code I've got below is failing to produce any numbers. If I extract the entire song it functions, but extraction of just the key points is giving me nothing. Does performing an extract make the remainder of the sound object invalid for future extracts? If so, is there some way around this that won't freeze flash for an extended period of time during the extract?
Some important variables from the rest of the code:
waveFormWidth: static width of the wave form sprite.
waveFormHeight: static height of the wave form sprite.
song: sound object that I'll be using to create the wave form.
public function mapWaveForm(e:Event = null):void
{
// Clear the wave form sprite
waveForm.graphics.clear();
waveForm.graphics.lineStyle(0, 0x000000, 1);
// Storage for the wave form bit data
var byteOutput:ByteArray;
var leftPeakSize:Number;
var rightPeakSize:Number;
var songTotalSamples:int;
var thisSample:int;
byteOutput = new ByteArray();
// How many samples?
songTotalSamples = (song.length * 44.1);
// Loop for the wave form width
for (var peakCount:int = 0; (peakCount < waveFormWidth); peakCount++)
{
// Get info at each peak.
thisSample = Math.floor(songTotalSamples * (peakCount / waveFormWidth));
song.extract(byteOutput, 1, thisSample);
byteOutput.position = 0;
trace(thisSample, byteOutput.readFloat());
leftPeakSize = byteOutput.readFloat() / 1.27;
rightPeakSize = byteOutput.readFloat() / 1.27;
// Turn those peaks into something usable.
leftPeakSize = leftPeakSize * (waveFormHeight * .5);
rightPeakSize = rightPeakSize * (waveFormHeight * .5);
// Make the left channel line
waveForm.graphics.moveTo(peakCount, (waveFormHeight * .5));
waveForm.graphics.lineTo(peakCount, (waveFormHeight * .5) - leftPeakSize);
// Make the right channel line
waveForm.graphics.moveTo(peakCount, (waveFormHeight * .5));
waveForm.graphics.lineTo(peakCount, (waveFormHeight * .5) + rightPeakSize);
}
}
Thanks for your help guys!
For what it's worth, I was just working on the EXACT same thing and I just got it working after some research. I cannot seem to get it to work with WAV files, but this is compatable with MP3 files of all types. This is what I ended up with:
var IMAGE_SIZE:int = new int(600); // Final width of image
var IMAGE_DEPTH:int = new int(5); // How many passes per pixel of image
var RESOLUTION:int = new int(IMAGE_SIZE * IMAGE_DEPTH);
var DRAW_AMPLITUDE:int = new int(150); // pixel height of max volume line
var waveForm:Shape = new Shape();
var mp3File:Sound = new Sound();
mp3File.load(new URLRequest("audio.mp3"));
mp3File.addEventListener(Event.COMPLETE, parseSound);
function parseSound(e:Event):void {
var soundBytes:ByteArray = new ByteArray();
for (var i:int=0; i<RESOLUTION; i++) {
mp3File.extract(soundBytes, 1, Math.floor((mp3File.length*44.1)*(i/RESOLUTION)));
soundBytes.position = 0;
while (soundBytes.bytesAvailable > 0) {
var tmpNum:Number = new Number();
tmpNum += soundBytes.readFloat();
}
drawWave(i, tmpNum);
soundBytes.clear();
}
this.addChild(waveForm);
trace("--DONE--");
}
function drawWave(i:Number, amp:Number):void {
var pixX:Number = new Number(Math.floor(i/IMAGE_DEPTH));
var pixY:Number = new Number((amp*DRAW_AMPLITUDE)/2);
waveForm.graphics.lineStyle(1, 0x0, (1.2/IMAGE_DEPTH));
waveForm.graphics.moveTo(pixX, ((DRAW_AMPLITUDE/2)-pixY));
waveForm.graphics.lineTo(pixX, ((DRAW_AMPLITUDE/2)+pixY));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With