Skip to main content
Code Review

Return to Question

Notice removed Draw attention by Max
Bounty Ended with Sᴀᴍ Onᴇᴌᴀ's answer chosen by Max
edited tags
Link
Notice added Draw attention by Max
Bounty Started worth 50 reputation by Max
Tweeted twitter.com/StackCodeReview/status/1041295685314863104
removed the css since it's irrelevant for the question
Source Link
Max
  • 241
  • 1
  • 4
  • 18

let toneContext = null;
let toneGenerator = null;
let toneAmplifier = null;
function startFrequencyTrainer(difficultyMode, previousFrequency) {
 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) {
 // 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() {
 if (toneGenerator) {
 toneGenerator.disconnect();
 }
}
function changeVolume(volumeControl) {
 toneAmplifier.gain.value = volumeControl.value / 100;
}
function getFrequencies(difficultyMode) {
 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) {
 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) {
 let frequencyFormatted = null;
 if (frequency > 999) {
 frequencyFormatted = frequency / 1000 + ' k';
 } else {
 frequencyFormatted = frequency + ' ';
 }
 return frequencyFormatted;
}
body {
 font-family: 'Montserrat', sans-serif;
 text-align: center;
 padding-top: 10px;
}
h1 {
 margin: 0 auto;
 font-size: 30px;
 text-decoration: underline;
}
h2 {
 margin: 0;
 font-size: 25px;
}
a {
 color: #0000BB;
}
a:hover {
 color: #000000;
}
button {
 font-family: 'Montserrat', sans-serif;
 text-align: center;
 font-size: calc(10px + 1vw);
}
.body {
 max-width: 1500px;
 border: 1px solid black;
 width: 95%;
 margin: 0 auto;
}
.title {
 padding: 10px 0 0 0;
 margin: 0 auto;
 width: 95%;
}
.content {
 padding: 30px 0 0 0;
 margin: 0 auto;
 width: 95%;
}
.controls {
 padding: 0;
 margin: 0 auto;
 width: 95%;
}
.volume-control {
 padding: 0;
 margin: 0 auto;
 min-width: 200px;
 width: 80%;
}
.footer {
 padding: 20px 0 10px 0;
 margin: 0 auto;
 width: 95%;
}
.grid {
 margin: 0 auto;
 width: 95%;
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
}
.frequency-container {
 margin: 2px;
 border: 1px solid black;
 padding: 0;
 min-width: 80px;
 min-height: 80px;
 max-width: 300px;
 max-height: 300px;
 display: flex;
 align-items: center;
 justify-content: center;
 font-size: calc(30px + 0.2vw);
 text-shadow: 0 0 25px white;
}
.frequency-container:before {
 content: '';
 padding-top: 100%;
 float: left;
}
<!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 () {
 let difficultyMode = 'easy'; // default difficulty mode
 let frequencyTrainer = startFrequencyTrainer(difficultyMode, null);
 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>

PS: Bonus question, who can figure out why the snippet won't work only on stackoverflow/codereview (it works everywhere else)?

let toneContext = null;
let toneGenerator = null;
let toneAmplifier = null;
function startFrequencyTrainer(difficultyMode, previousFrequency) {
 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) {
 // 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() {
 if (toneGenerator) {
 toneGenerator.disconnect();
 }
}
function changeVolume(volumeControl) {
 toneAmplifier.gain.value = volumeControl.value / 100;
}
function getFrequencies(difficultyMode) {
 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) {
 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) {
 let frequencyFormatted = null;
 if (frequency > 999) {
 frequencyFormatted = frequency / 1000 + ' k';
 } else {
 frequencyFormatted = frequency + ' ';
 }
 return frequencyFormatted;
}
<!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>
 <script>
 (function () {
 let difficultyMode = 'easy'; // default difficulty mode
 let frequencyTrainer = startFrequencyTrainer(difficultyMode, null);
 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>

let toneContext = null;
let toneGenerator = null;
let toneAmplifier = null;
function startFrequencyTrainer(difficultyMode, previousFrequency) {
 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) {
 // 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() {
 if (toneGenerator) {
 toneGenerator.disconnect();
 }
}
function changeVolume(volumeControl) {
 toneAmplifier.gain.value = volumeControl.value / 100;
}
function getFrequencies(difficultyMode) {
 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) {
 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) {
 let frequencyFormatted = null;
 if (frequency > 999) {
 frequencyFormatted = frequency / 1000 + ' k';
 } else {
 frequencyFormatted = frequency + ' ';
 }
 return frequencyFormatted;
}
body {
 font-family: 'Montserrat', sans-serif;
 text-align: center;
 padding-top: 10px;
}
h1 {
 margin: 0 auto;
 font-size: 30px;
 text-decoration: underline;
}
h2 {
 margin: 0;
 font-size: 25px;
}
a {
 color: #0000BB;
}
a:hover {
 color: #000000;
}
button {
 font-family: 'Montserrat', sans-serif;
 text-align: center;
 font-size: calc(10px + 1vw);
}
.body {
 max-width: 1500px;
 border: 1px solid black;
 width: 95%;
 margin: 0 auto;
}
.title {
 padding: 10px 0 0 0;
 margin: 0 auto;
 width: 95%;
}
.content {
 padding: 30px 0 0 0;
 margin: 0 auto;
 width: 95%;
}
.controls {
 padding: 0;
 margin: 0 auto;
 width: 95%;
}
.volume-control {
 padding: 0;
 margin: 0 auto;
 min-width: 200px;
 width: 80%;
}
.footer {
 padding: 20px 0 10px 0;
 margin: 0 auto;
 width: 95%;
}
.grid {
 margin: 0 auto;
 width: 95%;
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
}
.frequency-container {
 margin: 2px;
 border: 1px solid black;
 padding: 0;
 min-width: 80px;
 min-height: 80px;
 max-width: 300px;
 max-height: 300px;
 display: flex;
 align-items: center;
 justify-content: center;
 font-size: calc(30px + 0.2vw);
 text-shadow: 0 0 25px white;
}
.frequency-container:before {
 content: '';
 padding-top: 100%;
 float: left;
}
<!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 () {
 let difficultyMode = 'easy'; // default difficulty mode
 let frequencyTrainer = startFrequencyTrainer(difficultyMode, null);
 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>

PS: Bonus question, who can figure out why the snippet won't work only on stackoverflow/codereview (it works everywhere else)?

let toneContext = null;
let toneGenerator = null;
let toneAmplifier = null;
function startFrequencyTrainer(difficultyMode, previousFrequency) {
 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) {
 // 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() {
 if (toneGenerator) {
 toneGenerator.disconnect();
 }
}
function changeVolume(volumeControl) {
 toneAmplifier.gain.value = volumeControl.value / 100;
}
function getFrequencies(difficultyMode) {
 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) {
 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) {
 let frequencyFormatted = null;
 if (frequency > 999) {
 frequencyFormatted = frequency / 1000 + ' k';
 } else {
 frequencyFormatted = frequency + ' ';
 }
 return frequencyFormatted;
}
<!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>
 <script>
 (function () {
 let difficultyMode = 'easy'; // default difficulty mode
 let frequencyTrainer = startFrequencyTrainer(difficultyMode, null);
 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>
added a working online example for those who prefer to look at code with devtools in their own browser to encourage getting answers
Source Link
Max
  • 241
  • 1
  • 4
  • 18

A few days ago I posted the humble beginnings. I got very useful feedback and went further. Here is the working application. Before I continue adding more functions, I would like to know what you guys think of this so far.

Here is a working example on JSFiddle & here is the full code on GitHub. Bonus question: who can figure out whyIn case anyone prefers the snippet won't work only on stackoverflow/codereviewdevtools in their own browser, here is a (it works everywhere else)?working example online .

Before I continue adding more functions, I would like to know what you guys think of this so far. Any feedback is welcome!

PS: Bonus question, who can figure out why the snippet won't work only on stackoverflow/codereview (it works everywhere else)?

A few days ago I posted the humble beginnings. I got very useful feedback and went further. Here is the working application. Before I continue adding more functions, I would like to know what you guys think of this so far.

Here is a working example on JSFiddle & here is the full code on GitHub. Bonus question: who can figure out why the snippet won't work only on stackoverflow/codereview (it works everywhere else)?

Any feedback is welcome!

A few days ago I posted the humble beginnings. I got very useful feedback and went further. Here is a working example on JSFiddle & here is the full code on GitHub. In case anyone prefers the devtools in their own browser, here is a working example online .

Before I continue adding more functions, I would like to know what you guys think of this so far. Any feedback is welcome!

PS: Bonus question, who can figure out why the snippet won't work only on stackoverflow/codereview (it works everywhere else)?

deleted 1 character in body
Source Link
Max
  • 241
  • 1
  • 4
  • 18
Loading
added 3240 characters in body
Source Link
Max
  • 241
  • 1
  • 4
  • 18
Loading
added GitHub link
Source Link
Max
  • 241
  • 1
  • 4
  • 18
Loading
deleted 75 characters in body
Source Link
Max
  • 241
  • 1
  • 4
  • 18
Loading
Source Link
Max
  • 241
  • 1
  • 4
  • 18
Loading
default

AltStyle によって変換されたページ (->オリジナル) /