This commit is contained in:
parent
74938829fe
commit
23e0c008a8
1 changed files with 99 additions and 0 deletions
99
static/piano/index.html
Normal file
99
static/piano/index.html
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<title>piano</title>
|
||||
<h1>piano</h1>
|
||||
<div>
|
||||
<textarea id="input"></textarea>
|
||||
</div>
|
||||
|
||||
<h2>notes held</h2>
|
||||
<div id="notes-held"></div>
|
||||
|
||||
<script>
|
||||
const inputArea = document.querySelector('#input');
|
||||
const notesDiv = document.querySelector('#notes-held');
|
||||
const ctx = new AudioContext;
|
||||
const playing = {};
|
||||
let tone = {};
|
||||
let setupCompleted = false;
|
||||
inputArea.onfocus = start;
|
||||
inputArea.onblur = pause;
|
||||
|
||||
// arrange notes like on a piano. the second and fourth rows are each a major scale, but the first and third rows have gaps.
|
||||
function usePianoKeys() {
|
||||
tone = {};
|
||||
("zsxdcvgbhnjm,l.;/q2w3e4rt6y7ui9o0p-[]"
|
||||
.split('')
|
||||
.map((key, i) => {
|
||||
tone[key] = 440 * 2 ** ((i - 20)/12);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// arrange notes so that moving three keys sideways is exactly an octave. makes it easy to play octaves. everything else is wonky though...
|
||||
function useEqualSteps() {
|
||||
const rows = [
|
||||
"1234567890-=",
|
||||
"qwertyuiop[]",
|
||||
"asdfghjkl;'",
|
||||
"zxcvbnm,./",
|
||||
];
|
||||
tone = {};
|
||||
rows.map((row, y) => {
|
||||
row.split('').map((key, x) => {
|
||||
const semitone = x * 4 + y - 20;
|
||||
tone[key] = 440 * 2 ** (semitone / 12);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (setupCompleted) {
|
||||
addEventListener('keydown', onKeydown);
|
||||
return;
|
||||
}
|
||||
useEqualSteps();
|
||||
addEventListener('keydown', onKeydown);
|
||||
addEventListener('keyup', onKeyup);
|
||||
setupCompleted = true;
|
||||
}
|
||||
|
||||
function pause() {
|
||||
removeEventListener('keydown', onKeydown);
|
||||
}
|
||||
|
||||
function onKeydown(ev) {
|
||||
let key = ev.key;
|
||||
if (key == ' ') key = 'Space';
|
||||
if (!tone[key]) return;
|
||||
if (playing[key]) return;
|
||||
|
||||
const gain = new GainNode(ctx, { gain: 2 ** -5 });
|
||||
const oscillator = new OscillatorNode(ctx, { type: 'square', frequency: tone[key] });
|
||||
gain.connect(ctx.destination);
|
||||
oscillator.connect(gain);
|
||||
oscillator.start();
|
||||
|
||||
playing[key] = { gain, oscillator };
|
||||
showNotes();
|
||||
}
|
||||
|
||||
function onKeyup(ev) {
|
||||
let key = ev.key;
|
||||
if (key == ' ') key = 'Space';
|
||||
if (!playing[key]) return;
|
||||
|
||||
const { gain, oscillator } = playing[key];
|
||||
oscillator.stop();
|
||||
oscillator.disconnect();
|
||||
gain.disconnect();
|
||||
|
||||
delete playing[key];
|
||||
showNotes();
|
||||
}
|
||||
|
||||
function showNotes() {
|
||||
notesDiv.innerText = Object.keys(playing).join(' ');
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Reference in a new issue