-
Notifications
You must be signed in to change notification settings - Fork 127
Play MP3 directly from ByteArray
In Actionscript 3, there is currently no way to play an MP3 directly off a ByteArray due to the lack of a Sound.loadBytes() method. SWF and image files (JPEG, GIF and PNG) can be loaded and used without further ado by Loader.loadBytes, and raw sound data can be played back via the Sound object’s SampleDataEvent. Things get tricky though when you have an MP3 in a ByteArray that you want to play back. The as3swf library helps to solve this problem.
What needs to be done is the following:
- Create a SWF embedding the MP3 on the heap
- Load that SWF via Loader::loadBytes
- Instantiate the class bound to the sound asset
Obviously, the challenge is to create the SWF with the embedded MP3. We’ll just start by creating a dummy SWF using a dummy MP3 to see how it has to look like, in order to recreate the structure dynamically later.
package
{
import flash.display.Sprite;
public class MP3Wrapper extends Sprite
{
[Embed(source="test.mp3")]
public var soundClass:Class;
}
}
This embeds the MP3 and binds it to a Sound class definition. When we load the resulting SWF into our master SWF, we can instantiate the class and get an instance of a Sound object containing the MP3, which we can play back.
Here’s how a SWF created from the above source looks like. It contains 8 tags as follows:
[69:FileAttributes] AS3: true, HasMetadata: false, UseDirectBlit: false, UseGPU: false, UseNetwork: false
[09:SetBackgroundColor] Color: ffffffff
[86:DefineSceneAndFrameLabelData]
Scenes:
[0] Offset: 0, Name: Scene 1
[14:DefineSound] SoundID: 1, Format: 2, Rate: 44kHz, Size: 16bit, Type: stereo, Samples: 6867072
[82:DoABC] Lazy: true, Length: 767
[76:SymbolClass]
Symbols:
[0] TagID: 1, Name: MP3Wrapper_soundClass
[1] TagID: 0, Name: MP3Wrapper
[01:ShowFrame]
[00:End]
-
DefineSound
contains the embedded MP3. The dummy MP3 we used was a 44kHz, 16bit, stereo MP3, containing a total of 6867072 sound samples. It is an asset in the SWF’s internal library which is identified by ID 1. -
DoABC
contains all Actionscript bytecode, here the document class and the Sound class definition. -
SymbolClass
binds Actionscript classes to library assets, in our case the document classMP3Wrapper
, and most importantly the class definitionMP3Wrapper_soundClass
which is bound to the library asset with ID 1 (which happens to be our embedded sound).
We’ll just reuse all tags above including DoABC
and SymbolClass
as is, leaving us with the DefineSound
tag that we have to create dynamically.
DefineSound
contains the raw sound data (here MP3), along with some flags that tell the Flash Player about some characteristics of that data, such as the number of samples, the sampling rate, the size of the samples, whether it’s mono or stereo, and the library ID (which is always 1 as we only have one library asset).
The TagDefineSound class features a very convenient factory method to create itself from an MP3, called createWithMP3. This method scans the MP3 to automatically determine the number of samples contained in the MP3, as well as the sampling rate etc. It strips ID3 metadata and embeds the raw MP3.
var defineSound:TagDefineSound = TagDefineSound.createWithMP3(1, mp3);
Here is the source code to create a SWF with an embedded MP3 at runtime, and play that MP3: