Skip to content

Instantly share code, notes, and snippets.

@MarkRobertJohnson
Last active April 7, 2018 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarkRobertJohnson/e3f6b6f3eb674fccffb30979e0a74d10 to your computer and use it in GitHub Desktop.
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.
<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>
@EmmanuelWidmer
Copy link

EmmanuelWidmer commented Apr 7, 2018

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();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment