File size: 5,799 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
<!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="stylesheet" href="examples-styles.css"/>

	<link rel="icon" href="favicon.ico" type="image/x-icon"/>
	<title>abcjs: Basic Synth Demo</title>

	<style>
		main {
			max-width: 770px;
			margin: 0 auto;
		}
		.row {
			display: flex;
			justify-content: space-between;
			align-items: flex-start;
		}
		.status {
			padding: 2px 10px 10px 10px;
			background-color: #f0f0f0;
			width:250px;
		}
        @media (prefers-color-scheme: dark) {
            .status {
                background-color: #000000;
            }
        }
	</style>

	<script src="../dist/abcjs-basic.js" type="text/javascript"></script>
	<script type="text/javascript">
		var abc = "T: Cooley's\n" +
			"M: 4/4\n" +
			"L: 1/8\n" +
			"R: reel\n" +
			"K: Emin\n" +
			"|:D2|EB{c}BA B2 EB|~B2 AB dBAG|FDAD BDAD|FDAD dAFD|\n" +
			"EBBA B2 EB|B2 AB defg|afe^c dBAF|DEFD E2:|\n" +
			"|:gf|eB B2 efge|eB B2 gedB|A2 FA DAFA|A2 FA defg|\n" +
			"eB B2 eBgB|eB B2 defg|afe^c dBAF|DEFD E2:|";

		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];

			// This object is the class that will contain the buffer
			var midiBuffer;

			var startAudioButton = document.querySelector(".activate-audio");
			var stopAudioButton = document.querySelector(".stop-audio");
			var explanationDiv = document.querySelector(".suspend-explanation");
			var statusDiv = document.querySelector(".status");

			startAudioButton.addEventListener("click", function() {
				startAudioButton.setAttribute("style", "display:none;");
				explanationDiv.setAttribute("style", "opacity: 0;");
				statusDiv.innerHTML = "<div>Testing browser</div>";
				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 () {
						statusDiv.innerHTML += "<div>AudioContext resumed</div>";
						// In theory the AC shouldn't start suspended because it is being initialized in a click handler, but iOS seems to anyway.

						// This does a bare minimum so this object could be created in advance, or whenever convenient.
						midiBuffer = new ABCJS.synth.CreateSynth();

						// midiBuffer.init preloads and caches all the notes needed. There may be significant network traffic here.
						return midiBuffer.init({
							visualObj: visualObj,
							audioContext: audioContext,
							millisecondsPerMeasure: visualObj.millisecondsPerMeasure()
						}).then(function (response) {
							console.log("Notes loaded: ", response)
							statusDiv.innerHTML += "<div>Audio object has been initialized</div>";
							// console.log(response); // this contains the list of notes that were loaded.
							// midiBuffer.prime actually builds the output buffer.
							return midiBuffer.prime();
						}).then(function (response) {
							statusDiv.innerHTML += "<div>Audio object has been primed (" + response.duration + " seconds).</div>";
							statusDiv.innerHTML += "<div>status = " + response.status + "</div>"
							// At this point, everything slow has happened. midiBuffer.start will return very quickly and will start playing very quickly without lag.
							midiBuffer.start();
							statusDiv.innerHTML += "<div>Audio started</div>";
							return Promise.resolve();
						}).catch(function (error) {
							if (error.status === "NotSupported") {
								stopAudioButton.setAttribute("style", "display:none;");
								var audioError = document.querySelector(".audio-error");
								audioError.setAttribute("style", "");
							} else
								console.warn("synth error", 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;");
				if (midiBuffer)
					midiBuffer.stop();
			});
		}
	</script>
</head>
<body onload="load()">
<main>
  <header>
    <img src="https://paulrosen.github.io/abcjs/img/abcjs_comp_extended_08.svg" alt="abcjs logo">
    <h1>Basic Synth</h1>
  </header>
	<div class="container">
		<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>
		<div class="row">
			<div>
				<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>
			</div>
			<div class="status"></div>
		</div>
	</div>
</main>
</body>
</html>