<script>
  $(document).ready(function() {
    $("body").on("contextmenu", function(e) {
      return false;
    });
  });

</script>

<?xml version="1.0" encoding="UTF-8"?>
<svg width="100%" height="100%" viewBox="0 0 15000 7500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>02 Harmonic series</title>
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <rect id="Rectangle" stroke="#979797" fill="#000000" x="0.5" y="0.5" width="14999" height="7499"></rect>
        <g id="Pure-harmonics" transform="translate(1400.000000, 3749.893219)">
            <g id="Background" transform="translate(0.106781, 1553.106781)" fill="#4D908E" stroke="#4D908E" stroke-linejoin="round" stroke-width="75">
                <rect id="K1" x="-37.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K2" x="1462.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K3" x="2962.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K4" x="4462.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K5" x="5962.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K6" x="7462.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K7" x="8962.5" y="-37.5" width="1075" height="1075"></rect>
                <rect id="K8" x="10462.5" y="-37.5" width="1075" height="1075"></rect>
            </g>
            <g id="Text" fill="#FFFFFF" font-family="AvenirNext-Regular, Avenir Next" font-weight="normal">
                <text id="8/1" font-size="600">
                    <tspan x="10826" y="2250">8</tspan>
                </text>
                <text id="7/1" font-size="600">
                    <tspan x="9326" y="2250">7</tspan>
                </text>
                <text id="6/1" font-size="600">
                    <tspan x="7826" y="2250">6</tspan>
                </text>
                <text id="5/1" font-size="600">
                    <tspan x="6326" y="2250">5</tspan>
                </text>
                <text id="4/1" font-size="600">
                    <tspan x="4826" y="2250">4</tspan>
                </text>
                <text id="3/1" font-size="600">
                    <tspan x="3326" y="2250">3</tspan>
                </text>
                <text id="2/1" font-size="600">
                    <tspan x="1826" y="2250">2</tspan>
                </text>
                <text id="1/1" font-size="600">
                    <tspan x="326" y="2250">1</tspan>
                </text>
                <text id="The-first-8-pure-har" font-size="450">
                    <tspan x="0" y="450">The first 8 partials (pure harmonics) of the note above,</tspan>
                    <tspan x="0" y="1065">with frequencies 220 Hz, 440 Hz, 660 Hz et cetera.</tspan>
                </text>
            </g>
            <g id="Keys" transform="translate(0.106781, 1553.106781)" fill="#000000" fill-opacity="0">
                <rect class=key id="1" x="-75" y="-75" width="1150" height="1150"></rect>
                <rect class=key id="2" x="1425" y="-75" width="1150" height="1150"></rect>
                <rect class=key id="3" x="2925" y="-75" width="1150" height="1150"></rect>
<rect class=key id="4" x="4425" y="-75" width="1150" height="1150"></rect>
<rect class=key id="5" x="5925" y="-75" width="1150" height="1150"></rect>
<rect class=key id="6" x="7425" y="-75" width="1150" height="1150"></rect>
<rect class=key id="7" x="8925" y="-75" width="1150" height="1150"></rect>
<rect class=key id="8" x="10425" y="-75" width="1150" height="1150"></rect>

            </g>
        </g>
        <g id="Sawtooth" transform="translate(1400.000000, 1115.893219)">
            <rect id="saw-background" stroke="#F94144" stroke-width="75" fill="#F94144" stroke-linejoin="round" x="-37.3932188" y="47.6067812" width="1075" height="1075"></rect>
            <text id="A-harmonically-rich" font-family="AvenirNext-Regular, Avenir Next" font-size="450" font-weight="normal" fill="#FFFFFF">
                <tspan x="1397" y="450">A harmonically rich note (a sawtooth wave) with a </tspan>
                <tspan x="1397" y="1065">fundamental frequency of 220 Hz</tspan>
            </text>
            <text id="sawtooth" transform="translate(500.000000, 604.000000) scale(-1, 1) rotate(90.000000) translate(-500.000000, -604.000000) " font-family="STHeitiSC-Medium, Heiti SC" font-size="900" font-weight="bold" fill="#FFFFFF">
                <tspan x="50" y="878">∠</tspan>
            </text>
            <rect id="saw" fill-opacity="0" fill="#000000" x="-75" y="10" width="1150" height="1150"></rect>
        </g>
    </g>
</svg>
  
body {
  background-color: #000000;
  font-family: Andale mono, monospace;
  font-size: 100%;
  user-select: none;
  touch-action: none;
}

svg{
  display:block;
  position: absolute;
  z-index:0;
  height: 100%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  touch-action: none;
  background-color: #000000;
}


/* Portrait orientation */
@media screen and (orientation: portrait) {
button{
  display: block;
  position: absolute;
  background-color:#000000;
  font-family: Andale mono, monospace;
  border-radius: 2px;
  border-width: 2px;
  user-select: none;
  height: 7%;
  width: 17%;
  right: 2%;
  z-index: 3;
  font-size: 2vw
}
}

/* Landscape orientation */
@media screen and (orientation: landscape) {
button{
  display: block;
  position: absolute;
  background-color:#000000;
  font-family: Andale mono, monospace;
  border-radius: 2px;
  border-width: 2px;
  user-select: none;
  height: 7%;
  width: 17%;
  right: 2%;
  z-index: 3;
  font-size: 2vw
}
}

.ActiveButton {
  color: #F9C74F;
  border-color: #F9C74F;
}

.OtherButton {
  color: #577590;
  border-color: #577590;
}

// General

console.clear(); 

var elem = document.documentElement;


const baseFreq = 220
var root = baseFreq
var transpose=0
var voice = 0
var maxVoices = 4
var KeyArray = []
let index

//*** initialize tone.js synth ***

    // core synthesizer
const voice1 = new Tone.Synth({oscillator: {type:"sine"},
  envelope: { attack : 0.05, decay : 3.50, sustain : 0, release : 3.5}, 
  volume: -6});

const voice2 = new Tone.Synth({oscillator: {type:"sine"},
  envelope: { attack : 0.05, decay : 3.50, sustain : 0, release : 3.5}, 
  volume: -6});

const voice3 = new Tone.Synth({oscillator: {type:"sine"},
  envelope: { attack : 0.05, decay : 3.50, sustain : 0, release : 3.5}, 
  volume: -6});

const voice4 = new Tone.Synth({oscillator: {type:"sine"},
  envelope: { attack : 0.05, decay : 3.50, sustain : 0, release : 3.5}, 
  volume: -6});

const synth = [voice1, voice2, voice3, voice4]

const sawtooth = new Tone.Synth({oscillator: {type:"sawtooth"},
  envelope: { attack : 0.05, decay : 3.50, sustain : 0, release : 3.5}, 
  volume: -6});


const reverb = new Tone.Reverb({wet:0.5}).toDestination();

Tone.connect(voice1, reverb);
Tone.connect(voice2, reverb);
Tone.connect(voice3, reverb);
Tone.connect(voice4, reverb);
Tone.connect(sawtooth, reverb);




//Tone.Transport.lookAhead = 0.025;



      
// Interaction mode

let isTouchDevice
var interaction = 'click'

if ((navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)){isTouchDevice = true}
else {isTouchDevice = false}
    
if (isTouchDevice) {interaction = 'touchstart'}



// Make array of key elements by id

for(var i=0, n=document.getElementsByClassName("key"); i<n.length; i++) {
   KeyArray.push(n[i].id);
   };



// Trigger notes

//Tone.Transport.start()

function triggerNoteOnOff() {
  
  var index = math.eval(this.id)
 
synth[voice].triggerAttackRelease(root*index, "32n");
  
if (voice >= (maxVoices-1)){voice = 0}
else {voice ++}
 
  this.style.fillOpacity=0.75

  const key = this.id;

 function resetOpacity(key){
document.getElementById(key).style.fillOpacity=0}

  setTimeout(function(){resetOpacity(key)}, 200)
  
}
  
  for (const KeyValue of KeyArray) {
    document.getElementById(KeyValue).addEventListener(interaction, triggerNoteOnOff)
  }



function triggerSawtooth() {
  
  
 
sawtooth.triggerAttackRelease(root, "32n");
 
  this.style.fillOpacity=0.75

  const key = this.id;

 function resetOpacity(key){
document.getElementById(key).style.fillOpacity=0}

  setTimeout(function(){resetOpacity(key)}, 200)
  
}
  

    document.getElementById("saw").addEventListener(interaction, triggerSawtooth)
  
   

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.