Prettier
This commit is contained in:
43
tuner.css
43
tuner.css
@@ -1,38 +1,37 @@
|
|||||||
body {
|
body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: green;
|
background: green;
|
||||||
color: white;
|
color: white;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
transition: background 0.25s ease-in;
|
transition: background 0.25s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.flat {
|
body.flat {
|
||||||
background: blue;
|
background: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.sharp {
|
body.sharp {
|
||||||
background: red;
|
background: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
h1, h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 6em;
|
font-size: 6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
tuner.html
11
tuner.html
@@ -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>
|
||||||
|
|||||||
68
tuner.js
68
tuner.js
@@ -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
|
||||||
console.error("Error calling getUserMedia", err);
|
})
|
||||||
});
|
.then(handleStream, 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user