Ik ben nu al een goede 2 weken JavaScript aan het leren op mezelf en heb als oefening een 'audio frequency trainer' gemaakt. De applicatie geeft je een willekeurige frequentie en jij moet raden welke frequentie het is. Het kan evt. nuttig zijn voor beginnende geluidstechniekers (vb. om frequenties van feedbacks tijdens concerten / soundchecks sneller te herkennen), de frequenties zijn dan ook gebaseerd op die van de courante grafische equalisers.
De files (.js en .html) zijn elk zo'n 100 lijnen (dus nog niet zo ongelooflijk veel). Feedback is welkom op gelijk welk vlak: codestijl, organisatie van code, code die korter of duidelijker kan worden getypt of vervangen kan worden door iets dat sneller wordt uitgevoerd, namen van functies of variabelen die niet volledig duidelijk zijn, te veel of te weinig comments, lay-out die u niet aanstaat, enzv. ...
Omdat jullie waarschijnlijk allemaal een eigen voorkeur hebben van hoe je code nakijkt (online IDE, devtools in de browser, code downloaden en in eigen IDE openen, ...), heb ik een paar verschillende opties voor jullie:
De files (.js en .html) zijn elk zo'n 100 lijnen (dus nog niet zo ongelooflijk veel). Feedback is welkom op gelijk welk vlak: codestijl, organisatie van code, code die korter of duidelijker kan worden getypt of vervangen kan worden door iets dat sneller wordt uitgevoerd, namen van functies of variabelen die niet volledig duidelijk zijn, te veel of te weinig comments, lay-out die u niet aanstaat, enzv. ...
Omdat jullie waarschijnlijk allemaal een eigen voorkeur hebben van hoe je code nakijkt (online IDE, devtools in de browser, code downloaden en in eigen IDE openen, ...), heb ik een paar verschillende opties voor jullie:
- Linkje naar werkend voorbeeld op JSFiddle
- Linkje naar werkend voorbeeldje (gehost op Raspberry Pi)
- Linkje naar (de huidige versie van) de code op GitHub
JavaScript:
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
| let toneContext = null; let toneGenerator = null; let toneAmplifier = null; function startFrequencyTrainer(difficultyMode, previousFrequency) { 'use strict'; let frequencies = null; let frequency = null; // Create objects toneContext = new(window.AudioContext || window.webkitAudioContext)(); toneAmplifier = toneContext.createGain(); // Pick a frequency frequencies = getFrequencies(difficultyMode); frequency = getNewFrequency(frequencies, previousFrequency); return { frequencies, frequency }; } function stopFrequencyTrainer() { toneContext.close(); } function startToneGenerator(frequency, volumeControl, startTimer, stopTimer) { 'use strict'; // Create and configure the oscillator toneGenerator = toneContext.createOscillator(); toneGenerator.type = 'sine'; // could be sine, square, sawtooth or triangle toneGenerator.frequency.value = frequency; // Connect toneGenerator -> toneAmplifier -> output toneGenerator.connect(toneAmplifier); toneAmplifier.connect(toneContext.destination); // Set the gain volume toneAmplifier.gain.value = volumeControl.value / 100; // Fire up the toneGenerator toneGenerator.start(toneContext.currentTime + startTimer); toneGenerator.stop(toneContext.currentTime + startTimer + stopTimer); } function stopToneGenerator() { 'use strict'; if (toneGenerator) { toneGenerator.disconnect(); } } function changeVolume(volumeControl) { 'use strict'; toneAmplifier.gain.value = volumeControl.value / 100; } function getFrequencies(difficultyMode) { 'use strict'; let frequencies = null; if (difficultyMode === 'easy') { frequencies = ["250", "800", "2500", "8000"]; } else if (difficultyMode === 'normal') { frequencies = ["100", "200", "400", "800", "1600", "3150", "6300", "12500"]; } else if (difficultyMode === 'hard') { frequencies = ["80", "125", "160", "250", "315", "500", "630", "1000", "1250", "2000", "2500", "4000", "5000", "8000", "10000", "16000"]; } else if (difficultyMode === 'pro') { frequencies = ["20", "25", "31.5", "40", "50", "63", "80", "100", "125", "160", "200", "250", "315", "400", "500", "630", "800", "1000", "1250", "1600", "2000", "2500", "3150", "4000", "5000", "6300", "8000", "10000", "12500", "16000", "20000"]; } return frequencies; } function getNewFrequency(frequencies, previousFrequency) { 'use strict'; let newFrequency = null; newFrequency = frequencies[Math.floor(Math.random() * frequencies.length)]; // Avoid getting the same frequency twice in a row while (newFrequency === previousFrequency) { newFrequency = frequencies[Math.floor(Math.random() * frequencies.length)]; } return newFrequency; } function frequencyFormatter(frequency) { 'use strict'; let frequencyFormatted = null; if (frequency > 999) { frequencyFormatted = frequency / 1000 + ' k'; } else { frequencyFormatted = frequency + ' '; } return frequencyFormatted; } |
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
| <!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:900" /> </head> <body> <div class="body"> <div class="title"> <h1>Frequency Trainer</h1> </div> <div class="controls"> <br /> <button type="button" id="start-button" class="control-button">Start</button> <button type="button" id="stop-button" class="control-button">Stop</button> <button type="button" id="next-button" class="control-button">Next</button><br /> <br /> Volume:<br /> <input type="range" id="volume-control" class="volume-control" min="0" max="20" value="2" step="0.1" /><br /> <br /> <button type="button" id="difficulty-easy" class="difficulty-button" data-difficulty="easy">Easy</button> <button type="button" id="difficulty-normal" class="difficulty-button" data-difficulty="normal">Normal</button> <button type="button" id="difficulty-hard" class="difficulty-button" data-difficulty="hard">Hard</button> <button type="button" id="difficulty-pro" class="difficulty-button" data-difficulty="pro">Pro</button><br /> <br /> </div> <div class="grid"> </div> <div class="footer"> <a href="https://github.com/MaxVMH/frequency-trainer/tree/v.0.0.4-alpha">v.0.0.4</a> </div> </div> <script> (function () { 'use strict'; let difficultyMode = 'easy'; // default difficulty mode let frequencyTrainer = startFrequencyTrainer(difficultyMode); let frequency = frequencyTrainer.frequency; let frequencyContainers = null; // Control buttons let startButton = document.getElementById('start-button'); startButton.onclick = function () { stopToneGenerator(); startToneGenerator(frequency, volumeControl, 0, 3); }; let stopButton = document.getElementById('stop-button'); stopButton.onclick = function () { stopToneGenerator(); }; let nextButton = document.getElementById('next-button'); nextButton.onclick = function () { stopToneGenerator(); stopFrequencyTrainer(); frequency = startFrequencyTrainer(difficultyMode, frequency).frequency; startToneGenerator(frequency, volumeControl, 0.05, 3); }; let volumeControl = document.getElementById('volume-control'); volumeControl.oninput = function () { changeVolume(volumeControl); }; function fillFrequencyGrid(frequencies) { let frequencyFormatted = null; let frequencyGrid = document.getElementsByClassName('grid')[0]; frequencyGrid.innerHTML = ''; frequencies.forEach(function (frequency) { frequencyFormatted = frequencyFormatter(frequency); frequencyGrid.insertAdjacentHTML('beforeend', '<div class="frequency-container" data-frequency="' + frequency + '">' + frequencyFormatted + 'Hz</div>'); }); } function makeFrequencyGridInteractive() { frequencyContainers = document.getElementsByClassName('frequency-container'); Array.prototype.forEach.call(frequencyContainers, function (frequencyContainer) { frequencyContainer.onclick = function () { let frequencyChosen = frequencyContainer.getAttribute('data-frequency'); let frequencyChosenFormatted = frequencyFormatter(frequencyChosen); stopToneGenerator(); if (frequencyChosen === frequency) { if (window.confirm(frequencyChosenFormatted + 'Hz is correct!\nLet\'s try another one!')) { stopFrequencyTrainer(); frequency = startFrequencyTrainer(difficultyMode, frequency).frequency; startToneGenerator(frequency, volumeControl, 0.05, 3); } } else { window.alert(frequencyChosenFormatted + 'Hz is not correct.\nPlease try again.'); startToneGenerator(frequency, volumeControl, 0.05, 3); } }; }); } // Generate frequency grid fillFrequencyGrid(frequencyTrainer.frequencies); makeFrequencyGridInteractive(); // Difficulty buttons let difficultyButtons = document.getElementsByClassName('difficulty-button'); Array.prototype.forEach.call(difficultyButtons, function (difficultyButton) { difficultyButton.onclick = function () { stopToneGenerator(); stopFrequencyTrainer(); difficultyMode = difficultyButton.getAttribute('data-difficulty'); frequencyTrainer = startFrequencyTrainer(difficultyMode, frequency); frequency = frequencyTrainer.frequency; fillFrequencyGrid(frequencyTrainer.frequencies); makeFrequencyGridInteractive(); }; }); }()); </script> </body> </html> |