Calendar

July 2017
Mo Tu We Th Fr Sa Su
<< >>
12
3456789
10111213141516
17181920212223
24252627282930
31

Langs

Playing with Sfxr

Posted on Jan 22 2010

In case you don't know about it, Sfxris a very nice library used to general sound effects, perfectly suitable for independent game developers :)

Sfxr was then ported to AS3, which was itself ported to Haxe

I wanted to use it for one of my projects, but I was not very happy with the way it worked for Flash9 : you had to load a SWF (containing a sound and generated in-memory) each time you wanted to play a sound.

So I modified a bit the code in order to create a SWF that contains a Sfx class extending which is binded to the sound data. This way you can now :

  • build a SWF from wave bytes
  • load it using Loader.loadBytes into a new empty ApplicationDomain
  • retrieve the Sfx class
  • create a flash.media.Sound instance
  • cache it for further usage

The code uses some static data to define the AS3 class. I could have done it manually by using the Haxe Format Library which have full SWF+ABC support but I didn't want to add one more dependencies so did something more simple instead.

Here's the source code for that, you can plugin it into Sfxr Haxe port :

static var AS3_DATA = "s238:EAAuAAAAAAgAA1NmeAtmbGFzaC5tZWRpYQVTb3VuZAZPYmplY3QMZmxhc2guZXZlbnRzD0V2ZW50RGlzcGF0Y2hlcgUWARYDGAIWBgAFBwECBwIEBwEFBwQHAwAAAAAAAAAAAAAAAAABAQIIAwABAAAAAQIBAQQBAAMAAQEFBgPQMEcAAAEBAQYHBtAw0EkARwAAAgIBAQUX0DBlAGADMGAEMGACMGACWAAdHR1oAUcAAA";
static var AS3_BYTES : haxe.io.Bytes = null;

public function buildSWFSound() {
    var rate = switch( wav_freq ) {
        case 5500: 0;
        case 11000: 1;
        case 22000: 2;
        case 44100: 3;
        default: throw "Unsupported freq "+wav_freq;
    };
    var is16Bits = switch( wav_bits ) {
        case 8: false;
        case 16: true;
        default: throw "Unsupported bits "+wav_bits;
    };
    var stereo = stereo_pan != 0.0;
    var wave = haxe.io.Bytes.ofData(baWave);

    var swf = new haxe.io.BytesOutput();
    swf.writeString("FWS");
    swf.writeByte(0x09);  // version
    var o = new haxe.io.BytesOutput();
    for( b in [0x78,0x00,0x05,0x5F,0x00,0x00,0x0F,0xA0,0x00,0x00,0x0C] ) // header
        o.writeByte(b);
    o.writeUInt16(1);  // #frames

    // Sandbox
    o.writeUInt16((69 << 6) | 4);
    o.writeUInt30(8);

    // AS3
    if( AS3_BYTES == null )
        AS3_BYTES =  haxe.Unserializer.run(AS3_DATA);
    o.writeUInt16((72 << 6) | 63);
    o.writeUInt30(AS3_BYTES.length);
    o.write(AS3_BYTES);

    // DefineSound tag
    o.writeUInt16((14 << 6) | 63);
    o.writeUInt30(2 + 1 + 4 + wave.length);
    o.writeUInt16(1);  // sound (character) ID
    o.writeByte((3 << 4) | (rate << 2) | ((is16Bits?1:0) << 1) | (stereo?1:0));
    o.writeUInt30(wave.length >> ((is16Bits?1:0) + (stereo?1:0))); // samples
    o.write(wave);  // data

    // SymbolClass
    var cname = "Sfx";
    o.writeUInt16((76 << 6) | (2 + 2 + cname.length + 1));
    o.writeUInt16(1); // 1 class
    o.writeUInt16(1); // sound ID
    o.writeString(cname);
    o.writeByte(0);

    // ShowFrame
    o.writeUInt16((1 << 6) | 0);

    // end tag
    o.writeUInt16(0);

    // finalize
    var swfbytes = o.getBytes();
    swf.writeUInt30( swfbytes.length + 8 ); // filesize
    swf.write(swfbytes);
    return swf.getBytes();
}

#if flash9
static var cache = new Hash<flash.media.Sound>();
static var pendingLoaders = new List();
public static function play( settings : String, ?delay : Float = 0 ) {
    var sound = cache.get(settings);
    if( sound != null ) {
        sound.play(delay);
        return;
    }
    var s = new Sfxr();
    s.setSettingsString(settings);
    s.generate();
    var timer = haxe.Timer.stamp();
    var l = new flash.display.Loader();
    pendingLoaders.add(l);
    var domain = new flash.system.ApplicationDomain();
    l.contentLoaderInfo.addEventListener(flash.events.Event.INIT,function(_) {
        pendingLoaders.remove(l);
        var cl : Class<flash.media.Sound> = domain.getDefinition("Sfx");
        cache.set(settings,Type.createInstance(cl,[]));
        delay -= haxe.Timer.stamp() - timer;
        if( delay < 0 ) delay = 0;
        play(settings,delay);
    });
    l.loadBytes(s.buildSWFSound().getData(),new flash.system.LoaderContext(null,domain));
}
#end

0 comment
Name : Email : Website : Message :