Display an estimated "position" of an MP3 while streaming

One of the problems I’ve noticed with a lot of Flash based MP3 players is displaying/changing the position while the file is still loading. The reason for this of course is that the ‘duration’ property Flash gives you is based on how much of the file is currently loaded. The solution used in every player I have seen is either to show the position based on the duration which is wrong because the duration changes as the file loads or simply not to show or allow control of the position at all. The other possibility is to read the MP3s ID tags, this however can be error-prone using Flash’s ID methods so can not be relied on.

I came up with a solution to this a year ago and since I’m still seeing people having trouble with this I figured I’d post it here.

If you take a look at my MP3 player at http://www.audiotheory.co.uk you will notice that my position indicator (the yellow bar) behaves as it should with no relation to the loading indicator (the red bar) and you can in fact change the position even while the file is still loading.

The trick is to throw accuracy out the window (accuracy? I don’t need no stinkin’ accuracy!) and **estimate **the position using the file size and the current duration. Since MP3s are compressed (and one of those compression options is Variable Bitrate) this is an estimate, however I’ve thrown many files at it varying in compression method and size (check the last file in the playlist on my site - it’s over an hour long!) and it works very well.

[SIZE=4]Display Current Position[/SIZE]
To display the position I have an UpdateMP3Info method that is called on a timer. You can of course use onEnterFrame, I simply use a timer as I’m happy to only update the MP3’s info a couple of times a second and conserve those precious CPU cycles for things that require smoother animation. Inside UpdateMP3Info among other things I do the following.

First update the streaming bars _xscale to reflect the percentage of file loaded:

[FONT=Courier New] mcMP3.mcStreamBar.[/FONT][FONT=Courier New][COLOR=RoyalBlue]_xscale[/COLOR][/FONT][FONT=Courier New] = (myTunes.[/FONT][FONT=Courier New][COLOR=RoyalBlue]getBytesLoaded[/COLOR][/FONT]FONT=Courier New / myTunes.[/FONT][FONT=Courier New][COLOR=RoyalBlue]getBytesTotal[/COLOR][/FONT]FONT=Courier New) * 100;

[FONT=Verdana]Then calculate the position as a percentage of the current duration and multiply by 1% of the streaming bars _width to get the _width of the position bar:[/FONT]

mcMP3.mcPositionBar.[COLOR=RoyalBlue]_width[/COLOR] = ((myTunes.[COLOR=RoyalBlue]position[/COLOR] / myTunes.[COLOR=RoyalBlue]duration[/COLOR]) * 100) * (mcMP3.mcStreamBar.[COLOR=RoyalBlue]_width[/COLOR] / 100);
[SIZE=4]Set New Position[/SIZE]
To set the position based on where the user clicks you need the _xmouse value converted into a percentage so I use the following code in the onRelease handler of an invisible MovieClip called mcPositionBarHL that sits *above *the Position/Streaming bars.
This MovieClip is the red highlight you see when you rollover the Position/Streaming bars. When a MovieClip has it’s _alpha property set to 0 it can not be clicked on so as soon as the user moves the mouse off the Position/Streaming bar mcPositionBarHL disappears and the position can no longer be changed. This is good since you don’t want the user to change the position to a part of the file that hasn’t yet loaded!

First I set the Position bars _xscale so that it reaches where the user clicked by converting the _xmouse property of the mcPositionBarHL into a percentage:

[FONT=Courier New]mcMP3.mcPositionBar.[COLOR=RoyalBlue]_xscale[/COLOR] = (mcMP3.mcPositionBarHL.[COLOR=RoyalBlue]_xmouse[/COLOR] / mcMP3.mcPositionBarHL.[COLOR=RoyalBlue]_width[/COLOR]) * 100;[/FONT]

Then I simply use the same position estimate equation but in reverse to set the Sound objects new position. The Sound objects start method uses seconds while the estimate is in milliseconds so it must be divided by 1000:

[FONT=Courier New]myTunes.[COLOR=RoyalBlue]start[/COLOR]( ( ( mcMP3.mcPositionBar.[COLOR=RoyalBlue]_width[/COLOR] * ( 100/mcMP3.mcStreamBar.[COLOR=RoyalBlue]_width[/COLOR])) * (myTunes.[COLOR=RoyalBlue]duration[/COLOR] / 100)) / 1000);

[FONT=Verdana]And that’s it!
[/FONT][/FONT][FONT=Courier New][FONT=Verdana]The only visible sign that it’s an estimate is certain files cause the position bar to move a pixel or two back once the file has completely loaded but this only happens once and IMHO is a huge improvement on the shrinking position bar seen in players that simply use the duration property.
[/FONT][/FONT][FONT=Courier New][FONT=Verdana]It’s not a perfect solution but with the methods available in AS2 it’s the best you’re going to get without delving into some Flash to PHP MP3 library communication.

I hope this has been of help, feel free to shoot any questions my way. :beam: