Skip to content

Instantly share code, notes, and snippets.

@joeberkovitz
Last active February 25, 2017 06:08
Show Gist options
  • Save joeberkovitz/c3b37e3d818d7f4df26f11c53e8c8328 to your computer and use it in GitHub Desktop.
Save joeberkovitz/c3b37e3d818d7f4df26f11c53e8c8328 to your computer and use it in GitHub Desktop.
<!doctype html>
<!--
Example of a DOM-based music notation application that assesses a user's ability
to identify the roots of randomly voiced triads. jQuery is used to manipulate a
a MusicXML DOM and to respond to user interaction gestures on the displayed notation.
-->
<html>
<head>
<title></title>
<script src="/assets/lib/jquery-1.10.2.js"></script>
<script src="/clientapi/2.0.0/nfclient.js"></script>
<script src="discoverYourRoots.js"></script>
<style>
body, button {
font-size: 24px;
}
#correct {
color: green;
}
#incorrect {
color: red;
}
</style>
</head>
<body>
<!-- HTML user interface for the application -->
<div class="actionList">
<button onclick="generateNewTriads()">Next Problem Set</button>
</div>
<div class="results">
Right: <span id="correct" class="counter"></span>
</div>
<div class="results">
Wrong: <span id="incorrect" class="counter"></span>
</div>
<!-- this element will hold the Noteflight score iframe -->
<div id="score1"></div>
<script>
var exercise;
// This section employs a Noteflight-based MusicXML DOM renderer and is the only viewer-specific
// aspect of this example. The rest of the code only interacts with the DOM, not with Noteflight.
NFClient.onViewerLoad = function() {
// Load the skeleton of the document as a MusicXML DOM and tell the viewer to show it.
// Ordinary AJAX load of a MusicXML file; it comes back as a DOM
$.ajax({url: 'exercise.xml', type: 'GET', dataType: 'xml'}).done(function(data) {
// Save the DOM for local use, and tell Noteflight to show it in the given iframe
exercise = data;
NFClient.viewScore(exercise, "score1");
});
}
// Refresh the right/wrong counter fields in the display above the score
var correct = 0;
var incorrect = 0;
function displayCounters() {
$('#correct').text(correct);
$('#incorrect').text(incorrect);
}
// Generate a new triad problem set by randomly octave-displacing the notes of a diatonic triad
// starting on a random note.
function generateNewTriads() {
// Clear the counters
correct = incorrect = 0;
displayCounters();
// Find and clear the first measure in the piece
var measure = $(exercise).find('measure').first();
measure.empty();
// Generate 4 quarter-note triads
for (var beat = 0; beat < 4; beat++) {
var initialStep = Math.floor(Math.random() * 7); // root pitch of triad
var triadStructure = [0, 2, 4]; // expressed in terms of diatonic scale steps from root
// Generate the 3 notes of the triad in the chord as MusicXML <note> elements
for (var i = 0; i < 3; i++) {
// Build the note element in jQuery. Tag the non-initial notes as parts of a chord.
var note = $("<note><type>quarter</type></note>");
if (i > 0) {
note.append("<chord/>");
}
// Include a randomly octave-displaced pitch element including the next note of the triad
var pitch = $("<pitch><step/><octave/></pitch>");
var octaveDisplacement = Math.floor(Math.random() * 3);
pitch.find("step").text("ABCDEFG".charAt((initialStep + triadStructure[i]) % 7));
pitch.find("octave").text(4 + octaveDisplacement);
note.append(pitch);
// Stick it into the measure
measure.append(note);
// Attach the appropriate event listener for clicks on root and non-root triad tones
if (i == 0) {
note.click(function(event) {
$(this).attr('color', '#009900'); // turn note green
correct++;
displayCounters(); // update counter
});
}
else {
note.click(function(event) {
$(this).attr('color', '#FF0000');
incorrect++;
displayCounters();
});
}
}
}
}
</script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<!-- MusicXML template for DOM programming example -->
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN"
"http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="2.0">
<work>
<work-title>Discover Your Roots</work-title>
</work>
<identification>
<encoding>
<software>Noteflight version 0.3.2</software>
<encoding-date>2016-04-06</encoding-date>
<supports attribute="new-system" element="print" type="no" value="no"/>
<supports attribute="new-page" element="print" type="no" value="no"/>
</encoding>
</identification>
<defaults>
<scaling>
<millimeters>2.5</millimeters>
<tenths>10</tenths>
</scaling>
<page-layout>
<page-height>1320</page-height>
<page-width>1020</page-width>
<page-margins type="both">
<left-margin>59.583333333333336</left-margin>
<right-margin>56.66666666666667</right-margin>
<top-margin>96.66666666666667</top-margin>
<bottom-margin>80</bottom-margin>
</page-margins>
</page-layout>
<system-layout>
<system-margins>
<left-margin>59.583333333333336</left-margin>
<right-margin>26.666666666666668</right-margin>
</system-margins>
<system-distance>92.5</system-distance>
<top-system-distance>145.83333333333334</top-system-distance>
</system-layout>
<staff-layout>
<staff-distance>55</staff-distance>
</staff-layout>
</defaults>
<part-list>
<score-part id="P1">
<part-name></part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>64</divisions>
<key>
<fifths>0</fifths>
<mode>major</mode>
</key>
<time print-object="no">
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef number="1">
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note id="rest1">
<rest/>
<duration>256</duration>
<voice>1</voice>
<type>whole</type>
</note>
</measure>
</part>
</score-partwise>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment