<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>AaronHardy.com &#187; air</title>
	<atom:link href="http://aaronhardy.com/tag/air/feed/" rel="self" type="application/rss+xml" />
	<link>http://aaronhardy.com</link>
	<description>For all your Aaron Hardy needs.</description>
	<lastBuildDate>Fri, 20 Apr 2012 14:53:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SpeedDial AIR App: Dial from the Desktop</title>
		<link>http://aaronhardy.com/flex/speeddial-air-app-dial-from-the-desktop/</link>
		<comments>http://aaronhardy.com/flex/speeddial-air-app-dial-from-the-desktop/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 04:33:45 +0000</pubDate>
		<dc:creator>Aaron Hardy</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[call]]></category>
		<category><![CDATA[ClientLogin]]></category>
		<category><![CDATA[pbx]]></category>
		<category><![CDATA[phone]]></category>
		<category><![CDATA[SpeedDial]]></category>

		<guid isPermaLink="false">http://aaronhardy.com/?p=791</guid>
		<description><![CDATA[Please upgrade your Flash Player This is the content that would be shown if the user does not have Flash Player 9.0.115 or higher installed. Go ahead. Dump your wallet out on your desk and filter through your receipts and frequent-diner cards trying to find that one business card with that one phone number. Then [...]]]></description>
			<content:encoded><![CDATA[<p><div id="flashcontent2739" style="width:215px; height:180px;"><strong>Please upgrade your Flash Player</strong> This is the content that would be shown if the user does not have Flash Player 9.0.115 or higher installed.</div><script type="text/javascript">
<!-- // <![CDATA[
var so = new SWFObject("http://aaronhardy.com/wp-content/plugins/air-badge/AIRInstallBadge.swf", "Badge", "215", "180", "9.0.115", "#343434");
so.useExpressInstall("http://aaronhardy.com/wp-content/plugins/air-badge/expressinstall.swf");
so.addVariable("airversion", "1.0");
so.addVariable("appname", "SpeedDial");
so.addVariable("appurl", "http://aaronhardy.com/apps/speeddial/SpeedDial.air");
so.addVariable("appid", "SpeedDial");
so.addVariable("pubid", "");
so.addVariable("appversion", "1.0");
so.addVariable("imageurl", "/apps/speeddial/badge.jpg");
so.addVariable("appinstallarg", "installed from web");
so.addVariable("applauncharg", "launched from web");
so.addVariable("helpurl", "help.html");
so.addVariable("hidehelp", "true");
so.addVariable("skiptransition", "false");
so.addVariable("titlecolor", "#00AAFF");
so.addVariable("buttonlabelcolor", "#00AAFF");
so.addVariable("appnamecolor", "#00AAFF");
so.addVariable("str_err_airswf", "<u>Running locally?</u><br/><br/>The AIR proxy swf won't load properly when this is run from the local file system.");
so.write("flashcontent2739");
// ]]&gt; -->
</script>
</p>
<p>Go ahead.  Dump your wallet out on your desk and filter through your receipts and frequent-diner cards trying to find that one business card with that one phone number.  Then proceed to pick up that phone and take on the monumental task of manually dialing each and every grueling digit.  Pshhhh.  That&#8217;s so last year.</p>
<p>Introducing SpeedDial.  Run the app and click on a Google contact with a phone number.  Your phone will ring.  You pick up.  The contact&#8217;s phone will ring.  They pick up.  Done.  Want to call them again?  Click their name.  Done.  Again?  Click their name.  Done.<span id="more-791"></span></p>
<p>Found a phone number on the web for ordering a late-night pizza?  Ugh, the agony of lifting the phone and punching in each and every digit!  Copy text, open SpeedDial, hit the call button.  Done.</p>
<p>Sit back and enjoy the demo:</p>

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="fm_Demo_1393694595"
			class="flashmovie"
			width="560"
			height="420">
	<param name="movie" value="/apps/speeddial/Demo.swf" />
	<!--[if !IE]>-->
	<object	type="application/x-shockwave-flash"
			data="/apps/speeddial/Demo.swf"
			name="fm_Demo_1393694595"
			width="560"
			height="420">
	<!--<![endif]-->
		
<p><a href="http://adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p>

	<!--[if !IE]>-->
	</object>
	<!--<![endif]-->
</object>
<p>You will need to be on a phone system with a PBX (like a workplace) for the application to function.  See the juicy details below for more info.</p>
<h3>The juicy details</h3>
<p>Calls are made using a simple <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services" target="_blank">RESTful</a> API made available by a <a href="http://en.wikipedia.org/wiki/Private_branch_exchange#Private_branch_exchange" target="_blank">PBX</a> (generally <a href="http://en.wikipedia.org/wiki/Asterisk_(PBX)" target="_blank">Asterisk</a>-based).  Once the PBX is in place and you&#8217;ve discovered the REST API used to make calls, you can pass the URL into SpeedDial as an argument.  For example, let&#8217;s say I pass in this URL as an argument to SpeedDial:</p>
<p>https://phones.mydomain.com/api?cmd=call&#038;dial_first={extension}&#038;dial_second={destination}&#038;password={pin}</p>
<p>When placing the call, SpeedDial will use the URL but replace {extension} with the user&#8217;s extension, {destination} with the phone number the user is calling, and {pin} with the user&#8217;s phone PIN.  An HTTP request will then be made to the URL and the PBX takes it from there.  By passing in the URL to the app in this manner, you can configure SpeedDial to your specific workplace without modifying the code and creating a new build.</p>
<p>As for other juicy details, SpeedDial stores credentials using an AIR encrypted local store and contacts are loaded using the <a href="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html" target="_blank">Google ClientLogin API</a>.  The app uses <a href="http://www.adobe.com/products/flex" target="_blank">Flex 4</a> and <a href="http://www.robotlegs.org/" target="_blank">Robotlegs</a>.  The full source can be found <a href="http://github.com/Aaronius/SpeedDial" target="_blank">here</a>.</p>
<div class="goodies"><a href="http://github.com/Aaronius/SpeedDial" target="_blank">Fork Project</a><br class="break"></div>
]]></content:encoded>
			<wfw:commentRss>http://aaronhardy.com/flex/speeddial-air-app-dial-from-the-desktop/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>JavaUtils: Detecting and Installing Java from AIR</title>
		<link>http://aaronhardy.com/flex/javautils-detecting-and-installing-java-from-air/</link>
		<comments>http://aaronhardy.com/flex/javautils-detecting-and-installing-java-from-air/#comments</comments>
		<pubDate>Sat, 26 Jun 2010 05:27:17 +0000</pubDate>
		<dc:creator>Aaron Hardy</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[General Programming]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[installer]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[java runtime environment]]></category>
		<category><![CDATA[JRE]]></category>
		<category><![CDATA[native process]]></category>

		<guid isPermaLink="false">http://aaronhardy.com/?p=706</guid>
		<description><![CDATA[Adobe AIR is a great way to bring the sexiness of Flash to the desktop. However, sometimes you need more low-level power for things like connecting to peripherals. For this reason, AIR applications are sometimes paired with Java applications to accomplish such tasks. But first, the user&#8217;s system must have an adequate Java Runtime Environment [...]]]></description>
			<content:encoded><![CDATA[<p>Adobe AIR is a great way to bring the sexiness of Flash to the desktop.  However, sometimes you need more low-level power for things like connecting to peripherals.  For this reason, AIR applications are sometimes paired with Java applications to accomplish such tasks.  But first, the user&#8217;s system must have an adequate Java Runtime Environment (JRE) installed in order for the Java application to run in the first place.<span id="more-706"></span></p>
<p>Before we get too far, be aware that these JavaUtils are currently for Windows only.  Macs have their own version of the JRE that&#8217;s deployed through the Software Update feature so the process of detecting and installing the JRE is very different and is left for another day.</p>
<h3>The Short Story</h3>
<p>To get started with the utilities, first download the source by <a href="http://github.com/Aaronius/JavaUtils" target="_blank">checking out the git repository</a> or <a href="http://aaronhardy.com/samples/javautils/JavaUtils.exe">installing the sample application</a>.  If you choose to install the sample application, run the app and right-click on the stage to view the source.</p>
<p>The utilities include two executables: </p>
<ol>
<li>whereis.exe &#8211; This is used internally by the tools.  See the juicy details below if you care to learn more about this.</li>
<li>jre-blah-blah-blah.exe &#8211; This is the Windows JRE online installer found here: <a href="http://www.java.com/en/download/manual.jsp" target="_blank">http://www.java.com/en/download/manual.jsp</a>.  This is the installer that is used to install a JRE of your choice if the user&#8217;s system does not have an adequate JRE already installed.  Because it&#8217;s the &#8220;online&#8221; installer, it&#8217;s lightweight and lets you avoid bundling an entire JRE with your AIR app.</li>
</ol>
<p>There are two main utility classes:</p>
<ol>
<li>JavaValidationUtil &#8211; This is used to determine if the user has an adequate JRE installed.  Call validate() and it will dispatch an event letting you know if the user has a JRE installed and if the version is sufficient.</li>
<li>JavaInstallUtil &#8211; This is used to install the JRE if needed.  Call install() and it will dispatch an event letting you know when the installation is complete.
</ol>
<h3>The Juicy Details</h3>
<p>Let&#8217;s dig into the details of how this works.  Support for running other executables as described below comes from the new <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/desktop/NativeProcess.html" target="_blank">NativeProcess</a> in AIR 2.0. </p>
<p><strong>Validation.</strong>  The first chore is to validate whether the user has a JRE installed and, if so, whether the JRE is sufficient for the application&#8217;s needs.  The developer provides the validation utility with a minimum acceptable version broken into four segments: major, minor, revision, and update.</p>
<p>Now we need to find the version of the installed JRE to compare.  But first we need to find out where the JRE is installed if one exists.  On Windows there&#8217;s an environment variable called PATH which contains several directories that should be searched to find an application when a command is executed in the command shell.  When you open up cmd, for example, you can type &#8220;notepad&#8221; and hit enter.  The fact that it&#8217;s able to open notepad isn&#8217;t magic.  Windows simply searches the PATH directories for notepad.exe and then executes it.</p>
<p>We need to do the same thing to find the java executable (java.exe).  On *nix operating systems this is pretty easy.  There&#8217;s a simple tool called whereis that comes with the operating system that searches the paths to find a given executable.  On Windows, not so much.  Luckily, our friends over at <a href="http://www.synesis.com.au/systools.html" target="_blank">Synesis</a> have released a similar tool for Windows that allows us to do the same thing.  We bundle whereis.exe with our AIR application.</p>
<p>We execute whereis.exe, passing in name of the executable we&#8217;d like to find (java.exe) as an argument.  If we don&#8217;t find java.exe, the user doesn&#8217;t have a JRE installed&#8211;at least not in the PATH paths.  And if a JRE does exist that&#8217;s not in those paths it could take a long time to find and we probably don&#8217;t want to mess with it anyway.  If java.exe is found, we then execute it passing in the -version argument.  Java will then output the version in a <a href="http://java.sun.com/j2se/versioning_naming.html" target="_blank">specified format</a> that we can then parse.  After we parse the version, we compare with the minimum acceptable version and dispatch appropriate events.</p>
<p><strong>Installation.</strong>  If no JRE is installed or the one installed isn&#8217;t adequate, the application would then generally notify the user they need a newer JRE and ask if they&#8217;d like to proceed with the installation.</p>
<p>If the user chooses to proceed, it&#8217;s time to execute the installer.  But there&#8217;s a catch.  In Windows, installer applications require &#8220;elevated privileges&#8221; before executing which means Windows nags the user asking for permission to install the JRE.  If I were to double-click the installer when it was on the desktop, it would appropriately nag.  However, if I execute the installer using AIR&#8217;s NativeProcess, nothing happens.  No error, no output, no nagging, no installing, nothing.  Is this a bug in AIR?  Eight ball says signs point to yes, but who knows, maybe Windows is to blame.</p>
<p>In my search for a workaround I found that by executing the installer from the command shell, Windows again appropriately nagged.  So then I tried executing cmd from AIR and having cmd execute the JRE installer by passing the path of the installer into cmd as an argument.  What do you know&#8211;Windows nagged appropriately and off goes the installation as planned.  When <a href="http://forums.adobe.com/thread/661442" target="_blank">presenting this problem on the Adobe AIR forums</a>, not receiving a response, then proposing the workaround, a member of the AIR engineering team seemed to think it was a good trick&#8211;nay, a great trick&#8211;so I guess that&#8217;s just the way we have to do things for now.</p>
<p>So first we use our trusty whereis.exe to find the location to cmd.exe.  Then we use cmd.exe to execute our Java installer by passing the installer path into cmd as an argument.  Windows prompts the user for permission and after permission is granted the installation proceeds as expected.  After the installation is complete, we dispatch an appropriate event.  Of course we also stay aware of fringe cases (like if the user cancels the installation) and likewise dispatch appropriate events.</p>
<p>Hopefully that&#8217;ll give you some good direction as you start your journey pairing your AIR app with Java.  Now go make something freaking fetching awesome.</p>
<div class="goodies"><a href="/samples/javautils/JavaUtils.exe">View Demo</a><a href="http://github.com/Aaronius/JavaUtils" target="_blank">Fork Project</a><br class="break"></div>
]]></content:encoded>
			<wfw:commentRss>http://aaronhardy.com/flex/javautils-detecting-and-installing-java-from-air/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>RedLiteGreenLite</title>
		<link>http://aaronhardy.com/flex/redlitegreenlite/</link>
		<comments>http://aaronhardy.com/flex/redlitegreenlite/#comments</comments>
		<pubDate>Sun, 30 May 2010 21:44:42 +0000</pubDate>
		<dc:creator>Aaron Hardy</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[General Programming]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[amf]]></category>
		<category><![CDATA[BlazeDS]]></category>
		<category><![CDATA[GAE]]></category>
		<category><![CDATA[Google Apps Engine]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[messaging]]></category>
		<category><![CDATA[polling]]></category>
		<category><![CDATA[remoting]]></category>
		<category><![CDATA[RobotLegs]]></category>

		<guid isPermaLink="false">http://aaronhardy.com/?p=658</guid>
		<description><![CDATA[Please upgrade your Flash Player This is the content that would be shown if the user does not have Flash Player 9.0.115 or higher installed. What is it? RedLiteGreenLite is a small, simple app that allows a group of people to communicate the status of something. The status can be either red or green and [...]]]></description>
			<content:encoded><![CDATA[<p><div id="flashcontent9011" style="width:215px; height:180px;"><strong>Please upgrade your Flash Player</strong> This is the content that would be shown if the user does not have Flash Player 9.0.115 or higher installed.</div><script type="text/javascript">
<!-- // <![CDATA[
var so = new SWFObject("http://aaronhardy.com/wp-content/plugins/air-badge/AIRInstallBadge.swf", "Badge", "215", "180", "9.0.115", "#343434");
so.useExpressInstall("http://aaronhardy.com/wp-content/plugins/air-badge/expressinstall.swf");
so.addVariable("airversion", "1.0");
so.addVariable("appname", "RedLiteGreenLite");
so.addVariable("appurl", "http://aaronhardy.com/rlgl/RedLiteGreenLite.air");
so.addVariable("appid", "RedLiteGreenLite");
so.addVariable("pubid", "");
so.addVariable("appversion", ".5");
so.addVariable("imageurl", "/rlgl/rlglinstallbadge.jpg");
so.addVariable("appinstallarg", "installed from web");
so.addVariable("applauncharg", "launched from web");
so.addVariable("helpurl", "help.html");
so.addVariable("hidehelp", "true");
so.addVariable("skiptransition", "false");
so.addVariable("titlecolor", "#00AAFF");
so.addVariable("buttonlabelcolor", "#00AAFF");
so.addVariable("appnamecolor", "#00AAFF");
so.addVariable("str_err_airswf", "<u>Running locally?</u><br/><br/>The AIR proxy swf won't load properly when this is run from the local file system.");
so.write("flashcontent9011");
// ]]&gt; -->
</script>
</p>
<h3>What is it?</h3>
<p>RedLiteGreenLite is a small, simple app that allows a group of people to communicate the status of something.  The status can be either red or green and the subject can be whatever.  That may sound a bit general, but that&#8217;s the point.  It can be used for whatever purpose your crazy mind can come up with.  I&#8217;ll get you started:</p>
<ol>
<li>At work, we have a single shower and a lot of shweaty guys after soccer.  So we know when the shower&#8217;s available, someone can turn the status red when he enters the shower and turn it green when he exits.  This way nobody has to keep stopping by the shower to see if it&#8217;s available.  When it&#8217;s green, it&#8217;s available.   When it&#8217;s red, it&#8217;s not.</li>
<li>At a call center, representatives are split into groups. When one group is on break, no other group is allowed to go on break.  Again, when the status is red, a group is on break and other groups must continue attending the phones.  When the lite is green, the next group is free to take a break.</li>
</ol>
<p>The process is pretty simple: join a group.  Other people join the same group.  When others in the group change the status, you&#8217;ll be notified.  When you change the status, others in the group will be notified.  The status of the group will be persisted across sessions.  In other words, if everyone logs out and then logs back in a week later, the status will remain as it was the last time it was set.<span id="more-658"></span></p>
<p>There&#8217;s no need to explicitly create a group.  When you attempt to join a group, the group will automatically be created if it does not already exist.</p>
<p>The app is free.  As in free free.</p>
<h3>What technologies are used?</h3>
<p>RedLiteGreenLite has a client portion and a server portion.</p>
<p>The client is the app users download and install on their computers.  It&#8217;s built in <a href="http://www.adobe.com/products/flex/" target="_blank">Flex</a> and published for <a href="http://www.adobe.com/products/air/" target="_blank">AIR</a>.  It uses the <a href="http://www.robotlegs.org/" target="_blank">RobotLegs</a> MVCS framework and makes use of <a href="http://en.wikipedia.org/wiki/Action_Message_Format" target="_blank">AMF</a> remoting and messaging.</p>
<p>The server portion is built in <a href="http://www.java.com/en/" target="_blank">Java</a> using <a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS/" target="_blank">BlazeDS</a> and is hosted on <a href="http://code.google.com/appengine/" target="_blank">Google Apps Engine</a>.</p>
<h3>Ooh, that&#8217;s simply juicy.  Tell me more.</h3>
<p>Don&#8217;t mind if I do.  First of all, BlazeDS is an open source implementation of AMF-based remoting and messaging.  Natively it&#8217;s not compatible with Google Apps Engine, but I wanted to use GAE because it&#8217;s extremely scalable, it&#8217;s free (let&#8217;s be honest&#8211;I&#8217;m cheap like that&#8211;this is the main reason), and I wanted the challenge.</p>
<p>To get BlazeDS working on GAE, I recommend following <a href="http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html" target="_blank">Martin Zoldano&#8217;s blog post</a>.  Not only does he outline the steps you&#8217;ll need to take but he provides a critical patch to flex-messaging-core.jar as well.  While you can find this patch re-distributed elsewhere, I recommend posting a comment requesting that he email you the patched jar.  That&#8217;s how he seems to want to distribute his patch and I respect that.  He&#8217;s really helpful and quick to respond so it shouldn&#8217;t be much trouble.</p>
<p>Once BlazeDS was set up and configured, I started to plan the architecture.  First of all, I needed one client in the group to be able to send a message to the rest of the clients in the group.  This could be achieved through the messaging service BlazeDS provides.  However, messaging doesn&#8217;t store state; it just redistributes messages to clients.  I needed the group&#8217;s status to be persisted to storage so (1) when a new client joins a group it can retrieve the group&#8217;s current status and (2) the group&#8217;s status can be retained even when no clients are connected.</p>
<p>By default, BlazeDS&#8217;s messaging configuration uses ActionScriptAdapter to receive and distribute messages between clients.  It doesn&#8217;t persist messages.  To do so, I extend ActionScriptAdapter and persist the status to Google Storage before sending the message out to the other clients.  When clients connect to BlazeDS, they use remoting (not messaging) to retrieve the most recently persisted status for the group.  After the initial status is retrieved, the client talks to other clients using the messaging service.  You can see how this is set up in messaging-config.xml and PersistentASAdapter.java in the <a href="http://github.com/Aaronius/RedLiteGreenLite" target="_blank">server code</a>.</p>
<p>While GAE has been really nice to get the app up and running, it does have its downsides.  To send messages between clients, BlazeDS can use a few different techniques:</p>
<ul>
<li>Simple polling. The client, at a standard interval, simply asks the server if there is any new information.  The server responds to the request immediately regardless of whether there is new information.</li>
<li>Long polling. The client sends a request to the server.  The server holds onto the request until it has something useful to tell the client at which time it sends back the response.</li>
<li>Streaming.  The client opens an HTTP connection and the connection remains open.  The server shoots messages down the connection whenever it has something to say.  It&#8217;s an &#8220;infinate response&#8221;.</li>
</ul>
<p>While <a href="http://www.dcooper.org/blog/client/index.cfm?mode=entry&#038;entry=8E1439AD-4E22-1671-58710DD528E9C2E7" target="_blank">each approach has its pros and cons</a>, simple polling leaves a lot to be desired as it creates a lot of HTTP traffic.  Unfortunately, from my testing and research, GAE doesn&#8217;t seem to support either of the other two methods.  But hey, it&#8217;s free.  If any of you have a java environment and would like to host RedLiteGreenLite so we can step up our game, let me know.</p>
<p>Last but not least, RedLiteGreenLite is open source.  I&#8217;d love for you to <a href="http://github.com/Aaronius/RedLiteGreenLite" target="_blank">fork the project</a> and do something cool with it.</p>
<p>Now go have fun!  Install the client using the badge at the top of the post or fork the project using the link below.</p>
<div class="goodies"><a href="http://github.com/Aaronius/RedLiteGreenLite" target="_blank">Fork Project</a><br class="break"></div>
]]></content:encoded>
			<wfw:commentRss>http://aaronhardy.com/flex/redlitegreenlite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Piano Marvel: Interactive Piano Lessons</title>
		<link>http://aaronhardy.com/flex/piano-marvel-interactive-piano-lessons/</link>
		<comments>http://aaronhardy.com/flex/piano-marvel-interactive-piano-lessons/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 03:48:23 +0000</pubDate>
		<dc:creator>Aaron Hardy</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[General Programming]]></category>
		<category><![CDATA[adobe max award]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[merapi]]></category>
		<category><![CDATA[musicXML]]></category>
		<category><![CDATA[piano lessons]]></category>
		<category><![CDATA[piano marvel]]></category>
		<category><![CDATA[pianomarvel]]></category>

		<guid isPermaLink="false">http://aaronhardy.com/?p=341</guid>
		<description><![CDATA[Rain, where I work, has released yet another super-duper app. It&#8217;s called Piano Marvel and it&#8217;s set to revolutionize how people learn how to play the piano. I&#8217;m not a piano player myself, but I do remember taking private piano lessons as a kid. I hated it. It was monotonous, inconvenient, and felt like a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://mediarain.com" target="_blank">Rain</a>, where I work, has released yet another super-duper app.  It&#8217;s called <a href="http://pianomarvel.com" target="_blank">Piano Marvel</a> and it&#8217;s set to revolutionize how people learn how to play the piano.  I&#8217;m not a piano player myself, but I do remember taking <a href="http://takelessons.com/category/piano-lessons" target="_blank">private piano lessons</a> as a kid.  I hated it.  It was monotonous, inconvenient, and felt like a chore.  I wasn&#8217;t intrigued and I don&#8217;t believe I was the only kid that felt this way.</p>
<p>A while back, <a href="http://hub.guitarhero.com/" target="_blank">Guitar Hero</a> hit the gaming industry by storm and <a href="http://www.youtube.com/watch?v=-XjaImfQK6U" target="_blank">kids flocked to learning the guitar</a>.  Sure, it wasn&#8217;t a real guitar, but it was still an instrument of sorts and kids were still learning hand-eye-ear coordination, rhythm, and other music essentials.  The game was a huge success, bringing in over $1 billion in sales in the first 26 months and set an industry record.</p>
<p>Why such a difference in my experience learning how to play the piano years ago and kids learning the pseudo-guitar with Guitar Hero?  Guitar Hero provides objectivity, benchmarking, competition, and addiction.  You can play with your friends in a fun atmosphere.  Piano Marvel takes these concepts and applies them to learning the piano.  Students play along to accompaniment, see exactly which notes they hit and when they hit them, and earn trophies as they complete increasingly difficult exercises.  They can practice whenever they choose and can even battle it out with their piano-playing comrades.<span id="more-341"></span></p>
<p><object width="560" height="340" data="http://www.youtube.com/v/QotI0BLTGNE&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/QotI0BLTGNE&amp;hl=en&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /></object></p>
<p>Now to the gushy technical stuff.</p>
<p>First, Piano Marvel is built using <a href="http://www.adobe.com/products/air/" target="_blank">Adobe AIR</a> and <a href="http://www.java.com" target="_blank">Java</a>.  Adobe AIR provides the high level of interactivity needed for such an application.  Java provides the ability to communicate with a MIDI keyboard.  Both are bridged using <a href="http://code.google.com/p/transmission-as3/" target="_blank">Transmission</a>&#8211;AIR talks to Java, Java talks to AIR.  All are deployed onto the user&#8217;s desktop with a single installer.  Both Windows and Mac are supported.</p>
<p>Second, all the exercise content can be easily managed by the administrator.  Let&#8217;s say the administrator wants to add an exercise.  He plays a little ditty in <a href="http://www.finalemusic.com/" target="_blank">Finale</a> using his keyboard, saves the musical notation as a <a href="http://www.recordare.com/xml.html" target="_blank">MusicXML</a> file, saves the accompaniment in <a href="http://en.wikipedia.org/wiki/Musical_Instrument_Digital_Interface" target="_blank">MIDI</a> format, and uploads both files using an online admin panel.  The next time students log in, they have a new exercise to conquer.</p>
<p>Third, all music notation is dynamic.  In other words, an exercise is not just a big graphic of sheet music.  Instead, MusicXML is loaded from the server at runtime.  The XML is immediately parsed and notes, accidentals, lines, dots, and all notation the user sees is drawn to the screen at that moment.  Resize the window and the music is redrawn, not simply scaled, to fit into the available space in the most elegant and readable way possible.  Because the MusicXML is very comprehensive in describing a musical piece, we can also use the XML to determine pitch and timing for evaluating a user&#8217;s performance.</p>
<p>Fourth, the user can tweak the tempo, only play a portion of an exercise, toggle accompaniment and metronome sounds, get note hints, watch tutorial videos, and more.</p>
<p>Fifth, the application was recently nominated as an <a href="http://max.adobe.com/awards/" target="_blank">Adobe Max 2009 Awards</a> finalist in the education category.  Yeah, we&#8217;re kind of a big deal.</p>
<p>If that isn&#8217;t enough, you can watch my ugly cakehole yack about Piano Marvel below:</p>
<p><object width="560" height="315" data="http://vimeo.com/moogaloop.swf?clip_id=5012163&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" type="application/x-shockwave-flash"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=5012163&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" /></object></p>
<p>You can use a free demo account to get hooked then pay a low monthly fee after your trial period is over.  If you check it out using <a href="http://www.pianomarvel.com/users/free-trial/9CAEF13F" target="_blank">this link</a> you&#8217;ll only pay $12/month if you choose to sign up.  That&#8217;s less than the gas you&#8217;d pay for to visit a piano teacher.  All you need is a MIDI keyboard and a MIDI-to-USB adapter to get started.</p>
<p>Here are several screenshots of the app and its features.  Props go out to <a href="http://natescodevault.com/?p=241" target="_blank">Nate Ross</a> for letting me steal his screenshots and captions.</p>
<hr />
<div id="attachment_351" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-351" title="pianomarvel_tooltip" src="http://aaronhardy.com/wp-content/uploads/2009/09/pianomarvel_tooltip.png" alt="Create a rich interactive music notation engine." width="500" height="379" /><p class="wp-caption-text">Create a rich interactive music notation engine.</p></div>
<hr />
<div id="attachment_353" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-353" title="pianomarvel_scoring" src="http://aaronhardy.com/wp-content/uploads/2009/09/pianomarvel_scoring.png" alt="Display immediate feedback on all correct and incorrect notes that were played." width="500" height="209" /><p class="wp-caption-text">Display immediate feedback on all correct and incorrect notes that were played.</p></div>
<hr />
<div id="attachment_354" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-354" title="pianomarvel_controls" src="http://aaronhardy.com/wp-content/uploads/2009/09/pianomarvel_controls.png" alt="Have the ability to specify tempo, make music selections, and toggle fun accompaniment and metronome playback." width="500" height="124" /><p class="wp-caption-text">Have the ability to specify tempo, make music selections, and toggle fun accompaniment and metronome playback.</p></div>
<hr />
<div id="attachment_355" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-355" title="pianomarvel_lessons" src="http://aaronhardy.com/wp-content/uploads/2009/09/pianomarvel_lessons.png" alt="Create an environment that makes playing the piano addictive and entertaining." width="500" height="343" /><p class="wp-caption-text">Create an environment that makes playing the piano addictive and entertaining</p></div>
]]></content:encoded>
			<wfw:commentRss>http://aaronhardy.com/flex/piano-marvel-interactive-piano-lessons/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

