-
-
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; | |
} | |
} | |
} |
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
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.
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.
Hi Claus,
Where can i get the repository link for com.codeazur.as3swf
Thanks,
Rajan
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
Nicolas, yeah i'm stripping anything that's not an MPEG frame.
The relevant code is in TagDefineSound.processMP3.
(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
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.
incredible...