music21j-port
Version:
A toolkit for computer-aided musicology, Javascript version
213 lines (195 loc) • 7.62 kB
HTML
<html><head>
<title>Match pitches</title>
<script data-main="../src/music21" src="../ext/require/require.js"></script>
<link rel="stylesheet" href="http://web.mit.edu/music21/doc/_static/m21.css" type="text/css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Open+Sans:300italic,400italic,700italic,400,300,700" type="text/css" />
<script>
require(['music21'], function (music21) {
nnn = new music21.note.Note("C4");
nnn.duration.type = 'whole';
ng = new music21.note.Note("C4");
ng.duration.type = 'whole';
sg = new music21.stream.Stream();
sg.tempo = 240;
sg.clef = new music21.clef.Clef('treble');
sg.append(ng);
sg.renderOptions.scaleFactor = {x: 1.5, y: 1.5};
sg.appendNewDOM('#givenSVGDiv');
sss = new music21.stream.Stream();
sss.clef = new music21.clef.Clef('treble');
sss.append(nnn);
sss.renderOptions.scaleFactor = {x: 1.5, y: 1.5};
sss.appendNewDOM('#SVGDiv');
playNotes = true;
$('#playNotes').on('click', function() {
playNotes = true;
});
$('#muteNotes').on('click', function() {
playNotes = false;
});
keyOfC = true;
$('#naturals').on('click', function() {
keyOfC = true;
});
$('#accidentals').on('click', function() {
keyOfC = false;
});
$('#startListening').on('click', function () {
playingGame = true;
randNote();
music21.audioSearch.getUserMedia()
});
$('#stopListening').on('click', function () {
playingGame = false;
window.cancelAnimationFrame(music21.audioSearch.animationFrameCallbackId);
});
$nn = $('#noteName');
$centsDiv = $('#centsDiv');
$counter = $('#counter');
minPitch = new music21.pitch.Pitch('C4');
maxPitch = new music21.pitch.Pitch('C5');
expectedMidi = 60;
randNote = function() {
var randomRange = maxPitch.midi - minPitch.midi;
var rn = Math.round(Math.random() * randomRange) + minPitch.midi;
var p = new music21.pitch.Pitch(rn);
var counter = 0;
while (expectedMidi == rn
|| (p.accidental
&& p.accidental.alter != 0
&& keyOfC)) {
rn = Math.round(Math.random() * randomRange) + minPitch.midi
p = new music21.pitch.Pitch(rn);
}
ng.pitch = p;
expectedMidi = rn;
sg.replaceDOM('#givenSVGDiv');
}
$('#bassClef').on('click', function () {
sss.clef = new music21.clef.Clef('bass');
sg.clef = new music21.clef.Clef('bass');
minPitch = new music21.pitch.Pitch('C3');
maxPitch = new music21.pitch.Pitch('C4');
music21.audioSearch.minFrequency = minPitch.frequency;
music21.audioSearch.maxFrequency = maxPitch.frequency;
randNote();
sss.replaceDOM();
});
$('#trebleClef').on('click', function () {
sss.clef = new music21.clef.Clef('treble');
sg.clef = new music21.clef.Clef('treble');
minPitch = new music21.pitch.Pitch('B-3');
maxPitch = new music21.pitch.Pitch('B-4');
music21.audioSearch.minFrequency = minPitch.frequency;
music21.audioSearch.maxFrequency = maxPitch.frequency;
randNote();
sss.replaceDOM();
}).click();
var lastNote = 0;
var lastLeft = 150;
var consecutiveRight = 0;
var triggerRight = 20;
var playingGame = false;
sss.renderOptions.events.click = undefined;
sg.renderOptions.events.click = (function () {
consecutiveRight = 0;
if (playingGame) {
playingGame = false;
sg.playStream();
setTimeout(function() {
console.log('again!');
playingGame = true;
music21.audioSearch.animateLoop() }, 1000);
} else {
sg.playStream();
}
}).bind(sg);
newNote = function() {
randNote();
consecutiveRight = 0;
if (playNotes) {
sg.playStream();
}
if (playingGame) {
playingGame = false;
setTimeout(function() {
console.log('again!');
playingGame = true;
music21.audioSearch.animateLoop() }, 1000);
}
}
sampleCallback = function(frequency) {
if (playingGame == false) {
return -1;
}
var _ = music21.audioSearch.smoothPitchExtraction(frequency),
midiNum = _[0],
centsOff = _[1];
if (midiNum != -1) {
if (midiNum != lastNote) {
lastNote = midiNum;
var p = new music21.pitch.Pitch(midiNum);
var a = p.accidental;
var name = p.step;
if (a !== undefined && a.alter !== 0) {
name += "<span style='font-size: 70%; position: relative; left: -10px; margin-right: -20px'>" + a.unicodeModifier + "</span>";
}
name += p.octave.toString();
nnn.pitch = p
sss.replaceCanvas();
}
if (midiNum == expectedMidi) {
consecutiveRight += 1;
if (consecutiveRight > triggerRight) {
newNote();
return -1; // cancel
}
} else {
consecutiveRight -= 1;
if (consecutiveRight < 0) {
consecutiveRight = 0;
}
}
// 0 = red; 120 = green; 240 = blue
var hue = ((-1 * centsOff) + 50) * 2.4;
// highly saturated at the extremes;
var saturation = Math.round(50 + 2 * Math.abs(Math.abs(centsOff) - 25));
var colorString = 'hsl(' + hue + ', ' + saturation + '%, 50%)';
var newLeft = 3*(50+centsOff);
lastLeft = (lastLeft*9 + newLeft)/10;
$counter.css('background-color', colorString)
.css('left', lastLeft.toString() + 'px');
}
};
music21.audioSearch.sampleCallback = sampleCallback;
});
</script>
</head>
<body style='text-align: left;'>
<div style='padding-left: 20px; background-color: white'>
<h1>Match pitches</h1>
<h2>Needs Chrome, Firefox, MS Edge, or Safari 11.</h2>
<button id='startListening'>Start Listening</button>
<button id='stopListening'>Stop Listening</button>
<button id='bassClef'>Bass</button>
<button id='trebleClef'>Treble</button>
<button id='naturals'>Key of C</button>
<button id='accidentals'>Use Accidentals (Harder)</button>
<button id='playNotes'>Play Notes</button>
<button id='muteNotes'>Don't Play Notes (Harder)</button><br/>
<div id='given' style='float: left'>
<div id='givenSVGDiv' style='margin-left: 80px'></div>
</div>
<div id='userAgent' style='float: left'>
<div id='SVGDiv' style='margin-left: 80px'></div>
<div id='counterHolder' style='position: relative; text-align: center; border: 1px solid black; width: 340px'>
<div id='counter' style='position: relative; width: 40px; background-color: white; height: 30px'> </div>
</div>
</div>
<br>
<br>
<br>
<br>
</div>
</body>
</html>