Changeset 29893


Ignore:
Timestamp:
05/18/15 16:42:17 (6 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 edited

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");
Note: See TracChangeset for help on using the changeset viewer.