<?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/"
	>

<channel>
	<title>No, I am better than that!</title>
	<atom:link href="http://rickosborne.org/blog/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://rickosborne.org/blog</link>
	<description>Striving to subdue the mediocrity.</description>
	<lastBuildDate>Tue, 09 Mar 2010 05:24:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Automating workout mixes &#8211; help?</title>
		<link>http://rickosborne.org/blog/index.php/2010/03/08/automating-workout-mixes-help/</link>
		<comments>http://rickosborne.org/blog/index.php/2010/03/08/automating-workout-mixes-help/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 23:45:47 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://rickosborne.org/blog/?p=1186</guid>
		<description><![CDATA[
Update: I think I have this figured out: SoX will do pretty much everything I need.  It&#8217;ll even do intelligent crossfades and tempo adjustment.  w00t!
The Problem&#8212;Short Form
Given a database of MP3 files and their intro and outro times, I need a piece of software with a text-based file format that will allow me [...]]]></description>
			<content:encoded><![CDATA[<p align="center"><img src="/blog/wp-content/uploads/2010/03/Garageband-mix.png" alt="The mix console of Garageband 5 used to produce a workout MP3" title="Workout Mix in Garageband 5" width="500" height="309" /></p>
<blockquote><p><strong>Update:</strong> I think I have this figured out: <a href="http://sox.sourceforge.net/">SoX</a> will do pretty much everything I need.  It&#8217;ll even do intelligent crossfades and tempo adjustment.  w00t!</p></blockquote>
<h3>The Problem&mdash;Short Form</h3>
<p>Given a database of MP3 files and their intro and outro times, I need a piece of software with a text-based file format that will allow me to programmatically produce a workout mix, crossfading between tracks at the specified intervals.  Conceptually:</p>
<pre>[Track 1]
file    = /path/to/track01.mp3
startAt = 00:00:00
endAt   = 00:03:21

[Track 2]
file    = /path/to/track2.mp3
startAt = 00:00:17
endAt   = 00:02:57</pre>
<p>I&#8217;m unconcerned with the input file format, as long as it&#8217;s something I can produce with, for example, Perl.  My one effect requirement is the ability to crossfade, but I don&#8217;t need beat-matching or other magic.  (I&#8217;d like to also be able to pan, but that&#8217;s a want, not a need.)</p>
<p>I&#8217;ve tried:</p>
<dl>
<dt>GarageBand</dt>
<dd>The input .band file format is binary.  (Wrapped in xml to look friendly, but binary nonetheless.)</dd>
<dt>Audacity</dt>
<dd>The .aup project file format is XML and readily suits my needs &#8230; but the audio has to be pre-converted into chunked .au files.</dd>
<dt>SoundBooth</dt>
<dd>The .stmp file format is binary.</dd>
</dl>
<p>So, Lazyweb, any suggestions?</p>
<h3>The Problem&mdash;Long Form</h3>
<p>As the weather gets warmer and the runs get longer, I find myself in need of more customized music for my workouts.  Sometimes I want an interval mix, sometimes a gentle climb.  Point being, I&#8217;ve got a hundred gigabytes of music and I&#8217;d like to put it to good use.  I&#8217;ve got it BPM-tagged, as well as ancillary data on how long the intros and outros are.</p>
<p>But, <a href="/blog/index.php/2010/02/12/its-not-oakenfold-or-steveboy-but-itll-do/">mixing the music takes time</a>.  I&#8217;ve gotten it down to about 2:1 time invested to playback length&mdash;a 30-minute mix takes about an hour to prepare&mdash;but I&#8217;d like a bit more randomization.</p>
<p>I&#8217;d really, <em>really</em> like to programmatically generate my own playlists, with instructions for where to start and end each song.  But, in all my poking around, I have yet to find a program with a plain text input file that will also take MP3s.</p>
<p>I&#8217;ve started looking into <a href="http://csounds.com/">Csound</a>, but that seems like it might be like hiring a defense contractor to build a bird house.  It may just come down to Perl &rarr; <a href="http://mp3splt.sourceforge.net/">mp3splt</a> &rarr; <a href="http://www.underbit.com/products/mad/">madplay</a> &rarr; faac, presuming I can figure out a way to hack in little crossfades between tracks.</p>
<p>Any suggestions?</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/index.php/2010/03/08/automating-workout-mixes-help/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yes, Virginia, that&#8217;s automated SQL to MongoDB MapReduce</title>
		<link>http://rickosborne.org/blog/index.php/2010/02/19/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/</link>
		<comments>http://rickosborne.org/blog/index.php/2010/02/19/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 23:42:10 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[ColdFusion]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[derby]]></category>
		<category><![CDATA[mapreduce]]></category>
		<category><![CDATA[mongodb]]></category>

		<guid isPermaLink="false">http://rickosborne.org/blog/?p=1174</guid>
		<description><![CDATA[I have to admit, I&#8217;m pretty darn proud of this one.  This is a righteous hack.  I can now write SQL against MongoDB with ColdFusion.
My project today was to take this SQL statement:
SELECT "goalType",
  SUM("distancekm") AS "totalkm",
  COUNT(*) AS "workouts",
  COUNT("powerSongAlbum") AS "songcount",
  AVG("distancekm") AS "avgkm",
  MAX("distancekm") AS [...]]]></description>
			<content:encoded><![CDATA[<p>I have to admit, I&#8217;m pretty darn proud of this one.  This is a righteous hack.  I can now write SQL against MongoDB with ColdFusion.</p>
<p>My project today was to take this SQL statement:</p>
<pre class="sql">SELECT "goalType",
  SUM("distancekm") AS "totalkm",
  COUNT(*) AS "workouts",
  COUNT("powerSongAlbum") AS "songcount",
  AVG("distancekm") AS "avgkm",
  MAX("distancekm") AS "maxkm",
  MIN("distancekm") AS "minkm"
FROM "workouts"
GROUP BY "goalType"</pre>
<p>&#8230; and create a set of ColdFusion components to transform that query into a MapReduce function that would run on MongoDB.  <a href="/blog/index.php/2010/02/09/infographic-migrating-from-sql-to-mapreduce-with-mongodb/">Mapping basic SQL to MongoDB MapReduce</a> isn&#8217;t too hard.  Getting the <a href="/blog/index.php/2010/02/19/derby-svn-coldfusion-sql-parser/">SQL parser from Derby working within ColdFusion</a> was significantly harder.</p>
<p>But I did it.  This is the <strong>completely automated</strong> result:</p>
<pre class="javascript">db.runCommand({
mapreduce: "workouts",
map: function () { emit(
  this.goalType,
  {
    '_cfcount': 1,
    'distancekm_cfsum': isNaN(this.distancekm) ? null : this.distancekm,
    'distancekm_cfnum': isNaN(this.distancekm) ? 0 : 1,
    'powerSongAlbum_cfcount': (this.powerSongAlbum == null) ? 0 : 1,
    'distancekm_cfmax': isNaN(this.distancekm) ? null : this.distancekm,
    'distancekm_cfmin': isNaN(this.distancekm) ? null : this.distancekm
  }
); },
reduce: function (key,vals) {
  var ret = {
    'distancekm_cfmax': null,
    'distancekm_cfsum': null,
    'distancekm_cfmin': null,
    'distancekm_cfnum': 0,
    'powerSongAlbum_cfcount': 0,
    '_cfcount': 0
  };
  for(var i = 0; i < vals.length; i++) {
    var v = vals[i];
    ret['distancekm_cfnum'] += v['distancekm_cfnum'];
    if(!isNaN(v['distancekm_cfmax'])) ret['distancekm_cfmax'] = (ret['distancekm_cfmax'] == null) ? v['distancekm_cfmax'] : (ret['distancekm_cfmax'] > v['distancekm_cfmax']) ? ret['distancekm_cfmax'] : v['distancekm_cfmax'];
    ret['_cfcount'] += v['_cfcount'];
    if(!isNaN(v['distancekm_cfmin'])) ret['distancekm_cfmin'] = (ret['distancekm_cfmin'] == null) ? v['distancekm_cfmin'] : (v['distancekm_cfmin'] > ret['distancekm_cfmin']) ? ret['distancekm_cfmin'] : v['distancekm_cfmin'];
    ret['powerSongAlbum_cfcount'] += v['powerSongAlbum_cfcount'];
    if(!isNaN(v['distancekm_cfsum'])) ret['distancekm_cfsum'] = v['distancekm_cfsum'] + (ret['distancekm_cfsum'] == null ? 0 : ret['distancekm_cfsum']);
  }
  return ret;
},
finalize: function (key,val) {
  return {
    'totalkm'   : val['distancekm_cfsum'],
    'workouts'  : val['_cfcount'],
    'songcount' : val['powerSongAlbum_cfcount'],
    'avgkm'     : (isNaN(val['distancekm_cfnum']) || isNaN(val['distancekm_cfsum'])) ? null : val['distancekm_cfsum'] / val['distancekm_cfnum'],
    'maxkm'     : val['distancekm_cfmax'],
    'minkm'     : val['distancekm_cfmin']
  };
},
out: "s2mr",
verbose: true
});</pre>
<p>And here&#8217;s the output when I run that against my MongoDB collection:</p>
<pre class="coldfusion">{ "_id" : null, "value" : {
    "totalkm" : 451.6752000000001,
    "workouts" : 54,
    "songcount" : 53,
    "avgkm" : 8.364355555555557,
    "maxkm" : 19.7502,
    "minkm" : 0.0194
} }
{ "_id" : "Distance", "value" : {
    "totalkm" : 304.76879999999994,
    "workouts" : 27,
    "songcount" : 27,
    "avgkm" : 11.287733333333332,
    "maxkm" : 26.2581,
    "minkm" : 4.0486
} }
{ "_id" : "Time", "value" : {
    "totalkm" : 19.221,
    "workouts" : 2,
    "songcount" : 2,
    "avgkm" : 9.6105,
    "maxkm" : 9.9224,
    "minkm" : 9.2986
} }</pre>
<p>w00t!</p>
<p>I&#8217;ve left the code modular enough that I can make a CouchDB version <em>almost</em> as easily.</p>
<p><em>Update:</em> Better yet, I can now get all the way to an actual query data type:</p>
<table style="border-color: #884488 ; border-collapse: collapse; border-color: #884488;" border="2">
<tr>
<th style="background-color: #aa66aa;" colspan="8">query</th>
</tr>
<tr bgcolor="eeaaaa" >
<td style="background-color: #ffddff ;">&nbsp;</td>
<td style="background-color: #ffddff ;">AVGKM</td>
<td style="background-color: #ffddff ;">MAXKM</td>
<td style="background-color: #ffddff ;">MINKM</td>
<td style="background-color: #ffddff ;">SONGCOUNT</td>
<td style="background-color: #ffddff ;">TOTALKM</td>
<td style="background-color: #ffddff ;">WORKOUTS</td>
<td style="background-color: #ffddff ;">_ID</td>
</tr>
<tr >
<td style="background-color: #ffddff ;">1</td>
<td valign="top"> 8.3644 </td>
<td valign="top">19.7502 </td>
<td valign="top">0.0194 </td>
<td valign="top">53 </td>
<td valign="top">451.6752 </td>
<td valign="top">54 </td>
<td valign="top">[empty string] </td>
</tr>
<tr >
<td style="background-color: #ffddff ;">2</td>
<td valign="top">11.2877 </td>
<td valign="top">26.2581 </td>
<td valign="top">4.0486 </td>
<td valign="top">27 </td>
<td valign="top">304.7688 </td>
<td valign="top">27 </td>
<td valign="top">Distance </td>
</tr>
<tr >
<td style="background-color: #ffddff ;">3</td>
<td valign="top">9.6105 </td>
<td valign="top">9.9224 </td>
<td valign="top">9.2986 </td>
<td valign="top">2 </td>
<td valign="top">19.221 </td>
<td valign="top">2 </td>
<td valign="top">Time </td>
</tr>
</table>
<p>(Note for potential cynics: no, I&#8217;m <em>not</em> missing the point.  This is <em>not</em> meant as a production tool&mdash;it&#8217;s a learning tool.  If my students can start with SQL and see the end result in MapReduce, then they have that much better chance of grokking all of it.)</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/index.php/2010/02/19/yes-virginia-thats-automated-sql-to-mongodb-mapreduce/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Derby SVN + ColdFusion = SQL Parser</title>
		<link>http://rickosborne.org/blog/index.php/2010/02/19/derby-svn-coldfusion-sql-parser/</link>
		<comments>http://rickosborne.org/blog/index.php/2010/02/19/derby-svn-coldfusion-sql-parser/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 05:14:34 +0000</pubDate>
		<dc:creator>Rick Osborne</dc:creator>
				<category><![CDATA[ColdFusion]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[derby]]></category>

		<guid isPermaLink="false">http://rickosborne.org/blog/?p=1165</guid>
		<description><![CDATA[Brain dump follows.


Checkout Derby from SVN.


Apply a patch:
Index: java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java	(working copy)
@@ -732,6 +732,26 @@
 	}

 	/**
+	 * Get the operator
+	 *
+	 * @return String The operator.
+	 */
+	public String getOperatorString()
+	{
+		return operator;
+	}
+
+	/**
+	 * Get the methodName
+	 *
+	 * @return String The methodName.
+	 */
+	public String getMethodName()
+	{
+		return methodName;
+	}
+
+	/**
 	 * Categorize this predicate.  Initially, this means
 [...]]]></description>
			<content:encoded><![CDATA[<p>Brain dump follows.</p>
<ol>
<li>
<p><a href="https://svn.apache.org/repos/asf/db/derby/code/trunk/">Checkout Derby from SVN</a>.</p>
</li>
<li>
<p>Apply a patch:</p>
<pre class="diff">Index: java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java	(working copy)
@@ -732,6 +732,26 @@
 	}

 	/**
+	 * Get the operator
+	 *
+	 * @return String The operator.
+	 */
+	public String getOperatorString()
+	{
+		return operator;
+	}
+
+	/**
+	 * Get the methodName
+	 *
+	 * @return String The methodName.
+	 */
+	public String getMethodName()
+	{
+		return methodName;
+	}
+
+	/**
 	 * Categorize this predicate.  Initially, this means
 	 * building a bit map of the referenced tables for each predicate.
 	 * If the source of this ColumnReference (at the next underlying level)
Index: java/engine/org/apache/derby/impl/sql/compile/SelectNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/SelectNode.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/SelectNode.java	(working copy)
@@ -360,6 +360,36 @@
 	}

 	/**
+	 * Return the groupByList for this SelectNode.
+	 *
+	 * @return GroupByList	The groupByList for this SelectNode.
+	 */
+	public GroupByList getGroupByList()
+	{
+		return groupByList;
+	}
+
+	/**
+	 * Return the havingClause for this SelectNode.
+	 *
+	 * @return HavingClause	The havingClause for this SelectNode.
+	 */
+	public ValueNode getHavingClause()
+	{
+		return havingClause;
+	}
+
+	/**
+	 * Return the orderByList for this SelectNode.
+	 *
+	 * @return OrderByList	The orderByList for this SelectNode.
+	 */
+	public OrderByList getOrderByList()
+	{
+		return orderByList;
+	}
+
+	/**
 	 * Find colName in the result columns and return underlying columnReference.
 	 * Note that this function returns null if there are more than one FromTable
 	 * for this SelectNode and the columnReference needs to be directly under
Index: java/engine/org/apache/derby/impl/sql/compile/QueryTreeNodeVector.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/QueryTreeNodeVector.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/QueryTreeNodeVector.java	(working copy)
@@ -46,7 +46,7 @@
 		return v.size();
 	}

-	QueryTreeNode elementAt(int index)
+	public QueryTreeNode elementAt(int index)
 	{
 		return (QueryTreeNode) v.elementAt(index);
 	}
Index: java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java	(working copy)
@@ -198,7 +198,7 @@
 	 *
 	 * @return	The operator of this unary operator.
 	 */
-	String getOperatorString()
+	public String getOperatorString()
 	{
 		return operator;
 	}
@@ -267,6 +267,16 @@
 	}

 	/**
+	 * Get the methodName
+	 *
+	 * @return String The methodName.
+	 */
+	public String getMethodName()
+	{
+		return methodName;
+	}
+
+	/**
 	 * Get the parameter operand of this unary operator.
 	 * For the example below, for abs unary operator node, we want to get ?
 	 * select * from t1 where -? = max_cni(abs(-?), sqrt(+?))
Index: java/engine/org/apache/derby/impl/sql/compile/BinaryListOperatorNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/BinaryListOperatorNode.java	(revision 911671)
+++ java/engine/org/apache/derby/impl/sql/compile/BinaryListOperatorNode.java	(working copy)
@@ -95,6 +95,26 @@
 	}

 	/**
+	 * Get the operator
+	 *
+	 * @return String The operator.
+	 */
+	public String getOperatorString()
+	{
+		return operator;
+	}
+
+	/**
+	 * Get the methodName
+	 *
+	 * @return String The methodName.
+	 */
+	public String getMethodName()
+	{
+		return methodName;
+	}
+
+	/**
 	 * Prints the sub-nodes of this object.  See QueryTreeNode.java for
 	 * how tree printing is supposed to work.
 	 *
</pre>
</li>
<li>
<p>Build Derby:</p>
<pre class="bash">alias javac='/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/javac -target 1.5'
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/
ant -quiet clobber ; ant -quiet buildsource ; ant -quiet buildjars</pre>
</li>
<li>
<p>Archive <kbd>$CFROOT/lib/derby*.jar</kbd> to a cool, dry place.</p>
</li>
<li>
<p>Stop ColdFusion.</p>
</li>
<li>
<p>Copy <kbd>$DERBY/jars/sane/derby*.jar</kbd> to <kbd>$CFROOT/lib</kbd>.</p>
</li>
<li>
<p>Restart ColdFusion.</p>
</li>
<li>
<p>Execute template:</p>
<pre class="coldfusion">&lt;cfscript&gt;
createObject("java", "java.lang.System").
	setProperty("derby.debug.true", "StopAfterParsing");
driver = createObject("java", "org.apache.derby.jdbc.EmbeddedDriver").init();
props = createObject("java","java.util.Properties");
conn = driver.connect("jdbc:derby:memory:dummy;create=true",props);
sql = "SELECT a, b FROM foo, bar";
try { conn.prepareStatement(sql); }
catch(org.apache.derby.impl.jdbc.EmbedSQLException e) {
	if(e.sqlState neq "42Z55") rethrow();
}
qt = conn.getContextManager().
	getContext("LanguageConnectionContext").
	getLastQueryTree();
select = qt.getResultSetNode();
from = select.getFromList();
tableCount = from.size();
for(tableNum = 0; tableNum lt tableCount; tableNum++) {
	baseTable = from.getOptimizable(tableNum);
	tableName = baseTable.getTableName().toString();
	writeDump(tableName);
}
// bytes = createObject("java", "java.io.ByteArrayOutputStream").init();
// createObject("java", "org.apache.derby.iapi.services.sanity.SanityManager").
	SET_DEBUG_STREAM(createObject("java", "java.io.PrintWriter").init(bytes));
// qt.treePrint();
// writeDump(bytes.toString());
try { driver.connect("jdbc:derby:memory:dummy;shutdown=true", props); }
catch(any e) { }
&lt;/cfscript&gt;</pre>
</li>
</ol>
<p>Anybody wanna rewrite QoQ?</p>
]]></content:encoded>
			<wfw:commentRss>http://rickosborne.org/blog/index.php/2010/02/19/derby-svn-coldfusion-sql-parser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
