Last active
April 7, 2018 15:20
-
-
Save MarkRobertJohnson/e3f6b6f3eb674fccffb30979e0a74d10 to your computer and use it in GitHub Desktop.
A little polyphonic synthesizer that run in the browser. Uses computer keyboard to trigger notes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<header> | |
<script lang="javascript" > | |
var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
var sineTerms = new Float32Array([0, 0, 1, 0, 1]); | |
var cosineTerms = new Float32Array(sineTerms.length); | |
var customWaveform = audioCtx.createPeriodicWave(cosineTerms, sineTerms); | |
var pianoFreqKeyMap = { | |
"]":"739.989", | |
"'":"698.456", | |
";":"659.255", | |
"p":"622.254", | |
"l":"587.330", | |
"o":"554.365", | |
"k":"523.251", | |
"j":"493.883", | |
"u":"466.164", | |
"h":"440.000", | |
"y":"415.305", | |
"g":"391.995", | |
"t":"369.994", | |
"f":"349.228", | |
"d":"329.628", | |
"e":"311.127", | |
"s":"293.665", | |
"w":"277.183", | |
"a":"261.626" | |
} | |
var keysToIgnore = { | |
'Alt': true | |
} | |
var oscillators = {}; | |
function playNote(frequency, id) { | |
// create Oscillator node | |
var oscillator = audioCtx.createOscillator(); | |
oscillator.setPeriodicWave(customWaveform); | |
if(oscillators[id]) { | |
oscillators[id].stop(); | |
} | |
oscillators[id] = oscillator; | |
// oscillator.type = 'square'; | |
oscillator.frequency.value = frequency; // value in hertz | |
oscillator.connect(audioCtx.destination); | |
oscillator.start(); | |
} | |
function stopNote(id) { | |
if(oscillators[id]) { | |
oscillators[id].stop(); | |
oscillators[id] = null; | |
} | |
} | |
function startNote(e) { | |
console.log(e); | |
console.log(`REPEAT: ${e.repeat}`) | |
if(!e.repeat && !keysToIgnore[e.key]) { | |
var freq = e.keyCode *20; | |
if(pianoFreqKeyMap[e.key]) { | |
freq = pianoFreqKeyMap[e.key] | |
} | |
playNote(freq, e.key); | |
displayKeys(); | |
} | |
} | |
function toColor(num) { | |
num >>>= 0; | |
var b = num & 0xFF, | |
g = (num & 0xFF00) >>> 8, | |
r = (num & 0xFF0000) >>> 16, | |
a = ( (num & 0xFF000000) >>> 24 ) / 255 ; | |
return "rgba(" + [r, g, b, a].join(",") + ")"; | |
} | |
function displayKeys() { | |
// document.body.innerHTML = ''; | |
for (const key in oscillators) { | |
if (oscillators.hasOwnProperty(key)) { | |
const element = oscillators[key]; | |
if(element) { | |
document.body.innerHTML = `<div style="background-color: ${toColor(element.frequency.value * 10000000)}"><h1>${key}</h1></div>` + document.body.innerHTML; | |
} | |
} | |
} | |
} | |
function endNote(e) { | |
console.log(e) | |
if(!keysToIgnore[e.key]) { | |
stopNote(e.key); | |
} | |
} | |
window.addEventListener("keydown", startNote); | |
window.addEventListener("keyup", endNote); | |
</script> | |
</header> | |
<body> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Good help to build polyphonic synth with keyboard, thank you.
One improvement to avoid interference/saturation when press several keys at once: add gain and set volume 0.1 :
function playNote(frequency, id) {
// create Oscillator node
var oscillator = audioCtx.createOscillator();
oscillator.setPeriodicWave(customWaveform);
if(oscillators[id]) {
oscillators[id].stop();
}
oscillators[id] = oscillator;
// oscillator.type = 'square';
oscillator.frequency.value = frequency; // value in hertz
//---<<
var gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.gain.value = 0.1;
gainNode.connect(audioCtx.destination);
//---oscillator.connect(audioCtx.destination);
//--->>
oscillator.start();
}