Skip to content

Instantly share code, notes, and snippets.

@claus
Created October 25, 2009 20:31
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save claus/218226 to your computer and use it in GitHub Desktop.
Save claus/218226 to your computer and use it in GitHub Desktop.
// Author: Claus Wahlers
// License: Public Domain
// Dependencies:
// as3commons-bytecode-1.0-RC1.swc
// as3commons-lang-0.3.2.swc
// as3commons-logging-2.0.swc
// as3commons-reflect-1.3.4.swc
// as3swf.swc
// MinimalComps_0_9_9.swc
package
{
import com.bit101.components.PushButton;
import com.codeazur.as3swf.SWF;
import com.codeazur.as3swf.SWFData;
import com.codeazur.as3swf.data.SWFSymbol;
import com.codeazur.as3swf.tags.TagDefineSound;
import com.codeazur.as3swf.tags.TagDoABC;
import com.codeazur.as3swf.tags.TagEnd;
import com.codeazur.as3swf.tags.TagFileAttributes;
import com.codeazur.as3swf.tags.TagShowFrame;
import com.codeazur.as3swf.tags.TagSymbolClass;
import org.as3commons.bytecode.abc.AbcFile;
import org.as3commons.bytecode.emit.IAbcBuilder;
import org.as3commons.bytecode.emit.IClassBuilder;
import org.as3commons.bytecode.emit.IPackageBuilder;
import org.as3commons.bytecode.emit.impl.AbcBuilder;
import org.as3commons.bytecode.io.AbcSerializer;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.media.Sound;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.utils.ByteArray;
public class MP3FileRefLoader extends Sprite
{
private static const PACKAGENAME:String = "tmp";
private static const CLASSNAME:String = "SoundClass";
private static const QNAME:String = PACKAGENAME + "." + CLASSNAME;
public function MP3FileRefLoader()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE
addChild(new PushButton(this, 10, 10, "Load MP3", function():void {
var ref:FileReference = new FileReference();
ref.addEventListener(Event.SELECT, function(e:Event):void { ref.load(); });
ref.addEventListener(Event.COMPLETE, function(e:Event):void { loadBytes(ref.data); });
ref.browse([new FileFilter("MP3 (*.mp3)", "*.mp3")]);
}));
}
protected function loadBytes(mp3:ByteArray):void {
// Wrap the MP3 with a SWF
var swf:ByteArray = createSWFFromMP3(mp3);
// Load the SWF with Loader::loadBytes()
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, initHandler);
loader.loadBytes(swf);
}
protected function initHandler(e:Event):void {
// Get the sound class definition
var SoundClass:Class = LoaderInfo(e.currentTarget).applicationDomain.getDefinition(QNAME) as Class;
// Instantiate the sound class
var sound:Sound = new SoundClass() as Sound;
// Play the sound
sound.play();
}
protected function createSWFFromMP3(mp3:ByteArray):ByteArray
{
// Create an empty SWF
// Defaults to v10, 550x400px, 50fps, one frame (works fine for us)
var swf:SWF = new SWF();
// Add FileAttributes tag
// Defaults: as3 true, all other flags false (works fine for us)
swf.tags.push(new TagFileAttributes());
// Add DefineSound tag
// The ID is 1, all other parameters are automatically
// determined from the mp3 itself.
swf.tags.push(TagDefineSound.createWithMP3(1, mp3));
// Create and add DoABC tag
// Contains the AS3 byte code for the class definition for the embedded sound:
// package tmp {
// public dynamic class SoundClass extends flash.media.Sound {
// }
// }
var abcBuilder:IAbcBuilder = new AbcBuilder();
var packageBuilder:IPackageBuilder = abcBuilder.definePackage(PACKAGENAME);
var classBuilder:IClassBuilder = packageBuilder.defineClass(CLASSNAME, "flash.media.Sound");
var abcFile:AbcFile = abcBuilder.build();
var abcSerializer:AbcSerializer = new AbcSerializer();
var abcBytes:ByteArray = abcSerializer.serializeAbcFile(abcFile);
swf.tags.push(TagDoABC.create(abcBytes));
// Add SymbolClass tag
// Binds the sound class definition to the embedded sound
var symbolClass:TagSymbolClass = new TagSymbolClass();
symbolClass.symbols.push(SWFSymbol.create(1, QNAME));
swf.tags.push(symbolClass);
// Add ShowFrame tag
swf.tags.push(new TagShowFrame());
// Add End tag
swf.tags.push(new TagEnd());
// Publish the SWF
var swfData:SWFData = new SWFData();
swf.publish(swfData);
return swfData;
}
}
}
@hems
Copy link

hems commented Jun 3, 2011

incredible...

@garethfoote
Copy link

Hi Claus,
I am glad to see that someone has encountered this exact problem since it is the one that I am facing currently. I am however experiencing a problem when attempting to use this solution. I upload the mp3 and get the following error:

RangeError: Error #1125: The index 0 is out of range 0.
at com.codeazur.as3swf::SWFTimelineContainer/publishTags()[/Users/claus/Projects/as3swf/src/com/codeazur/as3swf/SWFTimelineContainer.as:222]
at com.codeazur.as3swf::SWF/publish()[/Users/claus/Projects/as3swf/src/com/codeazur/as3swf/SWF.as:68]
at MP3FileRefLoader/createSWFFromMP3()[E:\Projects\AudioRecorder\src\MP3FileRefLoader.as:123]
at MP3FileRefLoader/loadBytes()[E:\Projects\AudioRecorder\src\MP3FileRefLoader.as:64]
at Function/()[E:\Projects\AudioRecorder\src\MP3FileRefLoader.as:57]

I am using Flash Builder 4.5, compiling with Flex sdk version 4.1 and running Flash Player 10.3. I am hoping that you might have an idea of where I'm going wrong here.
Many thanks,Gareth

@claus
Copy link
Author

claus commented Sep 9, 2011

Gareth,
you are doing nothing wrong. A recent as3swf update introduced this issue. I committed a bugfix, please pull as3swf.swc from the repo and try again. Thanks for reporting this.
Claus.

@garethfoote
Copy link

Many thanks for the prompt action on this Claus.
I managed to put a little hack around the raw tags issue last night but I'll replace this with your latest swc today.

@rajanverma
Copy link

Hi Claus,

Where can i get the repository link for com.codeazur.as3swf
Thanks,
Rajan

@claus
Copy link
Author

claus commented Nov 23, 2011

@nicoptere
Copy link

hi, thanks for that !
this goes way beyond my understanding of th player but it works :)

I have an issue though: when using your technique, the ID3 tags seem to be discarded.
have I done something wrong or is it a limitation?
is there (simple) a workaround ?

anyway, thank you for this one
this is really brilliant
Nicolas

@claus
Copy link
Author

claus commented May 4, 2012

Nicolas, yeah i'm stripping anything that's not an MPEG frame.
The relevant code is in TagDefineSound.processMP3.

@nicoptere
Copy link

(thanks for your swift answer :) )
I see...
so the the ID3 tags must be located somewhere between 0 and 10 + ((mp3[i + 6] << 21) | (mp3[i + 7] << 14) | (mp3[i + 8] << 7) | mp3[i + 9]); in the ByteArray.
this is really way beyond my understanding ;)

I found an ID3Reader lib here : http://blog.benstucki.net/?p=3 ( metaphile on the SVN is up to date )
combining your scripts with his might do the trick.

again thanks a bunch for this,
cheers,
Nicolas

@claus
Copy link
Author

claus commented May 4, 2012

I should have documented that piece of code, because it's even beyond my understanding today, lol.
You should be able to use the MP3 as is, btw. FP should handle it fine. So you could try and just copy the MP3 bytearray to TagDefineSound.soundData. The main thing processMP3() does (apart from stripping non-frame stuff) is determining the MP3's parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment