Index: /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/etc/collectionConfig.xml
===================================================================
--- /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/etc/collectionConfig.xml	(revision 29892)
+++ /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/etc/collectionConfig.xml	(revision 29893)
@@ -17,5 +17,6 @@
 		<displayItem assigned="true" lang="en" name="section">section</displayItem>
 	</displayItemList>
-	<format>  <gsf:template name="choose-title">
+	<format>  
+	  <gsf:template name="choose-title">
     <gsf:choose-metadata>
       <gsf:metadata name="dc.Title"/>
@@ -27,15 +28,11 @@
       <gsf:default>Untitled</gsf:default>
     </gsf:choose-metadata>
+
+<xsl:text> </xsl:text>
+
     <gsf:switch>
-      <gsf:metadata name="dc.Creator"/>
+      <gsf:metadata name="dc.Description"/>
       <gsf:when test="exists">
-        <gsf:switch>
-          <gsf:metadata name="dc.Description"/>
-          <gsf:when test="notEquals" test-value="Unknown">
- 
-              <gsf:metadata name="dc.Description"/>
-
-          </gsf:when>
-        </gsf:switch>
+	<gsf:metadata name="dc.Description"/>
       </gsf:when>
     </gsf:switch>
@@ -249,7 +246,10 @@
 </xsl:call-template>
 -->
+<!--
     <h3>
       <xsl:call-template name="choose-title"/>
     </h3>
+-->
+
   </gsf:template>
 <!--
@@ -336,4 +336,7 @@
     <gsf:script src="{$httpCollection}/js/jquery.qtip.min.js"/>
     <gsf:script src="{$httpCollection}/js/qtip-popups.js"/>
+
+    <gsf:script src="{$httpCollection}/js/key-detection.js"/>
+
 <!--
 MIDI.js library
Index: /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/game-on.js
===================================================================
--- /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/game-on.js	(revision 29892)
+++ /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/game-on.js	(revision 29893)
@@ -88,4 +88,60 @@
 }
 
+
+function computeMidiStats(track)
+{
+    var min_midi_pitch = num_midi_pitches-1;
+    var max_midi_pitch = 0;
+
+    var track_chromatic_durations = [];
+    for (var i=0; i<12; i++) {
+	track_chromatic_durations[i] = 0;
+    }
+
+    // Process each block within the track
+    for (var b=0; b<track.length; b++) {
+	var track_block = track[b];
+	//var base_ctime = track_block.baseCTime;
+	var block_events = track_block.events;
+
+	var block_chromatic_durations = [];
+	for (var i=0; i<12; i++) {
+	    block_chromatic_durations[i] = 0;
+	}
+	
+	for (var ne=0; ne<block_events.length; ne++) {
+	    var midi_pitch = block_events[ne].midiPitch;
+
+	    if (midi_pitch < min_midi_pitch) {
+		min_midi_pitch = midi_pitch;
+	    }
+	    if (midi_pitch > max_midi_pitch) {
+		max_midi_pitch = midi_pitch;
+	    }
+
+	    var chromatic_pitch = midi_pitch % 12;
+	    var chromatic_duration = block_events[ne].duration;
+	    block_chromatic_durations[chromatic_pitch] += chromatic_duration;
+
+	    track_chromatic_durations[chromatic_pitch] += chromatic_duration;
+	}
+
+	if (!("_computedKey" in track_block)) {
+	    var strongest_profile = khKeyDetection(block_chromatic_durations);
+	    track_block._computedKey = strongest_profile;
+	    console.log("***### key prediction: " + strongest_profile);
+	}
+
+    }
+
+    if (!("_computedKey" in track)) {
+	var strongest_profile = khKeyDetection(track_chromatic_durations);
+	track._computedKey = strongest_profile;
+    }
+
+    return { "max_midi_pitch": max_midi_pitch, "min_midi_pitch": min_midi_pitch};
+}
+
+
 function displayActiveTrackLayers(docStorage)
 {
@@ -116,5 +172,17 @@
 	    if (track != null) {
 
+
+		var midi_stats = computeMidiStats(track);
+
+		if (midi_stats.min_midi_pitch < min_midi_pitch) {
+		    min_midi_pitch = midi_stats.min_midi_pitch;
+		}
+		if (midi_stats.max_midi_pitch > max_midi_pitch) {
+		    max_midi_pitch = midi_stats.max_midi_pitch;
+		}
+
+
 		// calculate range of midi pitches present
+/*
 		for (var b=0; b<track.length; b++) {
 		    var track_block = track[b];
@@ -132,4 +200,6 @@
 		    }
 		}
+*/
+
 	    }
 	}
Index: /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js
===================================================================
--- /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js	(revision 29892)
+++ /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js	(revision 29893)
@@ -1,6 +1,78 @@
 "use strict";
 
-// From:
+// Key detection algorithm, as described at:
 //  http://rnhart.net/articles/key-finding/
+
+// (from this web site) ....
+//  Krumhansl-Schmuckler key-finding algorithm (by Carol L. Krumhansl
+//  and Mark A. Schmuckler). The profile numbers came from experiments
+//  done by Krumhansl and Edward J. Kessler. The experiments consisted
+//  of playing a set of context tones or chords, playing a probe tone,
+//  and asking a listener to rate how well the probe tone fit with the
+//  context. You can read about the experiments and the algorithm in
+//  Krumhansl's book Cognitive Foundations of Musical Pitch. (The
+//  experiments are described in Chapter 2. The key-finding algorithm
+//  is described in Chapter 4.) You may be able to read portions of
+//  the book on Google Books.
+
+
+function khMean(vals) 
+{
+    var len = vals.length;
+    if (len==0) {
+	return 0;
+    }
+
+    var total = 0;
+
+    for (var i=0; i<len; i++) {
+	total += vals[i];
+    }
+
+    return total/len;
+}
+
+function khUnbiased(vals) 
+{
+    var unbiased_vals = [];
+
+    var len = vals.length;
+    if (len==0) {
+	return unbiased_vals;
+    }
+
+    var avg = khMean(vals);
+
+    for (var i=0; i<len; i++) {
+	unbiased_vals.push(vals[i] - avg)
+    }
+
+    return unbiased_vals;
+}
+
+
+function khCorrelationCoefficientUnbiased(a1,a2)
+{
+    var a1_len = a1.length;
+    var a2_len = a2.length;
+   
+    if (a1_len != a2_len) {
+	throw "khCorrelationCoefficientUnbiased(): arrays should be of the same length (" + a1_len + " vs " + a2_len + ")";
+    }
+    var len = a1_len;
+
+    var a1_a2_pair_prod = 0;
+    var a1_square = 0;
+    var a2_square = 0;
+
+    for (var i=0; i<len; i++) {
+	a1_a2_pair_prod += (a1[i]*a2[i]);
+	a1_square += (a1[i]*a1[i]);
+	a2_square += (a2[i]*a2[i]);	
+    }
+
+    return a1_a2_pair_prod / Math.sqrt(a1_square * a2_square);
+}
+
 
 //major profile
@@ -19,18 +91,24 @@
 var kh_minor_profile = [6.33, 2.68, 3.52, 5.38, 2.60, 3.53, 2.54, 4.75, 3.98, 2.69, 3.34, 3.17 ];
 
+var kh_major_profile_unbiased = khUnbiased(kh_major_profile);
+
+var kh_minor_profile_unbiased = khUnbiased(kh_minor_profile);
+
 
 function khCreatePairing(profile,chromatic_scale_durations,offset)
 {
-    var pairing = [];
-    for (var p=0; p<12; p++) {
-	pairing.push({"p":profile[p],"c":chromatic_scale_durations[(p+s)%12]});
+    var p = [];
+    var c = [];
+    for (var i=0; i<12; i++) {
+	p.push(profile[i])
+	c.push(chromatic_scale_durations[(i+offset)%12]);
     }
     
 
-    return pairing;
-}
-
-
-function khCreateAllPairings(chromatic_scale_durations,major_profile,minor_profile)
+    return {"p":p, "c":c};
+}
+
+
+function khCreateAllPairings(chromatic_scale_durations_unbiased,major_profile_unbiased,minor_profile_unbiased)
 {
     // chromatic_scale_durations.length = 12
@@ -45,11 +123,88 @@
 	var scale = chromatic_keys[s];
 
-	major_pairings[scale] = khCreatePairing(major_profile,chromatic_scale_durations,s);
-	minor_pairings[scale] = khCreatePairing(minor_profile,chromatic_scale_durations,s);
+	major_pairings[scale] = khCreatePairing(major_profile_unbiased,chromatic_scale_durations_unbiased,s);
+	minor_pairings[scale] = khCreatePairing(minor_profile_unbiased,chromatic_scale_durations_unbiased,s);
     }
 
     return {"major" : major_pairings, "minor" : minor_pairings};
-
-}
-
-
+}
+
+function khComputeKeyCorrelationCoefficients(key_pairings_unbiased)
+{
+    var correlations = {};
+
+    var keys = Object.keys(key_pairings_unbiased);
+    var keys_len = keys.length;
+
+    for (var k=0; k<keys_len; k++) {
+	
+	var key = keys[k];
+	var key_pairing_unbiased = key_pairings_unbiased[key];
+
+	var correlation_coeff = khCorrelationCoefficientUnbiased(key_pairing_unbiased.p,key_pairing_unbiased.c);
+	correlations[key] = correlation_coeff;
+    }
+
+    return correlations;
+}
+
+
+function khComputeAllCorrelationCoefficients(pairings_unbiased)
+{
+    var major_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.major);
+    var minor_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.minor);
+
+    return {"major" : major_correlation, "minor" : minor_correlation};
+}
+
+function khFindMaxCorrelation(alignments)
+{
+    var max_val = 0;
+    var max_key = null;
+
+    var major_minor = [ "major", "minor" ];
+
+    for (var m=0; m<major_minor.length; m++) {
+	var mm = major_minor[m];
+	var mm_alignment = alignments[mm];
+
+	var mm_keys = Object.keys(mm_alignment);
+
+	for (var k=0; k<mm_keys.length; k++) {
+	    var key = mm_keys[k];
+	    var correlation_coeff = mm_alignment[key];
+	    if (correlation_coeff>max_val) {
+		max_val = correlation_coeff;
+		max_key = key + " (" + mm + ")";
+	    }
+	}
+    }    
+	
+    return { "key": max_key, "score": max_val };
+}
+
+function khKeyDetection(chromatic_scale_durations)
+{
+    // Work out durations of MIDI events folded into octave (60=Middle-C)
+    // (unbiased data)
+
+    //var chromatic_scale_durations = [ 432, 231, 0, 405, 12, 316, 4, 126, 612, 0, 191, 1];
+    var chromatic_scale_durations_unbiased = khUnbiased(chromatic_scale_durations);
+
+    // Generate all (unbiased) pairings
+    var kh_pairings_unbiased = khCreateAllPairings(chromatic_scale_durations_unbiased,kh_major_profile_unbiased,kh_minor_profile_unbiased)
+
+    // Compute Correlation Coefficients
+    var kh_alignments = khComputeAllCorrelationCoefficients(kh_pairings_unbiased);
+
+    // Pick highest values
+    
+    var strongest_profile = khFindMaxCorrelation(kh_alignments);
+
+    console.log("Predicted Key: " + JSON.stringify(strongest_profile));
+
+    return strongest_profile;
+
+}
+
+
Index: /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/transform/pages/document.xsl
===================================================================
--- /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/transform/pages/document.xsl	(revision 29892)
+++ /main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/transform/pages/document.xsl	(revision 29893)
@@ -1315,6 +1315,19 @@
 
 <div>
+
   <div id='media-player' style="width: 96%">
 
+    <div class="about-bar">
+      <div id="about-titlebar" style="background-image: none; background-color: #2E52A4; width: 97%; float: left; margin-bottom: 10px; z-index: 4; position: relative;">
+	About: <xsl:call-template name="choose-title"/>
+      </div>
+
+      <div style="clear: both;"><xsl:comment>clear floats</xsl:comment></div>
+
+      <div id="about-area" class="documenttext" 
+	   style="display: none; position: absolute: left: 0px; top: 0px; z-index: 1;">
+	<xsl:call-template name="fingerprintMetadataBlock" />
+      </div>
+    </div>
 
     <div class="video-player-bar">
@@ -1917,4 +1930,6 @@
       <xsl:text disable-output-escaping="yes">
 	$(function(){
+  	  transformToTurnstyleBlock("about");
+
   	  transformToTurnstyleBlock("video");
   	  transformToTurnstyleBlock("playlist");
