|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="utf-8"> |
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
|
<link rel="icon" href="favicon.ico" type="image/x-icon"/> |
|
|
<link rel="stylesheet" href="examples-styles.css"/> |
|
|
|
|
|
<title>abcjs: Microtone Demo</title> |
|
|
|
|
|
<link rel="stylesheet" type="text/css" href="../abcjs-audio.css"> |
|
|
<style> |
|
|
main { |
|
|
max-width: 770px; |
|
|
margin: 0 auto; |
|
|
} |
|
|
.highlight { |
|
|
fill: #0a9ecc; |
|
|
} |
|
|
.abcjs-cursor { |
|
|
stroke: red; |
|
|
} |
|
|
.click-explanation { |
|
|
color: red; |
|
|
font-style: italic; |
|
|
} |
|
|
.midi { |
|
|
margin-top: 20px; |
|
|
margin-left: 5px; |
|
|
} |
|
|
</style> |
|
|
|
|
|
<script src="../dist/abcjs-basic.js" type="text/javascript"></script> |
|
|
<script type="text/javascript"> |
|
|
|
|
|
function CursorControl() { |
|
|
var self = this; |
|
|
|
|
|
self.onReady = function() { |
|
|
var clickEl = document.querySelector(".click-explanation") |
|
|
clickEl.setAttribute("style", ""); |
|
|
}; |
|
|
self.onStart = function() { |
|
|
var svg = document.querySelector("#paper svg"); |
|
|
var cursor = document.createElementNS("http://www.w3.org/2000/svg", "line"); |
|
|
cursor.setAttribute("class", "abcjs-cursor"); |
|
|
cursor.setAttributeNS(null, 'x1', 0); |
|
|
cursor.setAttributeNS(null, 'y1', 0); |
|
|
cursor.setAttributeNS(null, 'x2', 0); |
|
|
cursor.setAttributeNS(null, 'y2', 0); |
|
|
svg.appendChild(cursor); |
|
|
|
|
|
}; |
|
|
self.onEvent = function(ev) { |
|
|
if (ev.measureStart && ev.left === null) |
|
|
return; |
|
|
|
|
|
var lastSelection = document.querySelectorAll("#paper svg .highlight"); |
|
|
for (var k = 0; k < lastSelection.length; k++) |
|
|
lastSelection[k].classList.remove("highlight"); |
|
|
|
|
|
for (var i = 0; i < ev.elements.length; i++ ) { |
|
|
var note = ev.elements[i]; |
|
|
for (var j = 0; j < note.length; j++) { |
|
|
note[j].classList.add("highlight"); |
|
|
} |
|
|
} |
|
|
|
|
|
var cursor = document.querySelector("#paper svg .abcjs-cursor"); |
|
|
if (cursor) { |
|
|
cursor.setAttribute("x1", ev.left - 2); |
|
|
cursor.setAttribute("x2", ev.left - 2); |
|
|
cursor.setAttribute("y1", ev.top); |
|
|
cursor.setAttribute("y2", ev.top + ev.height); |
|
|
} |
|
|
}; |
|
|
self.onFinished = function() { |
|
|
var els = document.querySelectorAll("svg .highlight"); |
|
|
for (var i = 0; i < els.length; i++ ) { |
|
|
els[i].classList.remove("highlight"); |
|
|
} |
|
|
var cursor = document.querySelector("#paper svg .abcjs-cursor"); |
|
|
if (cursor) { |
|
|
cursor.setAttribute("x1", 0); |
|
|
cursor.setAttribute("x2", 0); |
|
|
cursor.setAttribute("y1", 0); |
|
|
cursor.setAttribute("y2", 0); |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
var cursorControl = new CursorControl(); |
|
|
|
|
|
var abc = "X:1\n" + |
|
|
"T:مجنون نبودم\n" + |
|
|
"R:Moderato \n" + |
|
|
"Q:1/4=112\n" + |
|
|
"L:1/4\n" + |
|
|
"M:2/4\n" + |
|
|
"K: Bb _/A\n" + |
|
|
"F/G/ G/G/ | Gd|c/d/ B/c/|cd|c/d/ B/c/|\n" + |
|
|
"Bc|B/c/ A/B/|Gz|F,/G,/ G,/G,/|G,D| \n" + |
|
|
"C/D/ B,/C/| CD|C/D/ B,/C/|B,C|B,/C/ A,/B,/|\n" + |
|
|
"G,z/D/|CB,/C/|B, z/D/|CB,/C/|B,zD/|\n" + |
|
|
"CB,/C/|A,z/C/|B,A,/B,/|A,G,|:F/G//G// G/G/|\n" + |
|
|
"Gd|c/c//d// B/c/|cd|c/c//d// B/c/|Bc|\n" + |
|
|
"B/B//c// A/B/ |1Gz:|2G z/d/||cB/c/|Bz/d/|\n" + |
|
|
"cB/c/|Bz/d/|cB/c/|A z/c/|BA/B/|\n" + |
|
|
"AG/C/|Gz|]"; |
|
|
|
|
|
var currentTune = 0; |
|
|
|
|
|
var synthControl; |
|
|
|
|
|
function clickListener(abcElem, tuneNumber, classes, analysis, drag, mouseEvent) { |
|
|
var lastClicked = abcElem.midiPitches; |
|
|
if (!lastClicked) |
|
|
return; |
|
|
|
|
|
ABCJS.synth.playEvent(lastClicked, abcElem.midiGraceNotePitches, synthControl.visualObj.millisecondsPerMeasure()).then(function (response) { |
|
|
console.log("note played"); |
|
|
}).catch(function (error) { |
|
|
console.log("error playing note", error); |
|
|
}); |
|
|
} |
|
|
|
|
|
var abcOptions = { |
|
|
add_classes: true, |
|
|
clickListener: self.clickListener, |
|
|
responsive: "resize" |
|
|
}; |
|
|
|
|
|
var koron = { d: [ |
|
|
['M',0,-4], |
|
|
['l', 0, 20], |
|
|
['l', 1.5, 0], |
|
|
['l', 0, -12], |
|
|
['l', 8.5, -4], |
|
|
['l', -8.5, -4], |
|
|
['l', 0, 1.5], |
|
|
['l', 6, 2.5], |
|
|
['l', -6, 2.5], |
|
|
['l', 0, -6.5], |
|
|
['z']],w:10,h:20 |
|
|
}; |
|
|
|
|
|
var sori = { d: [ |
|
|
['M',0,-9], |
|
|
|
|
|
['m',3,0.82], |
|
|
['l',0, 19.18], |
|
|
['l', 1.70, 0], |
|
|
['l', 0, -19.18], |
|
|
['z'], |
|
|
|
|
|
|
|
|
['m',3.06,-0.82], |
|
|
['l',0, 19.18], |
|
|
['l', 1.7, 0], |
|
|
['l', 0, -19.18], |
|
|
['z'], |
|
|
|
|
|
|
|
|
['m', -6.06,3.2], |
|
|
['l', 3, 1.29], |
|
|
['l',0, 1.39], |
|
|
['l',-3,-1.29], |
|
|
['l',0,-1.39], |
|
|
['z'], |
|
|
['m', 4.7,1.95], |
|
|
['l', 1.25, .6], |
|
|
['l',0, 1.39], |
|
|
['l',-1.25,-.6], |
|
|
['l',0,-1.39], |
|
|
['z'], |
|
|
['m', 3,1.3], |
|
|
['l', 4.5, 2.5], |
|
|
['l', -2.25,0], |
|
|
['l',-2.2,-1.1], |
|
|
['l',0,-1.39], |
|
|
['z'], |
|
|
|
|
|
|
|
|
['m', 0,5], |
|
|
['l', 4.5, -2.5], |
|
|
['l', -2.25,0], |
|
|
['l',-2.2,1.1], |
|
|
['l',0,1.39], |
|
|
['z'], |
|
|
['m', -3,1.5], |
|
|
['l', 1.25, -.6], |
|
|
['l',0, -1.39], |
|
|
['l',-1.25,.6], |
|
|
['l',0,1.39], |
|
|
['z'], |
|
|
['m', -4.2,1.7], |
|
|
['l', 3, -1.29], |
|
|
['l',0, -1.39], |
|
|
['l',-3,1.29], |
|
|
['l',0,1.39], |
|
|
['z']],w:15,h:20 |
|
|
}; |
|
|
|
|
|
function load() { |
|
|
ABCJS.setGlyph('accidentals.halfflat', koron); |
|
|
ABCJS.setGlyph('accidentals.halfsharp', sori); |
|
|
|
|
|
if (ABCJS.synth.supportsAudio()) { |
|
|
synthControl = new ABCJS.synth.SynthController(); |
|
|
synthControl.load("#audio", cursorControl, {displayLoop: true, displayRestart: true, displayPlay: true, displayProgress: true, displayWarp: true}); |
|
|
} else { |
|
|
document.querySelector("#audio").innerHTML = "<div class='audio-error'>Audio is not supported in this browser.</div>"; |
|
|
} |
|
|
setTune(false); |
|
|
} |
|
|
|
|
|
function setTune(userAction) { |
|
|
synthControl.disable(true); |
|
|
var visualObj = ABCJS.renderAbc("paper", abc, abcOptions)[0]; |
|
|
var midi = ABCJS.synth.getMidiFile(abc, { fileName: "i-was-not-insane.midi"}); |
|
|
var midiButton = document.querySelector(".midi"); |
|
|
midiButton.innerHTML = midi; |
|
|
|
|
|
var midiBuffer = new ABCJS.synth.CreateSynth(); |
|
|
midiBuffer.init({ |
|
|
|
|
|
visualObj: visualObj, |
|
|
|
|
|
|
|
|
|
|
|
options: { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
}).then(function (response) { |
|
|
if (synthControl) { |
|
|
synthControl.setTune(visualObj, userAction).then(function (response) { |
|
|
console.log("Audio successfully loaded.") |
|
|
}).catch(function (error) { |
|
|
console.warn("Audio problem:", error); |
|
|
}); |
|
|
} |
|
|
}).catch(function (error) { |
|
|
console.warn("Audio problem:", error); |
|
|
}); |
|
|
} |
|
|
|
|
|
</script> |
|
|
</head> |
|
|
<body onload="load()"> |
|
|
<header> |
|
|
<img src="https://paulrosen.github.io/abcjs/img/abcjs_comp_extended_08.svg" alt="abcjs logo"> |
|
|
<h1>Microtone Demo</h1> |
|
|
</header> |
|
|
<div class="container"> |
|
|
<main> |
|
|
<p>This is a tune with a non-traditional note (the A half sharp).</p> |
|
|
<p>You can play the tune with the audio control, click on individual notes to hear them, and download it as a MIDI file.</p> |
|
|
<div class="midi">MIDI</div> |
|
|
<div id="paper"></div> |
|
|
<div id="audio"></div> |
|
|
<p class="click-explanation" style="display:none;">Click on a note to play that note.</p> |
|
|
</main> |
|
|
</div> |
|
|
</body> |
|
|
</html> |
|
|
|