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>
- 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)?