Changeset 29893

Show
Ignore:
Timestamp:
18.05.2015 16:42:17 (4 years ago)
Author:
davidb
Message:

Completed version of Krumhansl's algorithm. Plus adding in of About bar. Plus tidy up of the 'by xxx' template

Location:
main/trunk/model-sites-dev/respooled/collect/popup-video-respooled
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/etc/collectionConfig.xml

    r29890 r29893  
    1717        <displayItem assigned="true" lang="en" name="section">section</displayItem> 
    1818    </displayItemList> 
    19     <format>  <gsf:template name="choose-title"> 
     19    <format>   
     20      <gsf:template name="choose-title"> 
    2021    <gsf:choose-metadata> 
    2122      <gsf:metadata name="dc.Title"/> 
     
    2728      <gsf:default>Untitled</gsf:default> 
    2829    </gsf:choose-metadata> 
     30 
     31<xsl:text> </xsl:text> 
     32 
    2933    <gsf:switch> 
    30       <gsf:metadata name="dc.Creator"/> 
     34      <gsf:metadata name="dc.Description"/> 
    3135      <gsf:when test="exists"> 
    32         <gsf:switch> 
    33           <gsf:metadata name="dc.Description"/> 
    34           <gsf:when test="notEquals" test-value="Unknown"> 
    35   
    36               <gsf:metadata name="dc.Description"/> 
    37  
    38           </gsf:when> 
    39         </gsf:switch> 
     36    <gsf:metadata name="dc.Description"/> 
    4037      </gsf:when> 
    4138    </gsf:switch> 
     
    249246</xsl:call-template> 
    250247--> 
     248<!-- 
    251249    <h3> 
    252250      <xsl:call-template name="choose-title"/> 
    253251    </h3> 
     252--> 
     253 
    254254  </gsf:template> 
    255255<!-- 
     
    336336    <gsf:script src="{$httpCollection}/js/jquery.qtip.min.js"/> 
    337337    <gsf:script src="{$httpCollection}/js/qtip-popups.js"/> 
     338 
     339    <gsf:script src="{$httpCollection}/js/key-detection.js"/> 
     340 
    338341<!-- 
    339342MIDI.js library 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/game-on.js

    r29888 r29893  
    8888} 
    8989 
     90 
     91function computeMidiStats(track) 
     92{ 
     93    var min_midi_pitch = num_midi_pitches-1; 
     94    var max_midi_pitch = 0; 
     95 
     96    var track_chromatic_durations = []; 
     97    for (var i=0; i<12; i++) { 
     98    track_chromatic_durations[i] = 0; 
     99    } 
     100 
     101    // Process each block within the track 
     102    for (var b=0; b<track.length; b++) { 
     103    var track_block = track[b]; 
     104    //var base_ctime = track_block.baseCTime; 
     105    var block_events = track_block.events; 
     106 
     107    var block_chromatic_durations = []; 
     108    for (var i=0; i<12; i++) { 
     109        block_chromatic_durations[i] = 0; 
     110    } 
     111     
     112    for (var ne=0; ne<block_events.length; ne++) { 
     113        var midi_pitch = block_events[ne].midiPitch; 
     114 
     115        if (midi_pitch < min_midi_pitch) { 
     116        min_midi_pitch = midi_pitch; 
     117        } 
     118        if (midi_pitch > max_midi_pitch) { 
     119        max_midi_pitch = midi_pitch; 
     120        } 
     121 
     122        var chromatic_pitch = midi_pitch % 12; 
     123        var chromatic_duration = block_events[ne].duration; 
     124        block_chromatic_durations[chromatic_pitch] += chromatic_duration; 
     125 
     126        track_chromatic_durations[chromatic_pitch] += chromatic_duration; 
     127    } 
     128 
     129    if (!("_computedKey" in track_block)) { 
     130        var strongest_profile = khKeyDetection(block_chromatic_durations); 
     131        track_block._computedKey = strongest_profile; 
     132        console.log("***### key prediction: " + strongest_profile); 
     133    } 
     134 
     135    } 
     136 
     137    if (!("_computedKey" in track)) { 
     138    var strongest_profile = khKeyDetection(track_chromatic_durations); 
     139    track._computedKey = strongest_profile; 
     140    } 
     141 
     142    return { "max_midi_pitch": max_midi_pitch, "min_midi_pitch": min_midi_pitch}; 
     143} 
     144 
     145 
    90146function displayActiveTrackLayers(docStorage) 
    91147{ 
     
    116172        if (track != null) { 
    117173 
     174 
     175        var midi_stats = computeMidiStats(track); 
     176 
     177        if (midi_stats.min_midi_pitch < min_midi_pitch) { 
     178            min_midi_pitch = midi_stats.min_midi_pitch; 
     179        } 
     180        if (midi_stats.max_midi_pitch > max_midi_pitch) { 
     181            max_midi_pitch = midi_stats.max_midi_pitch; 
     182        } 
     183 
     184 
    118185        // calculate range of midi pitches present 
     186/* 
    119187        for (var b=0; b<track.length; b++) { 
    120188            var track_block = track[b]; 
     
    132200            } 
    133201        } 
     202*/ 
     203 
    134204        } 
    135205    } 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/key-detection.js

    r29892 r29893  
    11"use strict"; 
    22 
    3 // From: 
     3// Key detection algorithm, as described at: 
    44//  http://rnhart.net/articles/key-finding/ 
     5 
     6// (from this web site) .... 
     7//  Krumhansl-Schmuckler key-finding algorithm (by Carol L. Krumhansl 
     8//  and Mark A. Schmuckler). The profile numbers came from experiments 
     9//  done by Krumhansl and Edward J. Kessler. The experiments consisted 
     10//  of playing a set of context tones or chords, playing a probe tone, 
     11//  and asking a listener to rate how well the probe tone fit with the 
     12//  context. You can read about the experiments and the algorithm in 
     13//  Krumhansl's book Cognitive Foundations of Musical Pitch. (The 
     14//  experiments are described in Chapter 2. The key-finding algorithm 
     15//  is described in Chapter 4.) You may be able to read portions of 
     16//  the book on Google Books. 
     17 
     18 
     19function khMean(vals)  
     20{ 
     21    var len = vals.length; 
     22    if (len==0) { 
     23    return 0; 
     24    } 
     25 
     26    var total = 0; 
     27 
     28    for (var i=0; i<len; i++) { 
     29    total += vals[i]; 
     30    } 
     31 
     32    return total/len; 
     33} 
     34 
     35function khUnbiased(vals)  
     36{ 
     37    var unbiased_vals = []; 
     38 
     39    var len = vals.length; 
     40    if (len==0) { 
     41    return unbiased_vals; 
     42    } 
     43 
     44    var avg = khMean(vals); 
     45 
     46    for (var i=0; i<len; i++) { 
     47    unbiased_vals.push(vals[i] - avg) 
     48    } 
     49 
     50    return unbiased_vals; 
     51} 
     52 
     53 
     54function khCorrelationCoefficientUnbiased(a1,a2) 
     55{ 
     56    var a1_len = a1.length; 
     57    var a2_len = a2.length; 
     58    
     59    if (a1_len != a2_len) { 
     60    throw "khCorrelationCoefficientUnbiased(): arrays should be of the same length (" + a1_len + " vs " + a2_len + ")"; 
     61    } 
     62    var len = a1_len; 
     63 
     64    var a1_a2_pair_prod = 0; 
     65    var a1_square = 0; 
     66    var a2_square = 0; 
     67 
     68    for (var i=0; i<len; i++) { 
     69    a1_a2_pair_prod += (a1[i]*a2[i]); 
     70    a1_square += (a1[i]*a1[i]); 
     71    a2_square += (a2[i]*a2[i]);  
     72    } 
     73 
     74    return a1_a2_pair_prod / Math.sqrt(a1_square * a2_square); 
     75} 
     76 
    577 
    678//major profile 
     
    1991var 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 ]; 
    2092 
     93var kh_major_profile_unbiased = khUnbiased(kh_major_profile); 
     94 
     95var kh_minor_profile_unbiased = khUnbiased(kh_minor_profile); 
     96 
    2197 
    2298function khCreatePairing(profile,chromatic_scale_durations,offset) 
    2399{ 
    24     var pairing = []; 
    25     for (var p=0; p<12; p++) { 
    26     pairing.push({"p":profile[p],"c":chromatic_scale_durations[(p+s)%12]}); 
     100    var p = []; 
     101    var c = []; 
     102    for (var i=0; i<12; i++) { 
     103    p.push(profile[i]) 
     104    c.push(chromatic_scale_durations[(i+offset)%12]); 
    27105    } 
    28106     
    29107 
    30     return pairing; 
    31 } 
    32  
    33  
    34 function khCreateAllPairings(chromatic_scale_durations,major_profile,minor_profile) 
     108    return {"p":p, "c":c}; 
     109} 
     110 
     111 
     112function khCreateAllPairings(chromatic_scale_durations_unbiased,major_profile_unbiased,minor_profile_unbiased) 
    35113{ 
    36114    // chromatic_scale_durations.length = 12 
     
    45123    var scale = chromatic_keys[s]; 
    46124 
    47     major_pairings[scale] = khCreatePairing(major_profile,chromatic_scale_durations,s); 
    48     minor_pairings[scale] = khCreatePairing(minor_profile,chromatic_scale_durations,s); 
     125    major_pairings[scale] = khCreatePairing(major_profile_unbiased,chromatic_scale_durations_unbiased,s); 
     126    minor_pairings[scale] = khCreatePairing(minor_profile_unbiased,chromatic_scale_durations_unbiased,s); 
    49127    } 
    50128 
    51129    return {"major" : major_pairings, "minor" : minor_pairings}; 
    52  
    53 } 
    54  
    55  
     130} 
     131 
     132function khComputeKeyCorrelationCoefficients(key_pairings_unbiased) 
     133{ 
     134    var correlations = {}; 
     135 
     136    var keys = Object.keys(key_pairings_unbiased); 
     137    var keys_len = keys.length; 
     138 
     139    for (var k=0; k<keys_len; k++) { 
     140     
     141    var key = keys[k]; 
     142    var key_pairing_unbiased = key_pairings_unbiased[key]; 
     143 
     144    var correlation_coeff = khCorrelationCoefficientUnbiased(key_pairing_unbiased.p,key_pairing_unbiased.c); 
     145    correlations[key] = correlation_coeff; 
     146    } 
     147 
     148    return correlations; 
     149} 
     150 
     151 
     152function khComputeAllCorrelationCoefficients(pairings_unbiased) 
     153{ 
     154    var major_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.major); 
     155    var minor_correlation = khComputeKeyCorrelationCoefficients(pairings_unbiased.minor); 
     156 
     157    return {"major" : major_correlation, "minor" : minor_correlation}; 
     158} 
     159 
     160function khFindMaxCorrelation(alignments) 
     161{ 
     162    var max_val = 0; 
     163    var max_key = null; 
     164 
     165    var major_minor = [ "major", "minor" ]; 
     166 
     167    for (var m=0; m<major_minor.length; m++) { 
     168    var mm = major_minor[m]; 
     169    var mm_alignment = alignments[mm]; 
     170 
     171    var mm_keys = Object.keys(mm_alignment); 
     172 
     173    for (var k=0; k<mm_keys.length; k++) { 
     174        var key = mm_keys[k]; 
     175        var correlation_coeff = mm_alignment[key]; 
     176        if (correlation_coeff>max_val) { 
     177        max_val = correlation_coeff; 
     178        max_key = key + " (" + mm + ")"; 
     179        } 
     180    } 
     181    }     
     182     
     183    return { "key": max_key, "score": max_val }; 
     184} 
     185 
     186function khKeyDetection(chromatic_scale_durations) 
     187{ 
     188    // Work out durations of MIDI events folded into octave (60=Middle-C) 
     189    // (unbiased data) 
     190 
     191    //var chromatic_scale_durations = [ 432, 231, 0, 405, 12, 316, 4, 126, 612, 0, 191, 1]; 
     192    var chromatic_scale_durations_unbiased = khUnbiased(chromatic_scale_durations); 
     193 
     194    // Generate all (unbiased) pairings 
     195    var kh_pairings_unbiased = khCreateAllPairings(chromatic_scale_durations_unbiased,kh_major_profile_unbiased,kh_minor_profile_unbiased) 
     196 
     197    // Compute Correlation Coefficients 
     198    var kh_alignments = khComputeAllCorrelationCoefficients(kh_pairings_unbiased); 
     199 
     200    // Pick highest values 
     201     
     202    var strongest_profile = khFindMaxCorrelation(kh_alignments); 
     203 
     204    console.log("Predicted Key: " + JSON.stringify(strongest_profile)); 
     205 
     206    return strongest_profile; 
     207 
     208} 
     209 
     210 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/transform/pages/document.xsl

    r29890 r29893  
    13151315 
    13161316<div> 
     1317 
    13171318  <div id='media-player' style="width: 96%"> 
    13181319 
     1320    <div class="about-bar"> 
     1321      <div id="about-titlebar" style="background-image: none; background-color: #2E52A4; width: 97%; float: left; margin-bottom: 10px; z-index: 4; position: relative;"> 
     1322    About: <xsl:call-template name="choose-title"/> 
     1323      </div> 
     1324 
     1325      <div style="clear: both;"><xsl:comment>clear floats</xsl:comment></div> 
     1326 
     1327      <div id="about-area" class="documenttext"  
     1328       style="display: none; position: absolute: left: 0px; top: 0px; z-index: 1;"> 
     1329    <xsl:call-template name="fingerprintMetadataBlock" /> 
     1330      </div> 
     1331    </div> 
    13191332 
    13201333    <div class="video-player-bar"> 
     
    19171930      <xsl:text disable-output-escaping="yes"> 
    19181931    $(function(){ 
     1932      transformToTurnstyleBlock("about"); 
     1933 
    19191934      transformToTurnstyleBlock("video"); 
    19201935      transformToTurnstyleBlock("playlist");