UNPKG

music21j-port

Version:

A toolkit for computer-aided musicology, Javascript version

213 lines (195 loc) 7.62 kB
<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'>&nbsp;</div> </div> </div> &nbsp;<br> &nbsp;<br> &nbsp;<br> &nbsp;<br> </div> </body> </html>