This commit is contained in:
Aaron Gutierrez
2021-12-27 18:07:37 -08:00
parent 7c39ec3c2b
commit 979c018317
3 changed files with 61 additions and 61 deletions

View File

@@ -23,8 +23,8 @@ body.sharp {
background: red; background: red;
} }
h1,
h1, h2 { h2 {
margin: 0; margin: 0;
} }
@@ -35,4 +35,3 @@ h1 {
h2 { h2 {
font-size: 3em; font-size: 3em;
} }

View File

@@ -1,13 +1,14 @@
<html> <html>
<head> <head>
<meta name="viewport" conetnt="width=device-width, initial-scale=1"> <meta name="viewport" conetnt="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="tuner.css"> <link rel="stylesheet" href="tuner.css" />
<script src="tuner.js"></script> <script src="tuner.js"></script>
<title>Tuner</title> <title>Tuner</title>
</head>
<body onload="setup()"> <body onload="setup()">
<h1 id="note">Listening...</h2> <h1 id="note">Listening...</h1>
<h2 id="tune"></h3> <h2 id="tune"></h2>
<div id="frequency"></div> <div id="frequency"></div>
<div>(<span id="rate">??</span> kHz sample rate)</div> <div>(<span id="rate">??</span> kHz sample rate)</div>
</bdoy> </body>
</html> </html>

View File

@@ -1,4 +1,17 @@
const NOTE_NAMES = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] const NOTE_NAMES = [
"A",
"A#",
"B",
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#"
];
// We don't care about fundamenatls above 4kHz, so setting a lower sample rate // We don't care about fundamenatls above 4kHz, so setting a lower sample rate
// gives us finer-graned FFT buckets // gives us finer-graned FFT buckets
@@ -9,7 +22,6 @@ let dom_rate;
let dom_note; let dom_note;
let dom_tune; let dom_tune;
const setup = () => { const setup = () => {
dom_frequency = document.getElementById("frequency"); dom_frequency = document.getElementById("frequency");
dom_rate = document.getElementById("rate"); dom_rate = document.getElementById("rate");
@@ -17,28 +29,27 @@ const setup = () => {
dom_tune = document.getElementById("tune"); dom_tune = document.getElementById("tune");
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ navigator.mediaDevices
audio: true, .getUserMedia({
}).then(handleStream, err => { audio: true
})
.then(handleStream, err => {
console.error("Error calling getUserMedia", err); console.error("Error calling getUserMedia", err);
}); });
}; }
if (navigator.wakeLock && navigator.wakeLock.request) { if (navigator.wakeLock && navigator.wakeLock.request) {
try { try {
navigator.wakeLock navigator.wakeLock
.request('screen') .request("screen")
.then(wakeLock => .then(wakeLock => setTimeout(() => wakeLock.release(), 60000));
setTimeout(() => wakeLock.release(), 60000)
);
} catch (err) {} } catch (err) {}
} }
}; };
const handleStream = stream => { const handleStream = stream => {
const audioContext = new AudioContext({ const audioContext = new AudioContext({
sampleRate: TARGET_SAMPLE_RATE, sampleRate: TARGET_SAMPLE_RATE
}); });
const analyser = audioContext.createAnalyser(); const analyser = audioContext.createAnalyser();
@@ -55,7 +66,6 @@ const handleStream = stream => {
setInterval(tune(analyser, data), 500); setInterval(tune(analyser, data), 500);
}; };
const tune = (analyser, data) => () => { const tune = (analyser, data) => () => {
analyser.getByteFrequencyData(data); analyser.getByteFrequencyData(data);
@@ -88,45 +98,35 @@ const tune = (analyser, data) => () => {
document.body.className = semitonesToClassname(semitones, margin); document.body.className = semitonesToClassname(semitones, margin);
}; };
const frequencyToSemitones = frequency => 12 * Math.log2(frequency / 440) + 69;
const frequencyToSemitones = frequency =>
12 * Math.log2(frequency / 440) + 69;
const semitonesToNote = semitones => { const semitonesToNote = semitones => {
const rounded = Math.round(semitones - 69); const rounded = Math.round(semitones - 69);
const index = rounded >= 0 const index = rounded >= 0 ? rounded % 12 : (12 + (rounded % 12)) % 12;
? rounded % 12
: (12 + (rounded % 12)) % 12
return NOTE_NAMES[index]; return NOTE_NAMES[index];
} };
const errorPercentage = (semitones, margin) => { const errorPercentage = (semitones, margin) => {
const rounded = Math.round(semitones); const rounded = Math.round(semitones);
const cents = Math.round((semitones - rounded) * 100); const cents = Math.round((semitones - rounded) * 100);
const accuracy = Number.parseFloat(margin * 100).toFixed(1); const accuracy = Number.parseFloat(margin * 100).toFixed(1);
const sign = cents > 0 ? "+" : "" const sign = cents > 0 ? "+" : "";
return `${sign}${cents} cents ± ${accuracy}`; return `${sign}${cents} cents ± ${accuracy}`;
} };
const semitonesToClassname = (semitones, margin) => { const semitonesToClassname = (semitones, margin) => {
const rounded = Math.round(semitones); const rounded = Math.round(semitones);
const error = Math.abs(semitones - rounded); const error = Math.abs(semitones - rounded);
const ok = margin > 0.05 ? margin : 0.05 const ok = margin > 0.05 ? margin : 0.05;
if (error <= ok) { if (error <= ok) {
return ""; return "";
} }
return Math.round(semitones) > semitones return Math.round(semitones) > semitones ? "flat" : "sharp";
? "flat" };
: "sharp";
}