4

I have dynamically created Sound object

var     files:Object={};
files["file1"]={};
files["file1"]["snd"]=new Sound();
...... //url etc
files["file1"]["snd"].addEventListener(ProgressEvent.PROGRESS, onLoadProgress); 

function onLoadProgress(event:ProgressEvent):void 
//// somehow I need to get the raw data (first 48 bytes to be exact) of the mp3 file which is downloading now
}

I tried URLRequest in that fuction

var myByteArray:ByteArray = URLLoader(event.target).data as ByteArray;

but with no success

It's just funny that such a simple thing as the file data is so hard to get

el Dude
  • 5,003
  • 5
  • 28
  • 40
  • 1
    (From top of my head) : In the progress event, test to see if you have at least your 48 bytes via the `.bytesLoaded` property on the event and if so, via the Sound `.extract` method, extract the 48 bytes to a byte array. If you are trying to decode mp3 frame data/id3v2/etc... you might be better using `URLStream`, do your raw byte processing and than covert that byte array to your Sound object. – SushiHangover Mar 18 '16 at 16:27
  • @SushiHangove Oh, `Sound .extract` extracts processed data (frames), on my biggest regret. It has nothing to do with the raw mp3 file data – el Dude Mar 18 '16 at 16:50
  • Than use `URLStream`, read and convert from there – SushiHangover Mar 18 '16 at 18:19
  • @SushiHangover seems like too much code to rewrite – el Dude Mar 18 '16 at 20:20
  • @elDude Are you looking for ID3 info ? If yes, you can use an `Event.ID3` event listener on your `Sound` object to get that ... – akmozo Mar 20 '16 at 16:58
  • 1: The code that you are showing cannot work. 2: using URLStream will work. 3: Your words: "seems like too much code to rewrite". 4: You do not want to rewrite a code that is already not working. 5: You are asking for a miracle and miracle never happen in coding. Use URLStream and fix your problem or stop wasting your time and ours. – BotMaster Mar 21 '16 at 12:26

1 Answers1

3

flash.media.Sound is a high level class that allows you to play a sound file in one line : new Sound(new URLRequest('your url')).play(); but does not provide public access to the data being loaded

The class will handle streaming for you (more precisely, progressive download)

If you need to access id3 data, just listen the Event.ID3 event:

var sound:Sound = new Sound("http://archive.org/download/testmp3testfile/mpthreetest.mp3");
sound.addEventListener(Event.ID3, onId3);
sound.play();
function onId3(e:Event):void {
    var id3:ID3Info = (e.target as Sound).id3;
    trace(id3.album, id3.artist, id3.comment, id3.genre,
        id3.songName, id3.track, id3.year);
}

If you really need to get the raw first 48 bytes and process them by yourself, but keep in mind you will have to deal with various mp3 formats id3/no id3, and work directly on binary data, instead of letting actionscript do the work for you. Assuming you don't want to download the mp3 file twice, you can either:

  • Load the mp3 file as ByteArray with URLLoader, read the 48 bytes manually, and load the Sound instance from memory, thus losing any progressive download ability. :

    var l:URLLoader = new URLLoader;
    l.dataFormat = URLLoaderDataFormat.BINARY;
    l.addEventListener(Event.COMPLETE, onComplete);
    l.load(new URLRequest("http://archive.org/download/testmp3testfile/mpthreetest.mp3"));
    function onComplete(e:Event):void {
        //do whatever you need to do with the binary data (l.data)
        // ...
        // load sound from memory
        new Sound().loadCompressedDataFromByteArray(l.data, l.data.length);
    
  • You could also load use the Sound class in the classic way (to allow progressive download), and load independently the first 48 bytes with a URLStream, and close the stream ASAP (only onie packet of network overhead, plus you might get it from cache anyway) :

    var s:URLStream = new URLStream;
    s.addEventListener(ProgressEvent.PROGRESS, onStreamProgress);
    s.load(new URLRequest("http://archive.org/download/testmp3testfile/mpthreetest.mp3"));
    function onStreamProgress(e:ProgressEvent):void {
        if (s.bytesAvailable >= 48) {
            // whatever you need to do with the binary data: s.readByte()...
            s.close();
        }
    }
    

I'm still curious to know why you would need those 48 bytes ?

EDIT: since the 48 bytes are supposed to be fed to MP3InfoUtil, you don't need to do anything particular, just let the lib do the work :

MP3InfoUtil.addEventListener(MP3InfoEvent.COMPLETE, yourHandler);
MP3InfoUtil.getInfo(yourMp3Url);
jauboux
  • 888
  • 6
  • 12
  • I didn't thought about cache. In my case it's really much simple to download it again (from cache) after oncomplete event. Of course this is not the answer to my question (I thought of something like URLStream in my `Object`) but I think there's no other way then the one You've given – el Dude Mar 21 '16 at 16:20
  • ps 48 bytes - for `MP3InfoUtil`. I was told it's better than as3's `Sound`'s native `id` – el Dude Mar 21 '16 at 16:21
  • I had a look to MP3InfoUtil, it's already using a URLStream to fetch the first 48 bytes so I updated the answer – jauboux Mar 21 '16 at 17:37
  • I rewrited some code of `MP3InfoUtil` to parse only `ByteArray` data, but also I was sure there's no problem to get the raw data from `Sound` object )) – el Dude Mar 21 '16 at 18:01
  • you already have MP3InfoUtil.analyze(bytes:ByteArray) to process from memory, and MP3InfoUtil.getInfo(url:String,...) that works on remote url, I don't think you need more – jauboux Mar 22 '16 at 10:15
  • that's not resolves my question. though. Btw it is much simplier for me to pass these 48bytes via `php>html>as3` rather then rewrite as3 code with additional routines – el Dude Mar 22 '16 at 14:49
  • anyway thanx for your answer – el Dude Mar 22 '16 at 14:50
  • it doesn't sound more simple than just call `MP3InfoUtil.getInfo(mp3Url);` , in your case: `MP3InfoUtil.getInfo(files["file1"]["snd"].url);` . I don't understand why you want to load bytes by php since MP3InfoUtil already has the code to do it, and get the infos at the same time, in just one line of code – jauboux Mar 22 '16 at 17:24
  • probably. But I was curious about `Sound` object – el Dude Mar 22 '16 at 19:21
  • @elDude, you're over-complicating it by `php>html>as3`. Simply make a bytearray, tell urlstream to load the bytes of some mp3 url. Now just read **all bytes** into that bytearray (otherwise they stream into nowhere). From there you can sample the 48 bytes if needed or just play using the `loadCompressed...` method. – VC.One Mar 22 '16 at 19:56
  • @elDude, also is this question really "How to get ID3 from MP3?" (ID3 is artist name, album etc) or is it really "How to get technical MP3 info" (like samplerate = 44.1k and bit-depth = 16 bit) etc??. Anyways none of those are in the first 48 bytes. To me its a random number. Metadata is always more than 48 bytes and even without it, the technical info is in the first 5 bytes of every MP3 frame. Update your question with **what you really need from an MP3 file** and I will try to answer... – VC.One Mar 22 '16 at 20:07
  • @VC.One no problem to feed more if there's a need. I mean if you can get 48bytes, then you can always get more (mp3util seems like uses first 48, maybe I am wrong) )) – el Dude Mar 22 '16 at 20:33
  • mp3infoutil (https://code.google.com/archive/p/mp3infoutil/) is supposed to get `bitRate|sampleRate|mpegLayer|mpegVersion|channelMode|channels|lengthBytes|lengthSeconds|lengthFormatted|frameCount|isVBR|isCBR` from those 48 bytes – jauboux Mar 23 '16 at 17:06
  • @jauboux Hoping this is true )) – el Dude Mar 23 '16 at 17:33