Solution 1 :

Consider separating logic from the data it operates on:

<html>

<body onkeydown="play(event)" onkeyup="stop(event)">
    <span style="font-size:10em;">Piano</span>
    <script>

        const keyToFrequencyMap = {
            49: 116.54,
            81: 123.47,
            87: 130.81,
            51: 138.59,
            69: 146.83,
            52: 155.56,
            82: 164.81,
            84: 174.61,
            54: 185.00,
            89: 196.00,
            55: 207.65,
            85: 220.00,
            56: 233.08,
            73: 246.94,
            79: 261.63,
            48: 277.18,
            80: 293.66,
            189: 311.13,
            219: 329.63,
            221: 349.23
        }
        var context, o, g;

        function play(event) {
            context = new AudioContext();
            o = context.createOscillator();
            var key = event.which || event.keyCode;
            o.frequency.value = keyToFrequencyMap[key]
            console.log(`Playing ${o.frequency.value}`)
            g = context.createGain();
            o.connect(g);
            g.connect(context.destination);
            o.start(0);
        }

        function stop(event) {
            g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
            console.log('Disconnecting')
            o.disconnect(context.destination);
        }
    </script>
</body>

</html>

console.log is your friend. Either multiple notes are being played, or the note is not stopping when you think it should.

Problem :

I am trying to make a simple piano software using HTML and JavaScript which can play just one octave with only the keyboard keys. The key layout is almost like this:
enter image description here
Although the sound is not like a piano, I will be considering that part later on. I wrote this code:

<html>

<body onkeydown="play(event)" onkeyup="stop(event)">
    <span style="font-size:10em;">Piano</span>
    <script>
        var context, o, g;

        function play(event) {
            context = new AudioContext();
            o = context.createOscillator();
            var key = event.which || event.keyCode;
            if (key == 49) o.frequency.value = 116.54;
            if (key == 81) o.frequency.value = 123.47;
            if (key == 87) o.frequency.value = 130.81;
            if (key == 51) o.frequency.value = 138.59;
            if (key == 69) o.frequency.value = 146.83;
            if (key == 52) o.frequency.value = 155.56;
            if (key == 82) o.frequency.value = 164.81;
            if (key == 84) o.frequency.value = 174.61;
            if (key == 54) o.frequency.value = 185.00;
            if (key == 89) o.frequency.value = 196.00;
            if (key == 55) o.frequency.value = 207.65;
            if (key == 85) o.frequency.value = 220.00;
            if (key == 56) o.frequency.value = 233.08;
            if (key == 73) o.frequency.value = 246.94;
            if (key == 79) o.frequency.value = 261.63;
            if (key == 48) o.frequency.value = 277.18;
            if (key == 80) o.frequency.value = 293.66;
            if (key == 189) o.frequency.value = 311.13;
            if (key == 219) o.frequency.value = 329.63;
            if (key == 221) o.frequency.value = 349.23;
            g = context.createGain();
            o.connect(g);
            g.connect(context.destination);
            o.start(0);
        }

        function stop(event) {
            g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
            o.disconnect(context.destination);
        }
    </script>
</body>

</html>

Now, the problem is, if I keep a key held down, there are multiple instances of that particular frequency. For this reason, I cannot press multiple keys at the same time. To overcome this, I have modified the code a little bit:



var context, o, g;

    function play(event) {
        context = new AudioContext();
        o = context.createOscillator();
        var key = event.which || event.keyCode;
        if (key == 49) o.frequency.value = 116.54;
        if (key == 81) o.frequency.value = 123.47;
        if (key == 87) o.frequency.value = 130.81;
        if (key == 51) o.frequency.value = 138.59;
        if (key == 69) o.frequency.value = 146.83;
        if (key == 52) o.frequency.value = 155.56;
        if (key == 82) o.frequency.value = 164.81;
        if (key == 84) o.frequency.value = 174.61;
        if (key == 54) o.frequency.value = 185.00;
        if (key == 89) o.frequency.value = 196.00;
        if (key == 55) o.frequency.value = 207.65;
        if (key == 85) o.frequency.value = 220.00;
        if (key == 56) o.frequency.value = 233.08;
        if (key == 73) o.frequency.value = 246.94;
        if (key == 79) o.frequency.value = 261.63;
        if (key == 48) o.frequency.value = 277.18;
        if (key == 80) o.frequency.value = 293.66;
        if (key == 189) o.frequency.value = 311.13;
        if (key == 219) o.frequency.value = 329.63;
        if (key == 221) o.frequency.value = 349.23;
        g = context.createGain();
        o.connect(g);
        g.connect(context.destination);
        o.start(0);
        document.body.removeEventListener("keydown", play(event)); //Added this part
    }

    function stop(event) {
        g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
        o.disconnect(context.destination);
        document.body.addEventListener("keydown", play(event)); //Added this part
    }

Now, if I load this in Chrome browser and press a key, the browser along with my Ubuntu OS hangs!!! Why does this happen and how can I achieve what I want?

Comments

Comment posted by Puspam

Thanks for the advice. But, if I remove the

Comment posted by Josh Wulf

added console.log to debug.

Comment posted by Puspam

Whenever I press a key, I get this error in the console:

Comment posted by Josh Wulf

Well, you do

By