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
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
e = s => document.getElementById(s);
n2n = n => ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"][n];
let ans = false;
let nq = 0;
let nc = 0;
function init()
{
e("gench").disabled = false;
e("response").style.display = "none";
e("prompt").innerHTML = " ";
reset_stats();
loadTheme();
}
function play_notes(freq, t, arpt)
{
const stop_notes = function(g, o)
{
o.stop();
g.disconnect(audioCtx.destination);
o.disconnect(g);
}
const play_note = function(f)
{
const gn = audioCtx.createGain();
gn.gain.setValueAtTime(.5 / freq.length, audioCtx.currentTime);
gn.gain.linearRampToValueAtTime(0, audioCtx.currentTime + t / 1000.);
gn.connect(audioCtx.destination);
const osc = audioCtx.createOscillator();
osc.type = "sine";
osc.frequency.setValueAtTime(f, audioCtx.currentTime);
osc.connect(gn);
osc.start();
setTimeout(stop_notes.bind(null, gn, osc), t);
}
let i=0;
freq.forEach(function(f){setTimeout(play_note.bind(null, f), arpt * (i++));});
}
get_freq = n => 440 * Math.pow(Math.pow(2, 1. / 12), n - 69)
function generate_challenge()
{
const nmin=Number(e("minnnotes").value);
const nmax=Number(e("maxnnotes").value);
const omin=Number(e("minorange").value);
const omax=Number(e("maxorange").value);
if (omax < omin || nmax < nmin)
{
alert("?");
return;
}
const nnotes = Math.floor(Math.random() * (nmax - nmin + 1)) + nmin;
const minrange = 60 + omin * 12;
const maxrange = 71 + omax * 12;
let f = [];
let l = [];
ans = false;
if (Math.random() < 0.3)
{
const o = Math.floor(Math.random() * (omax - omin + 1)) + omin;
let n = 60 + Number(e("note").value) + o * 12;
f.push(get_freq(n));
l.push(n);
ans = true;
}
while (f.length < nnotes)
{
let n = Math.floor(Math.random() * (maxrange - minrange + 1)) + minrange;
if (l.indexOf(n) != -1)
continue;
ans |= ((n % 12) == Number(e("note").value));
f.push(get_freq(n));
}
f.sort((a,b)=>a - b);
play_notes(f, 1000, e("arp").checked ? 50 : 0);
e("gench").disabled = true;
e("response").style.display = "";
e("prompt").innerHTML = nnotes == 1 ? `Was the note you just heard ${n2n(Number(e("note").value))}?`
: `Did the chord you just heard contain the note ${n2n(Number(e("note").value))}?`;
}
function update_stats()
{
e("stats").innerHTML = `You got ${nc} of the ${nq} challenges correct.`;
}
function reset_stats()
{
nq = nc = 0;
update_stats();
}
function check_yes()
{
if (ans)
++nc;
++nq;
e("gench").disabled = false;
e("response").style.display="none";
update_stats();
}
function check_no()
{
if (!ans)
++nc;
++nq;
e("gench").disabled = false;
e("response").style.display="none";
update_stats();
}
|