Flash for the masses – AS, JSFL, XUL, etc.

2008/12/30

AS3.0 Font Embedding

Filed under: AS3.0 — delfeld @ 9:46 pm
Tags: , ,

IDE font embedding, and using it in AS3.0:
http://www.adobe.com/devnet/flash/quickstart/embedding_fonts/
(This is updated for CS4, so some of the concepts may not work in CS3.)

Offset timer alarm based on UTC or local time

Filed under: AS3.0 — delfeld @ 9:27 pm
Tags: , , , ,

This is from my response to a post on finding UTC time from a local time on ActionScript.org

Simply add the Date object’s getTimezoneOffset() (this is in minutes) to the resulting time offset.

With AS3, it is easy to make this into a class, and inherit that class from a Flash library object’s “linkage”.

The class below is not very robust, since there is only a single alarm per class instance, and no error-checking. However, it does show how to convert to UTC time.

package
{
	import flash.display.MovieClip;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	/**
	 * ...
	 * @author Delfeld, copyright 2008
	 */
	public class alarmTestAS extends MovieClip
	{
		private var alarm:Timer;
		private var endingDate:Date;

		public function alarmTestAS()
		{
			getAlarmDate(0, 0, 0, 2, true);
			setAlarm();
		}

		private function setAlarm():void
		{
			// end time - immediate time = offset time, timer delay, timer interval, etc.
			alarm = new Timer(endingDate.time - (new Date()).time,1);
			alarm.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler, false, 0, true);
			alarm.start();
		}

		private function getAlarmDate(dyOffset:int, hrOffset:int, mnOffset:int, secOffset:int, asUTC:Boolean = false):void
		{
			endingDate = new Date();
			//endingDate.setMinutes(endingDate.minutes + endingDate.timezoneOffset);

			// Change time to an offset of the current UTC time.
			// Note that this will still maintain your current clock's offset in the endingDate object,
			// but the time - delivered via a non-UTC method - will be offset from the UTC time.
			if (asUTC)
			{
				trace(" UTC offset minutes: " + endingDate.timezoneOffset);
				endingDate.setUTCHours(
					endingDate.getUTCHours() + hrOffset,
					endingDate.getUTCMinutes() + mnOffset + endingDate.getTimezoneOffset(),
					endingDate.getUTCSeconds() + secOffset
				);
				endingDate.setUTCDate(
					endingDate.getUTCDate() + dyOffset
				);
			}
			// Change time to an offset of the current local time.
			else
			{
				endingDate.setHours(
					endingDate.getHours() + hrOffset,
					endingDate.getMinutes() + mnOffset, //+ endingDate.getTimezoneOffset()
					endingDate.getSeconds() + secOffset
				);
				endingDate.setDate(
					endingDate.getDate() + dyOffset
				);
			}

			trace(" alarm time: \t" + endingDate.toString());
			trace(" local time: \t" + (new Date()).toString());
			trace(" UTC time: \t\t" + (new Date()).toUTCString());
		}		

		private function timerHandler(e:TimerEvent):void
		{
			alarm.stop();
			e.target.removeEventListener(e.type, timerHandler);
			trace("alarmTestAS.timerHandler: " + alarm.delay + " ms");
		}
	}
}

Extract Sound Bytes from an MP3

Filed under: AS3.0 — delfeld @ 6:13 pm
Tags: , , , , ,

This was a response I made to a post about extracting sound bytes, found on ActionScript.org.

The code listed in the post works for me, though there are some bad coding practices in it.

What I found to be areas of concern:

  • This only works in FlashPlayer 10 and Air 1.0, so certain methods (e.g., sound.extract()) are not found in previous SDK’s.
  • The code is not optimized – that is, it takes a long time to load. A tiny test MP3 I made took over 7 seconds, which implies that there must be a better way to handle this. The code may actually be working, but that may be unknown to the programmer.
  • Put the MP3 is in the same directory as the SWF.
  • This Flash can only be run from a webpage (this is because of the way you are loading the MP3). An error #2032 indicates this (though it means other things, too).
  • The code should provide debugging feedback. I added a TextField to the object that inherits this class, and wrote content to that TextField (instead of using trace()).
  • Extend from MovieClip class instead of Sprite. I had to do this because I was using a Flash library object, and the linkage’s Base Class needed to extend a MovieClip.

    Good coding practices may help clear up difficulties, too.

  • The Sound and URLRequest objects should not be declared at the class level, but rather within methods.
  • The ByteArray is defined as a class variable, but then bashed by a local declaration in the completeHandler() method.
  • Add error checking to the code!

    My revision follows.

    Before using this class:
    You inherit this class within Flash by setting up a linkage to this class from a Flash library object. Further, you will have to add a dynamic TextField called text1 to the object that inherits this class within Flash (it must be a child object of the inheriting library object).
    This example only has one error check added, but you have to do a lot more to make sure the code works as you expect. Look into the try-catch syntax. Further, I made no attempt to optimize the code.

    package
    {
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.IOErrorEvent;
    	import flash.events.ProgressEvent;
    	import flash.display.Graphics;
    	import flash.media.Sound;
    	import flash.net.URLRequest;
    	import flash.utils.ByteArray;
    
    	// Change: from Sprite class
    	public class soundTest extends MovieClip
    	{
    		const WAVE_HEIGHT:int = 200;
    		var snd:Sound;
    
    		// change: removed defs from this area.
    		var req:URLRequest;
    		var buffer:ByteArray;
    
    		public function soundTest():void
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    
    		private function init(e:Event = null):void
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    
    			// entry point
    			// change: moved sound def to here:
    			req = new URLRequest("test.mp3");
    			snd = new Sound();
    
    			snd.addEventListener(ProgressEvent.PROGRESS, progressHandler);
    			snd.addEventListener(Event.COMPLETE, completeHandler);
    			// change: added error checking
    			snd.addEventListener(IOErrorEvent.IO_ERROR, ioerrorHandler, false, 0, true);
    
    			snd.load(req);
    		}
    
    		//change: added this function
    		private function ioerrorHandler(e:IOErrorEvent):void
    		{
    			traceHTML("(caught error) soundTest.init: " + e.type + " :\n.\n" + e.toString());
    		}
    
    		public function completeHandler(e:Event):void {
    
    			traceHTML("soundTest.completeHandler");
    
    			var g:Graphics = this.graphics;
    			g.lineStyle(1, 0x6600CC); 
    
    			// Change: removed: snd.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
    			// Change: added remove Complete handler
    			e.target.removeEventListener(e.type, completeHandler);
    			e.target.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
    
    			// change: removed declaration from here (was not accessing class variable):
    			buffer = new ByteArray();
    			var buffercounter:int = 0;
    
    			var lsample:Number
    			var rsample:Number
    			var lmin:Number;
    			var lmax:Number;
    			var rmin:Number;
    			var rmax:Number;
    
    			//outerloop
    
    			while (snd.extract(buffer, 8192)) {
    				buffer.position = 0;
    				lmin = 0.0;
    				lmax = 0.0;
    				rmin = 0.0;
    				rmax = 0.0;
    				//innerloop
    
    				traceHTML("soundTest.completeHandler: buffer.bytesAvailable:" + buffer.bytesAvailable);
    
    				while (buffer.bytesAvailable) {
    					lsample = buffer.readFloat();
    					rsample = buffer.readFloat();
    
    					traceHTML("soundTest.completeHandler: lsample:" + lsample);
    
    					if (lsample  lmax) lmax = lsample;
    					if (rsample  rmax) rmax = rsample;
    
    					traceHTML("soundTest.completeHandler: lmin:" + lmin	);
    
    					buffer.position += 1024;
    				}
    				//draw the wave
    				g.moveTo(buffercounter, ( -lmax + 1.0) * WAVE_HEIGHT);
    				g.lineTo(buffercounter, ( -lmin + 1.0) * WAVE_HEIGHT);
    				g.moveTo(buffercounter, ( -rmax + 2.0) * WAVE_HEIGHT);
    				g.lineTo(buffercounter, ( -rmin + 2.0) * WAVE_HEIGHT);
    				buffercounter++;
    			}
    			traceHTML("completed");
    		}
    
    		public function progressHandler(event:ProgressEvent):void {
    			//traceHTML("soundTest.progressHandler");
    			traceHTML(Number(event.bytesLoaded / event.bytesTotal * 100).toPrecision(3) + "% loaded.");
    		}
    
    		// change: added this function
    		public function traceHTML(str:String):void
    		{
    			//if (text1)
    			//{
    				text1.appendText(str + "\n");
    			//}
    		}
    	}
    }
    
  • Blog at WordPress.com.