-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
118 lines (113 loc) · 3.93 KB
/
index.html
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
<!DOCTYPE html>
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<title>Guitar-Simulator Demo</title>
<style>
body {
font-family: Arial, Helvetica, sans-serif;
margin: 30px;
}
.string-box {
float: right;
width: 110px;
margin-left: 20px;
margin-bottom: 20px;
}
.string {
border: 2px solid #444;
border-radius: 5px;
margin: 5px;
padding: 5px 15px;
width: 80px;
height: 100px;
display: flex;
align-items: center;
}
.note-text {
display: inline-block;
width: 40px;
}
.note-svg {
width: 60px;
height: 90px;
}
</style>
<body>
<div class="string-box">
<div class="string" id="e-string"></div>
<div class="string" id="b-string"></div>
<div class="string" id="g-string"></div>
<div class="string" id="d-string"></div>
</div>
<h1>Guitar-Simulator Demo</h1>
<p>
This demo simulates 4 strings of a guitar,
each mapped to one row of keys on your keyboard:
<ul>
<li>The e string on the number row (1, 2, 3, 4, ...)</li>
<li>The b string on the next row (Q, W, E, R, ...)</li>
<li>The g string on the next row (A, S, D, F, ...)</li>
<li>The d string on the next row (Z, X, C, V, ...)</li>
</ul>
Your keyboard layout may differ.
In any case, the effect of pressing a key should be determined by its
position, not the associated character.
</p>
<p>
The first key in each row plays the open string while the subsequent
keys correspond to the frets.
Note that key shapes and positions at the right ends of the rows
vary across keyboards.
So there the mapping from keys to notes might not fully fit.
</p>
<p>
A string is "picked" by pressing a key
and the corresponding note will play until
you release the key,
you press another key for the same string,
or the string's vibration has faded out after some time.
While you cannot play more than one note at a time on a single string,
it is possible to play multiple notes on different strings simultaneously
(as far as your keyboard properly reports multiple key presses/releases).
</p>
<p>
For each string the currently playing note is displayed
in one of the boxes to the right.
</p>
<p>
Most browsers do not allow web pages to emit sound
before you have interacted with the page
(and keyboard input does not count).
So click this button to enable audio output:
<button id="resumeAudio">Start Audio</button>
</p>
<h2>Implementation notes</h2>
<p>
The purpose of this demo was to experiment with sound generation
in an <code>AudioWorkletNode</code>.
(See <a href="https://github.com/hcschuetz/guitar-simulation/blob/main/index.js" target="_blank" rel="noopener noreferrer">here</a>
for the main JavaScript code and
<a href="https://github.com/hcschuetz/guitar-simulation/blob/main/StringWorklet.js" target="_blank" rel="noopener noreferrer">here</a>
for the worklet processor code. Furthermore
<a href="https://github.com/hcschuetz/guitar-simulation/blob/main/note-display.js" target="_blank" rel="noopener noreferrer">here</a>
is the code for drawing the notes.)
</p>
<p>
There is one long-lived worklet node per string. Picking and damping
works by sending messages.
</p>
<p>
The code simulates a string sound
by superimposing multiple harmonics, each of which is a decaying sine wave.
While the actual sound generation by the worklet processor
happens in the audio thread,
the parameters are calculated in the main JS thread.
</p>
<p>
As with real guitar strings higher harmonics decay faster than lower ones.
So over time a picked string changes
from an overtone-rich sound towards a pure sine wave.
You can play with the sound generator code to create even more realistic
string sounds or sounds of completely different instruments.
</p>
</body>
<script type="module" src="index.js"></script>