Playing with Sfxr
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.loadBytesinto a new emptyApplicationDomain - retrieve the
Sfxclass - create a
flash.media.Soundinstance - 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 Comments
-
(you)Mar 11, 2010 at 12:49
