<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>joeberkovitz.com &#187; Programming</title>
	<atom:link href="http://joeberkovitz.com/blog/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://joeberkovitz.com/blog</link>
	<description>Just another WordPress weblog</description>
	<pubDate>Tue, 30 Dec 2008 15:57:34 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>Live (or not so live) on The Flex Show</title>
		<link>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/</link>
		<comments>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 01:48:35 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Music]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=127</guid>
		<description><![CDATA[Starting today, you can catch me on episode 63 of The Flex Show, in which the effervescent John Wilker and Jeffry Houser interview yours truly about Noteflight, Flex, and I forget what else &#8212; it was taped a few weeks ago, which feels more like several years given the wealth of activity that was packed [...]]]></description>
			<content:encoded><![CDATA[<p>Starting today, you can catch me on <a href="http://www.theflexshow.com/blog/index.cfm/2008/12/17/Flex-Show-Episode-63-Interview-with-Joe-Berkovitz-of-Noteflightcom">episode 63 of The Flex Show</a>, in which the effervescent John Wilker and Jeffry Houser interview yours truly about Noteflight, Flex, and I forget what else &#8212; it was taped a few weeks ago, which feels more like several years given the wealth of activity that was packed into it.  I think I might take a listen right now, to find out the exact manner in which I embarrassed myself.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/12/19/live-or-not-so-live-on-the-flex-show/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Flash &#8220;Clipboard&#8221; using Local Shared Objects</title>
		<link>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/</link>
		<comments>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 17:48:57 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=117</guid>
		<description><![CDATA[I spent a good part of yesterday implementing a new global clipboard feature for Noteflight using local shared objects or LSOs.  These cookie-like constructs are often used to persist application-specific data across multiple sessions, so that when you close an application down and then restart it later, it resumes in the same state you left [...]]]></description>
			<content:encoded><![CDATA[<p>I spent a good part of yesterday implementing a new global clipboard feature for Noteflight using <a href="http://www.adobe.com/products/flashplayer/articles/lso/">local shared objects</a> or LSOs.  These cookie-like constructs are often used to persist application-specific data across multiple sessions, so that when you close an application down and then restart it later, it resumes in the same state you left it.  What I haven&#8217;t seen much of (and haven&#8217;t done before myself) is use LSOs to communicate data between completely different instances of the same application running <em>at the same time</em>.  It does work, and seems to work well.</p>
<p>Noteflight is a Flash-based music notation editor, and one of the most often-requested features has been the ability to cut, copy and paste between different documents.  These &#8220;clipboard&#8221; operations already worked within a single session editing a single document.  However, the clipboard contents did not survive across edits to a series of documents,  nor could they transfer between different documents open in different windows.  In effect, each copy of the application had its own private copy of the clipboard, initialized to emptiness.  Not surprisingly, users don&#8217;t like these limitations.</p>
<p>It seemed clear that LSOs would be a good vehicle for this enhancement.  We would write the clipboard to an LSO on every cut or copy, and read it out of the same LSO before every paste.  This would not be exactly like a real native system clipboard (since it would be separate from the system clip that contains text, images, etc.) but for the purposes of Noteflight it would seem a lot like one.  The challenges we expected to solve (and did) were as follows:  serialization, keeping LSOs small, handling LSO failure gracefully, and application version skew.  There were of course a couple of major surprises, too!</p>
<p><strong>Serialization</strong>.  All LSOs are stored in files, and must serialize their data.  They do so using the <a href="http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf">AMF3</a> protocol. ActionScript 3 defines how one can manage the serialization of arbitrary Objects using the [RemoteClass] and [Transient] metadata tags (be sure to look those up if you are thinking of serializing objects in a Flex application).  I&#8217;ve used them before, but the special problem here was that the clipboard data structures had already been designed and were quite complex, with a number of potential references to objects sitting &#8220;out in the application&#8221;.  Serializing any of those would result in lots of irrelevant data getting &#8220;dragged in&#8221; to the LSO and bloating it, so they&#8217;d have to be marked as transient.  It would be also necessary to make sure that each and every class requiring a [RemoteClass] tag received it.  Getting all this right in a short amount of time seemed unlikely.</p>
<p>Fortunately I had plenty of existing code to serialize the objects in the clipboard to XML and back, since Noteflight persists musical scores as XML.  So I used Flash&#8217;s handy <tt>IExternalizable</tt> interface to take advantage of this.  This is a great technique that allows you to decide how your objects will be serialized.  Basically, what I did was kind of like this:</p>
<pre>[RemoteClass]
public class AppClipboard implements IExternalizable
{
  private var _data:AppData;  // contents of the clipboard...

  public function writeExternal(output:IDataOutput):void
  {
    output.writeObject(XmlWriter.toXML(_data).toXMLString());
  }

  public function readExternal(input:IDataInput):void
  {
    _data = XMLReader.fromXml(new XML(input.readObject()))
  }
}</pre>
<p>(Note the [RemoteClass] tag &#8212; you still need it even if you use IExternalizable, or Flash won&#8217;t reconsititute the class of your object when you read it back in again.)</p>
<p>With this code written,  when you setting one of your shared object&#8217;s <tt>data</tt> properties to an AppClipboard, like this:</p>
<pre>  mySO.data.contents = myAppClipboard;</pre>
<p>then the writeExternal() method is implicitly used to serialize that object.  Same deal goes when reading the shared object back in: readExternal() gets used.</p>
<p>Next challenge:</p>
<p><strong>Keeping the data size low.</strong> since there is a default 100K limit on LSO storage.  XML has its disadvantages, and verbosity is certainly one of them.  I needed to compress my serialized objects somehow.  I found a nice way to do that, which works for any serializable objects at all (whether you use IExternalizable or not).  Here&#8217;s the &#8220;write side&#8221; of the technique:</p>
<pre>
  var so:SharedObject = getClipboardSO();
  var bytes:ByteArray = new ByteArray();
  bytes.writeObject(_clipboard);   // write our object to a ByteArray
  bytes.compress();    // compress the ByteArray
  so.data.contents = bytes;   // and write the ByteArray instead
  so.data.version = NotationXmlReader.CURRENT_VERSION;
  so.data.creationTime = _clipboardCreationTime;
  so.flush();
</pre>
<p>The &#8220;read side&#8221; works similarly:</p>
<pre>
  var so:SharedObject = getClipboardSO();
  if (so != null
      &#038;&#038; so.data.version == CURRENT_VERSION
      &#038;&#038; (_clipboard == null
          || _clipboardCreationTime < so.data.creationTime))
  {
      var bytes:ByteArray = so.data.contents as ByteArray;
      bytes.uncompress();
      _clipboard = bytes.readObject() as AppClipboard;
      _clipboardCreationTime = new Date().getTime();

      // Flush the object after reading it so it doesn't get cached!
      so.flush();
  }
</pre>
<p>Here you can see the <strong>version skew</strong> detection, as well as a guard against using a &#8220;stale&#8221; shared clipboard that is actually older than the local version.  That can happen if the &#8220;write side&#8221; fails to save an LSO due to size limitations, in which case we have to <strong>degrade gracefully</strong> and use the local clipboard instead of the stale shared one.   This means that a single instance will still behave consistently even if it fails to transfer data to other instances.</p>
<p>Surprise #2: note the call to <tt>so.flush()</tt> on the read side.  I did not expect to have to flush() a SharedObject after <em>reading</em> it.  However, before putting this flush in, I found that the player would cache the SharedObject and refuse to check to see if it had been updated when reloading it by calling <tt>SharedObject.getLocal()</tt>.  This caused clipboard-style transfer of data between different application windows to fail sporadically.  It took a long time to figure this one out.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/12/12/clipboard-using-local-shared-objects/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Minimal Apache/Rails configuration on small virtual server</title>
		<link>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 15:31:55 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=114</guid>
		<description><![CDATA[As I&#8217;ve mentioned before I&#8217;m running a couple of WordPress blogs and a Rails application on Slicehost, using the smallest slice size of 256 MB RAM.  Apart from Rails, this is a typical LAMP setup with Ubuntu Hardy Heron, Apache2-prefork, MySQL 5.x, PHP5.  It took a little while for me to find a [...]]]></description>
			<content:encoded><![CDATA[<p>As I&#8217;ve mentioned before I&#8217;m running a couple of WordPress blogs and a Rails application on <a href="http://www.slicehost.com">Slicehost</a>, using the smallest slice size of 256 MB RAM.  Apart from Rails, this is a typical LAMP setup with Ubuntu Hardy Heron, Apache2-prefork, MySQL 5.x, PHP5.  It took a little while for me to find a robust Apache and Rails configuration, though.  The out of the box Apache2 config would periodically eat up all the swap space and die.  So my hope here is to save others some newbie-sysadmin headaches.</p>
<p><strong>Apache2.</strong>  Apache2 prefork is configured to keep a certain number of processes running to respond to HTTP requests that come in.  These processes are reused across a number of requests and thus tend to grow over time in their memory consumption to reach the largest amount of RAM demanded by any page served.  When using mod_php, the RAM consumption is related to PHP application resources, in this case WordPress.  I found that my Apache processes generally were in the 20m range for resident memory size (the RSS column in the &#8216;top&#8217; display).  With the out-of-box Apache2 configuration allowing as many as 15-20 processes, that meant that any large batch of concurrent requests (such as those originating from a search bot) would totally nail my machine.  So the most important change I wound up making was to reduce the number of processes:</p>
<pre>
&lt;IfModule mpm_prefork_module&gt;
    StartServers          3
    MinSpareServers       3
    MaxSpareServers       3
    ServerLimit          10
    MaxClients           10
    MaxRequestsPerChild   1000
&lt;/IfModule&gt;
</pre>
<p>This generally causes me to see around 5-6 processes running, with the possibility of as many as 10.</p>
<p>A number of folks have suggested I run nginx or lighttpd, which I&#8217;m sure would be a great idea, but I was strapped for time and in a mood to stick with things that have lots of online recipes and that I already somewhat understood.</p>
<p><strong>Rails</strong>.  Various approaches are available here as well. At first I was running the mod_passenger module, but I found this gave me a few 30m processes as opposed to the single 50m process I could get by running a single mongrel.  So now I&#8217;m running a single mongrel and it&#8217;s working fine.</p>
<p><strong>MySQL</strong>.  Haven&#8217;t tuned this much yet, but I&#8217;m not seeing any problems.</p>
<p><strong>WordPress</strong>.  Caching is enabled on the advice of a number of people that this will decrease MySQL resource consumption.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/23/minimal-apache-rails-on-small-virtual-server/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Flexcover 0.81 is out</title>
		<link>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/#comments</comments>
		<pubDate>Tue, 18 Nov 2008 15:12:22 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=112</guid>
		<description><![CDATA[A quick update: Alex Uhlmann and I have just released the latest Flexcover edition on our Google Code Project.  This release supports the newly announced Flex 3.2 SDK, Flex Builder 3.0.2 and AIR 1.5.
]]></description>
			<content:encoded><![CDATA[<p>A quick update: <a href="http://weblogs.macromedia.com/auhlmann/">Alex Uhlmann</a> and I have just released the latest Flexcover edition on our <a href="http://code.google.com/p/flexcover/">Google Code Project</a>.  This release supports the newly announced Flex 3.2 SDK, Flex Builder 3.0.2 and AIR 1.5.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/18/flexcover-081-is-out/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Vote for sampled audio to not crash IE7</title>
		<link>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 11:55:27 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=109</guid>
		<description><![CDATA[Turns out there&#8217;s a nasty bug in sampled audio playback in the newly released Flash 10 player.  Found by Tyler Wright of Legato Media, this bug takes down your entire IE7 browser if you open simultaneous windows with Flash content, one of which is playing back audio using the new SampleDataEvent API.  This [...]]]></description>
			<content:encoded><![CDATA[<p>Turns out there&#8217;s a nasty bug in sampled audio playback in the newly released Flash 10 player.  Found by Tyler Wright of Legato Media, this bug takes down your entire IE7 browser if you open simultaneous windows with Flash content, one of which is playing back audio using the new <tt>SampleDataEvent</tt> API.  This is a crippling problem for any ambitious Flash content on the web incorporating dynamic audio.</p>
<p>Fortunately, we now have the prospect of an American President who can speak in intelligible sentences&#8230;  which means that you can turn all of your positive energy to getting Adobe to fix this bug.  Please vote on it at:</p>
<p><a href="https://bugs.adobe.com/jira/browse/FP-985">https://bugs.adobe.com/jira/browse/FP-985</a></p>
<p>Future generations thank you!  (Future generations of what, you may ask?)</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/17/vote-for-sampled-audio-to-not-crash-ie7/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Flexcover upgrade for Flex 3.2.0 SDK is looking good</title>
		<link>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/</link>
		<comments>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 02:29:56 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://joeberkovitz.com/blog/?p=106</guid>
		<description><![CDATA[Alex and I &#8212; lately, to be honest, it&#8217;s mostly Alex &#8212; have been working on the forthcoming upgrade release of Flexcover, the code coverage instrumentation tool for Flex/AS3.  I&#8217;m feeling pleased because I finally merged up the modifications to the Flex SDK compiler to the 3.2.0 branch, in preparation for an expected release [...]]]></description>
			<content:encoded><![CDATA[<p>Alex and I &#8212; lately, to be honest, it&#8217;s mostly Alex &#8212; have been working on the forthcoming upgrade release of <a href="http://code.google.com/p/flexcover/">Flexcover</a>, the code coverage instrumentation tool for Flex/AS3.  I&#8217;m feeling pleased because I finally merged up the modifications to the Flex SDK compiler to the 3.2.0 branch, in preparation for an expected release of a new Flex Builder in the MAX timeframe.</p>
<p>The merge went smoothly and the 3.2.0 compiler seems to work like a champ &#8212; well, at least, it does everything that the 3.0.x version did.  What&#8217;s more, a sneak peek at Flex Builder 3.2 revealed that they&#8217;ve fixed an irksome bug in the Flex Compiler project options dialog, and it&#8217;s now possible to enable and disable coverage instrumentation using the compiler options field.</p>
<p>That&#8217;s just the part I did.  Alex has been busy working on some very nice changes to the CoverageViewer, which should greatly reduce the performance problems people were seeing during data collection before.  We&#8217;ve also made it much easier to merge reports from multiple test runs.  A few more fixes are needed but things are looking up&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/11/11/flexcover-upgrade-for-flex-320/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Strongly Typed Proxies in AS3</title>
		<link>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/</link>
		<comments>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 12:00:43 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/</guid>
		<description><![CDATA[Something I&#8217;ve often wanted in AS3 is a strongly typed proxy: an object that implements a known interface with typed methods, but where every method results in the invocation of some method like invokeMethod(methodName:String, args:Array).  AS3 does have a Proxy class, but unlike Java&#8217;s class of the same name, an AS3 Proxy doesn&#8217;t implement [...]]]></description>
			<content:encoded><![CDATA[<p>Something I&#8217;ve often wanted in AS3 is a <em>strongly typed proxy</em>: an object that implements a known interface with typed methods, but where every method results in the invocation of some method like <code>invokeMethod(methodName:String, args:Array)</code>.  AS3 does have a <code>Proxy</code> class, but unlike Java&#8217;s class of the same name, an AS3 <code>Proxy</code> doesn&#8217;t implement any particular interface.  One can extend Proxy into a subclass that has an interface, but by that time the Proxy superclass isn&#8217;t delivering any real value.  The AS3 <code>Proxy</code>  has been designed for loose, dynamic typing &#8212; which after all is one of the strengths of the ActionScript/ECMAScript languages.</p>
<p>Why use a strongly typed proxy?  A common use of such a proxy is to create a &#8220;smart wrapper&#8221; around some underlying object with a known interface that looks and acts (and code-hints) exactly like the underlying thingamabob, but does some other stuff around every method call or property access.  You might want a smart wrapper that logs or records all the function calls (as well as executing them).  You might want a wrapper that does a try/catch around every call.  You might want a wrapper that serializes the call over a stream to some remote destination.</p>
<p>(If this sounds like what some call &#8220;aspect-oriented programming&#8221;, well, it is similar to one aspect of aspect oriented programming :-)</p>
<p>Anyway, we can&#8217;t use AS3&#8217;s Proxy to solve this problem, so what to do?  We&#8217;ll start with a simple approach, but make it more general.  If our interface looked like this:</p>
<pre>
public interface ISmashable
{
    function smash(force:Number):String;
}</pre>
<p>and we wanted to create a smart wrapper that logged all function calls around any ISmashable implementation, we might create something like this:</p>
<pre>
public class SmashableLoggingProxy implements ISmashable
{
    private var _smashable:ISmashable;
    public function SmashableProxy(smashable:ISmashable)
    {
        _smashable = smashable;
    }

    public function smash(force:Number):String
    {
        trace("smash():", force);
        var result:String = _smashable.smash(force);
        trace("    result:",result);
        return result;
    }
}</pre>
<p>Then, if we did something like <code>var proxy:ISmashable = new SmashableProxy(realSmashable);</code> we could treat the resulting <code>proxy</code> as an ISmashable everywhere in our application,  Every time we called, say <code>smash(5)</code> method on <code>proxy</code>, not only would <code>realSmashable.smash(5)</code> be called but we&#8217;d see some nice trace output as well.<br />
If you have the time to create a lot of wrapper methods like this (or write a fancy code generator to save the trouble), that&#8217;s fine.  Another way to go, however would be to create a &#8220;generic&#8221; smart wrapper base class: <span id="more-92"></span></p>
<pre>
public class SmartProxy
{
    private var _obj:Object;
    private var _functionNames:Dictionary;

    public function SmartProxy(obj:Object)
    {
        _obj = obj;

        // set up Dictionary that goes from functions in this wrapper to function names
        _functionNames = new Dictionary();
        var typeInfo:XML = describeType(this);   // returns metadata for subclass interface
        for each (var functionInfo:XML in typeInfo.method)
        {
            var name:String = functionInfo.@name;
            _functionNames[this[name]] = name;
        }
    }

    protected function handleInvocation(args:Object):*
    {
        // 'callee' is a special AS3-defined property of an 'arguments' object
        // that provides the Function which was called
        var functionName:String = _functionNames[args.callee];
        return applyFunction(functionName, args);
    }

    protected function applyFunction(functionName:String, args:Object):*
    {
        // This looks up the name of the function that was called, uses it to
        // obtain the Function in the underlying object as a property, and calls it.
        return (_obj[functionName] as Function).apply(_smashable, args);
    }
}</pre>
<p>Now extend this to implement our interface:</p>
<pre>
public class SmashableProxy extends SmartProxy implements ISmashable
{
    public function SmashableProxy(smashable:ISmashable)
    {
        super(smashable);  // sounds like a Nintendo game, eh?
    }
    public function smash(force:Number):String
    {
        return handleInvocation(arguments);  // arguments is a special AS3 language keyword!
    }

    // (if our interface had other functions, they would all have the same body!)
}</pre>
<p>The above SmashableProxy acts exactly like the underlying object.  What&#8217;s the point?  Well, given a base class of this kind, one can create smart wrappers of any variety with very little additional effort:</p>
<pre>
public class SmashableLoggingProxy extends SmashableProxy
{
    public function SmashableProxy(smashable:ISmashable)
    {
        super(smashable);
    }

    override protected function applyFunction(functionName:String, args:Object):*
    {
        trace(functionName, "():", args);
        var result:String = super.applyFunction(functionName, args);
        trace("result:",result);
        return result;
    }
}</pre>
<p>The astute reader may notice that logging is generic, and wonder if it should be handled in the SmartProxy, not in this subclass.  So a further extension of this idea might  introduce a separate <em>invocation handler</em> that can supply generic handling for all method invocations,  and is a property of the SmartProxy.  Java in fact has exactly such a class for its Proxies.</p>
<p>In another post soon, I&#8217;ll describe how this fits into the testing strategy for Noteflight, which has a large automated test suite of recorded UI actions.  We use this suite to validate the program before every checkin &#8212; it is a very complex editor, and it&#8217;s all too easy to fix one thing and break another, so the test suite makes sure we don&#8217;t do that!</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/10/30/strongly-typed-proxies-in-as3/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Controlling Audio Latency in Flash 10</title>
		<link>http://joeberkovitz.com/blog/2008/10/15/controlling-audio-latency-in-flash-10/</link>
		<comments>http://joeberkovitz.com/blog/2008/10/15/controlling-audio-latency-in-flash-10/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 20:04:47 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Music]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.joeberkovitz.com/blog/2008/10/15/controlling-audio-latency-in-flash-10/</guid>
		<description><![CDATA[Adobe threw a slight curve ball with the long-awaited release of Flash Player 10 today.  The release itself wasn&#8217;t the curve ball (although not everyone expected it to happen on thisdate).  The surprise was the audio latency using the new dynamic sound generation APIs.
Audio latency, for programs that synthesize sound on the fly, is roughly [...]]]></description>
			<content:encoded><![CDATA[<p>Adobe threw a slight curve ball with the long-awaited release of Flash Player 10 today.  The release itself wasn&#8217;t the curve ball (although not everyone expected it to happen on thisdate).  The surprise was the audio latency using the new dynamic sound generation APIs.</p>
<p>Audio latency, for programs that synthesize sound on the fly, is roughly defined as the amount of time between the program creating a sound and the computer&#8217;s audio output actually playing that same sound.  Latency is important because it affects the user experience.  If a user hits a &#8220;play&#8221; button and waits 1 second before hearing anything, that can be annoying.  If a user types a note into a music notation editor and has to wait 1 second before hearing anything, that&#8217;s downright maddening.</p>
<p>Latency isn&#8217;t all bad, though.  The higher the latency, the more &#8220;give&#8221; the sound output pipeline has, and the more resistant it is to disruption by other processes running in your browser and on your computer.  Ideally you want to strike a balance between latency and robustness in your sound output.</p>
<p>In Noteflight, the latency on Mac OS X had been at a comfortable 30 milliseconds &#8212; about a 30th of a second &#8212; using the Flash 10 beta.  But in the released production version, Noteflight&#8217;s audio latency suddenly jumped to about 850 milliseconds.  Other folks with audio synthesis apps reported other numbers, all of them different.  Whoa!  What happened?  (Before going further, let me say that our latency is now back at 250 milliseconds, so things aren&#8217;t as bad as they first seemed.)</p>
<p>Adobe introduced a new behavior into the released player, where the latency depends on the number of samples you provide to SampleDataEvent.  If you provide 2048 samples per callback, your latency will be the minimum available on the platform (30 ms on Mac, ~250 on Windows).  If you provide 8192 samples per callback, on the other hand, your latency will be in the neighborhood 1000 milliseconds.  The amount of latency for in-between sample block sizes is a complex function of this number.  Tinic Uro will hopefully publish more information about that function, which apparently involves a power-law nonlinear function of the block size combined with the native sound driver buffer size, but experimentally I have seen these numbers on Mac OS X:</p>
<p>block size      latency (ms)<br />
2048            30<br />
3072            170<br />
4096            250<br />
8192            850</p>
<p>This is good stuff to know, and it&#8217;s something of a surprise to us all.  I notched the sample size in Noteflight back down to 4096 in a hurry, and latency is acceptable once again.  Or, semi-acceptable.  I&#8217;d like to get it even lower, but I don&#8217;t want to do that in too much of a hurry without adequate testing and tuning of the synthesis pipeline.</p>
<p>[<strong>Important footnote (10/16/08)</strong>:  You might think that by adjusting the sample block size dynamically, you can change the latency on the fly for a single Sound object that is streaming samples.  The answer is... sort of, but not in a useful way.  You can make the latency increase by making the sample block size larger, but if you make it smaller again, the latency will not go back down: it will stay at the higher value.  What is reported to work, but I haven't tried it yet, is to output sound using more than one Sound object, each with its own block size (and hence its own latency value).  The usefulness of that approach is also not clear.]</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/10/15/controlling-audio-latency-in-flash-10/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Noteflight: An Online Music Notation Editor</title>
		<link>http://joeberkovitz.com/blog/2008/10/06/introducing-noteflight/</link>
		<comments>http://joeberkovitz.com/blog/2008/10/06/introducing-noteflight/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 13:46:39 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Music]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.joeberkovitz.com/blog/2008/10/06/introducing-noteflight/</guid>
		<description><![CDATA[It&#8217;s my great pleasure to make an introduction: Noteflight, please say hello to the world.  World, there&#8217;s something I&#8217;d like you to meet: Noteflight.  I&#8217;m really pleased to be able to finally write this, because it&#8217;s been a long journey to get to this point!
Noteflight is a new kind of tool for musicians, [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s my great pleasure to make an introduction: Noteflight, please say hello to the world.  World, there&#8217;s something I&#8217;d like you to meet: <a href="http://www.noteflight.com">Noteflight</a>.  I&#8217;m really pleased to be able to finally write this, because it&#8217;s been a long journey to get to this point!</p>
<p>Noteflight is a new kind of tool for musicians, composers and educators: an online music notation editor. With Noteflight, anyone can create, share and publish musical scores using nothing more than a web browser.  This ease of editing, sharing and publishing are what make Noteflight so different from other notation editors: music notation can finally be used on the Web in as natural and flexible a way as text, images or videos.</p>
<p>Here&#8217;s an example of a score that was created in Noteflight, shared, and embedded in this post:</p>
<p><object height="316" width="440"><param name="movie" value="http://www.noteflight.com/scores/embed"></param><param name="FlashVars" value="id=ca3a1593ed6236c9bb56971b89d80f23a105f5c4&amp;scale=1"></param><embed src="http://www.noteflight.com/scores/embed" type="application/x-shockwave-flash" flashvars="id=ca3a1593ed6236c9bb56971b89d80f23a105f5c4&amp;scale=1" height="316" width="440"></embed></object></p>
<p>This isn&#8217;t just a picture of music, but an interactive music display; for example, you can select and listen to individual notes and measures.  Click the logo to see the full-page score, which can be printed.  To get a sense of how the score above was created using the Noteflight score editor, please watch this video:</p>
<p><object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/S1BrFc1Qjog&amp;hl=en&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/S1BrFc1Qjog&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" height="344" width="425"></embed></object></p>
<p>Scores are saved on the Noteflight server, so you and anyone you share them with can access them from anywhere on the Web.  The music can be heard as well as seen: Noteflight has its own integrated audio playback, that sounds consistent on every computer.  And Noteflight keeps track of all the past versions of your scores, so you can always go back and see where you&#8217;ve been.</p>
<p>The Noteflight beta is free and we&#8217;re accepting signups.  As with all beta software, Noteflight is constantly being improved and extended; this blog is the best place to find out what&#8217;s happening (and what&#8217;s going to happen next) with Noteflight.   Besides filling out the score editing features of Noteflight, we are planning additional services and capabilities for sharing music and organizing content.</p>
<p>There will be more posts coming up here about the development and internals of Noteflight &#8212; I&#8217;ve had to wait on many of those because the product wasn&#8217;t officially launched yet!  A few quick techie observations:</p>
<ul>
<li>The Noteflight score editor was built with Adobe Flex 3.0.1 and Flash CS3</li>
<li>The Noteflight server side was built with Ruby on Rails 2, Apache and MySQL and is hosted on Amazon EC2 and S3.</li>
<li>The Moccasin open-source editing framework (see previous post) is a distillation of many of the music-independent aspects of the Noteflight score editor.</li>
<li>The StandingWave audio library, previously discussed here (but not yet open-source), is used by the music synthesizer internal to Noteflight.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/10/06/introducing-noteflight/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Moccasin: a Flex framework for graphical editing apps</title>
		<link>http://joeberkovitz.com/blog/2008/09/30/moccasin-intro/</link>
		<comments>http://joeberkovitz.com/blog/2008/09/30/moccasin-intro/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 01:41:46 +0000</pubDate>
		<dc:creator>joe</dc:creator>
		
		<category><![CDATA[Flex]]></category>

		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.joeberkovitz.com/blog/2008/09/30/moccasin-intro/</guid>
		<description><![CDATA[Lately I&#8217;ve been working on a set of projects (both my own and others) that are built on top of Moccasin, a new open source AS3 framework that I&#8217;ve developed for building graphical editors.  Moccasin was distilled and refactored out of the first project that used these ideas so that I could use it [...]]]></description>
			<content:encoded><![CDATA[<p>Lately I&#8217;ve been working on a set of projects (both my own and others) that are built on top of <a href="http://code.google.com/p/moccasin/">Moccasin</a>, a new open source AS3 framework that I&#8217;ve developed for building graphical editors.  Moccasin was distilled and refactored out of the first project that used these ideas so that I could use it elsewhere without IP issues, and it lives on Google Code.  Moccasin still has a long way to go in terms of overview documentation and I have to ask a certain amount of forgiveness on that subject.  I&#8217;m perhaps releasing it a bit prematurely, but I regard it as pretty useful in a practical sense since I&#8217;m now working on the third substantial application built on top of it.  This post is an attempt to bite off a little bit of that overview problem and endow Moccasin with a little more value to other people.</p>
<p>If the current lack of great overview docs is the bad news, well, the good news about Moccasin is that it&#8217;s got a complete sample editor application called Simpleworld as part of the distribution, with both AIR and Flex versions.  Both the Moccasin framework and the sample application source code are pretty well commented, also.  Here&#8217;s the Simpleworld application itself, to give a concrete sense of what Moccasin&#8217;s all about &#8212; it&#8217;s an editor for documents that consist of a bunch of squares of different sizes (I don&#8217;t call this world &#8220;simple&#8221; for nothin&#8217;):</p>
<p><object height="480" width="540"><param name="movie" value="/projects/moccasin-demo/simpleworld.swf"></param><param name="FlashVars" value="hostPrefix=/projects/moccasin-demo/"></param><embed src="/projects/moccasin-demo/simpleworld.swf" type="application/x-shockwave-flash" flashvars="hostPrefix=/projects/moccasin-demo/" height="480" width="540"></embed></object></p>
<p>Here are some of the things you can do, which show off what Moccasin&#8217;s about&#8230;<span id="more-89"></span></p>
<ul>
<li>load and save XML documents on the server.  View the one that&#8217;s loaded by the above example <a href="/projects/moccasin-demo/document1.xml">here</a>.</li>
<li>Click any square to select it singly, Ctrl/Command-click squares to make discontinuous selections</li>
<li>Click on the background to add a new square to the world</li>
<li>Drag any selected square to move all selected squares together</li>
<li>Drag the mouse across the background to select all squares intersecting that rectangle</li>
<li>Delete, Cut, Copy or Paste any selected objects</li>
<li>Resize any individual square by dragging its resize handle (generalizes easily to multiple object handles)</li>
<li>Undo/redo the last N editing actions</li>
<li>View the graphical document at any desired magnification using the zoom slider</li>
</ul>
<p>That&#8217;s the externally visible stuff; what about the internals, though?  Moccasin is a framework for building applications, not a single application.  Some of the above features are built right into Moccasin (like undo/redo or magnification), while others are implemented on top of it (like square objects, or the ability to resize them with a draggable handle).</p>
<p>Moccasin is not a &#8220;thin&#8221; framework that encapsulates a set of recommended practices like Cairngorm.  It&#8217;s more of a &#8220;thick&#8221; framework.  Moccasin is aimed at building a particular type of app: one with interactive graphical views that support a lot of mouse gestures, have some notion of compound or nested views, have some notion of a current selection, a clipboard for cut/copy/paste, need robust undo/redo, and must load and save documents to persist the editor state.  The views in question are generally not Flex UIComponents in Canvases or Boxes, but lower-level Flash DisplayObjects that can have very arbitrary shapes and layout geometries.  Within this domain, Moccasin very much adheres to an MVCS way of thinking: there is a model representing the edited document&#8217;s state, a set of views that adjust to the model&#8217;s state via events, a controller which changes the model in response to user actions, and a set of services responsible for talking to the world around and outside the application.</p>
<p>Let me devote the rest of this post to a few observations on Moccasin&#8217;s treatment of the Model/View relationship.  I&#8217;ll try to keep up a series of posts over the coming weeks and, with some luck, accumulate some overview materials in fits and starts.  Probably the only way it&#8217;s going to happen given my schedule these days.</p>
<p>The way Moccasin treats Models and Views is somewhat unique (where by &#8220;unique&#8221; I mean, &#8220;I never tried it before&#8221; &#8212; I&#8217;m sure someone else has!).  As usual, one goal here is to absolutely separate view objects from models: views can reference models, but never the other way around.   This not only keeps the architecture clean, but it is absolutely essential to permit multiple views of the same model.  A second primary goal is that any change to the model should cause the view to adjust itself accordingly without additional effort by the programmer.  This involves more than just data bindings: creating a model should cause the view to be added to the display list, and removing a model from the document must cause the view to vanish.</p>
<p>A common approach to model objects in a graphical editor is to make them inherit from some big old AbstractModel superclass with a boatload of common code in it.  This code consists of all the gears and wires to dispatch the right events when the model changes, or when its set of children changes, or when some descendant model changes, or to generate a stable ID for use in document persistence&#8230; a lot of junk.</p>
<p>By contrast, here is a SimpleWorld-style class (with comments removed for brevity):</p>
<pre>
    [RemoteClass]
    [Bindable]
    public class Square
    {
        public var x:Number;
        public var y:Number;
        public var size:Number;
    }
</pre>
<p>Hey, what&#8217;s up?  This model class has no methods and extends&#8230; Object!  (Actually, EventDispatcher, due to the Bindable tag, but we&#8217;re splitting hairs).</p>
<p>In Moccasin, there are actually two sets of model objects: the <em>domain-specific model</em> (that application programmers work with) and the <em>framework model</em> (that Moccasin deals with).  The developer of a Moccasin app only writes code against the domain-specific model, and Moccasin automatically wraps that model object inside another object of type MoccasinModel.  MoccasinModel is where the &#8220;framework junk&#8221; lives, but the application programmer doesn&#8217;t see it.</p>
<p>There is also going to be a corresponding View class to draw a Square on the screen &#8212; SquareView.  Here&#8217;s a sense of what a view class looks like:</p>
<pre>
    public class SquareView extends ShapeView
    {
        public function SquareView(context:ViewContext, model:MoccasinModel=null)
        {
            super(context, model);
            initialize();
        }

        override protected function updateView():void
        {
            super.updateView();

            graphics.beginFill(0);
            var square:Square = model.value as Square;
            graphics.drawRect(0, 0, square.size, square.size);
            graphics.endFill();
        }

        override protected function createFeedbackView():DisplayObject
        {
            return new SquareFeedback(context, model);
        }
    }</pre>
<p>Because of the strong decoupling between the view, the framework model and the domain-specific model, application programmers can wind up writing very pure code to manipulate the model that doesn&#8217;t have to have any dependencies on Moccasin.  You can say something like <tt>mySquare.x += 100</tt>, and this will cause the framework to adjust the corresponding SquareView object to be redrawn in a different position.  Changing an &#8216;x&#8217; property doesn&#8217;t seem very exciting, but consider that it&#8217;s not SquareView&#8217;s &#8216;x&#8217; property being changed: it&#8217;s the Square&#8217;s property.  In fact, the relationship between model properties and view properties can be quite arbitrary.  We could have some other view of our Squares besides a 2D rendering, perhaps a numerical SquareCoordinatesTable with an X column, and a Y column, and Moccasin would manage that model/view relationship in much the same way.</p>
<p>It&#8217;s getting near my lame-old-guy bedtime and I&#8217;m flagging.  I feel better for having squeezed this post out at the end of a long day though; now to keep it going!  Next probable topic: Mediators, Contexts and Controllers in Moccasin.</p>
]]></content:encoded>
			<wfw:commentRss>http://joeberkovitz.com/blog/2008/09/30/moccasin-intro/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
