File size: 6,995 Bytes
af6912c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<!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: Play On Repeat Demo</title>

	<style>
		main {
			max-width: 770px;
			margin: 0 auto;
		}
		.abcjs-cursor {
			stroke: red;
		}
	</style>

	<script src="../dist/abcjs-basic.js" type="text/javascript"></script>
	<script type="text/javascript">
		var abc = "T: Cooley's\n" +
			"%%barnumbers 1\n" +
			"M: 4/4\n" +
			"L: 1/8\n" +
			"R: reel\n" +
			"K: Emin\n" +
			"EBBA B2 EB|~B2 AB dBAG|FDAD BDAD|FDAD dAFD|\n" +
			"EBBA B2 EB|B2 AB defg|afe^c dBAF|DEFD E2 gf|\n" +
			"|eB B2 efge|eB B2 gedB|A2 FA DAFA|A2 FA defg|\n" +
			"eB B2 eBgB|eB B2 defg|afe^c dBAF|DEFD E2 D2||";
		var NUM_MEASURES = 16;
		var NUM_BEATS_PER_MEASURE = 4;
		var synth = new ABCJS.synth.CreateSynth();
		var startMeasure;
		var endMeasure;
		var timingCallbacks;

		function load() {
			// First draw the music - this supplies an object that has a lot of information about how to create the synth.
			// NOTE: If you want just the sound without showing the music, use "*" instead of "paper" in the renderAbc call.
			var visualObj = ABCJS.renderAbc("paper", abc, {
				responsive: "resize" })[0];

			var startAudioButton = document.querySelector(".activate-audio");
			var stopAudioButton = document.querySelector(".stop-audio");
			var explanationDiv = document.querySelector(".suspend-explanation");
			startMeasure = document.querySelector("#start-measure");
			endMeasure = document.querySelector("#end-measure");

			startAudioButton.addEventListener("click", function() {
				startAudioButton.setAttribute("style", "display:none;");
				explanationDiv.setAttribute("style", "opacity: 0;");
				if (ABCJS.synth.supportsAudio()) {
					stopAudioButton.setAttribute("style", "");

					// An audio context is needed - this can be passed in for two reasons:
					// 1) So that you can share this audio context with other elements on your page.
					// 2) So that you can create it during a user interaction so that the browser doesn't block the sound.
					// Setting this is optional - if you don't set an audioContext, then abcjs will create one.
					window.AudioContext = window.AudioContext ||
						window.webkitAudioContext ||
						navigator.mozAudioContext ||
						navigator.msAudioContext;
					var audioContext = new window.AudioContext();
					audioContext.resume().then(function () {
						// In theory the AC shouldn't start suspended because it is being initialized in a click handler, but iOS seems to anyway.

						synth.init({
							audioContext: audioContext,
							visualObj: visualObj
						}).then(function () {
							timingCallbacks = new ABCJS.TimingCallbacks(visualObj, {
								beatCallback: cursorControl.onBeat,
								eventCallback: cursorControl.onEvent
							});
							cursorControl.onStart();
							synth.prime().then(function () {
								var start = (startMeasure.value - 1) / NUM_MEASURES;
								synth.seek(start);
								timingCallbacks.setProgress(start);
								synth.start();
								timingCallbacks.start();
							});
						}).catch(function (error) {
							console.log("Audio Failed", error);
						});
					});
				} else {
					var audioError = document.querySelector(".audio-error");
					audioError.setAttribute("style", "");
				}
			});

			stopAudioButton.addEventListener("click", function() {
				startAudioButton.setAttribute("style", "");
				explanationDiv.setAttribute("style", "");
				stopAudioButton.setAttribute("style", "display:none;");
				synth.stop();
				timingCallbacks.stop();
			});
		}

		function CursorControl() {
			var self = this;

			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.onBeat = function(beatNumber, totalBeats, totalTime) {
				console.log(beatNumber)
				var end = (endMeasure.value-1) * NUM_BEATS_PER_MEASURE;
				if (beatNumber >= end) {
					var start = (startMeasure.value-1) / NUM_MEASURES;
					synth.seek(start);
					timingCallbacks.setProgress(start);
				}
			};
			self.onEvent = function(ev) {
				if (ev.measureStart && ev.left === null)
					return; // this was the second part of a tie across a measure line. Just ignore it.

				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();
	</script>
</head>
<body onload="load()">
  <header>
    <img src="https://paulrosen.github.io/abcjs/img/abcjs_comp_extended_08.svg" alt="abcjs logo">
    <h1>Play on Repeat</h1>
  </header>
  <div class="container">
    <main>
      <p>Demonstration of playing a selection of a tune in a loop. Set the start and end measures on the fly using the inputs.</p>
      <div>
      <label>Start Measure: <input type="number" min="1" max="16" id="start-measure" value="5"></label>
      <label>End Measure: <input type="number" min="1" max="16" id="end-measure" value="8"></label>
      </div>
      <div id="paper"></div>
      <p class="suspend-explanation">Browsers won't allow audio to work unless the audio is started in response to a user action. This prevents auto-playing web sites. Therefore, the
        following button is needed to do the initialization:</p>
      <button class="activate-audio">Activate Audio Context And Play</button>
      <button class="stop-audio" style="display:none;">Stop Audio</button>
      <div class='audio-error' style="display:none;">Audio is not supported in this browser.</div>
    </main>
  </div>
</body>
</html>