Problems with Glitching and Distortions in the Web Audio API

Hey there! I recently delved into exploring the web audio API and put together a simple synthesizer to get familiar with its features. However, I've encountered an issue where the audio gets distorted when subjected to intense sound input. If anyone well-versed in the API could spare a moment to glance over my code and point out any glaring mistakes or omissions that might be causing this distortion problem, it would be greatly appreciated. The problem persists across Safari, Chrome, and Firefox browsers. You can check out the demo version HERE. Thanks a bunch for any assistance!

// initializing a new audio session.
var context = new (window.webkitAudioContext || window.AudioContext || window.mozAudioContext)

function playSound(note) {
    oscillator = context.createOscillator();
    
    // create volume controller
    var gainNode = context.createGain();
    
    // connect signal to default audio output (speakers)
    oscillator.connect(gainNode);
    gainNode.connect(context.destination);

    // adjust frequency by 50%, 100%, or 200%
    var octave = document.getElementById('octave').value;

    // set oscillator frequency
    oscillator.frequency.value = frequencies[note] * octave;

    // set oscillator wave type
    oscillator.type = document.getElementById('waveSelect').value;

    // initialize gain at 0 and ramp up quickly to avoid audible pop
    gainNode.gain.value = 0;
    var quickFadeIn = gainNode.gain.setTargetAtTime(1, context.currentTime, 0.1);

    // start the oscillator after a slight delay
    oscillator.start(context.currentTime + 0.05);

    /** 
     * AUDIO EFFECTS
     */

    function delayNode() {
        // implement delay effect
        var delay = context.createDelay();
        delay.delayTime.value = 0.5;

        gainNode;
        quickFadeIn;

        // create feedback loop
        oscillator.connect(gainNode);
        gainNode.connect(delay);
        delay.connect(gainNode);
        delay.connect(context.destination);

        // reduce gain
        quickFadeOut;
    }

    function distortionNode() {
        // apply distortion effect using createWaveShaper
        var distortion = context.createWaveShaper();

        // generate distortion curve based on provided amount
        function makeDistortionCurve(amount) {
            //...
        };

        distortion.curve = makeDistortionCurve(500);
        distortion.oversample = '4x';

        gainNode;

        quickFadeIn;

        oscillator.connect(gainNode);
        gainNode.connect(distortion);
        distortion.connect(context.destination);

        // decrease gain
        quickFadeOut;   
    }

    if (document.getElementById('toggleDelay').value == 'true'){delayNode();}   
    if (document.getElementById('toggleDistortion').value == 'true'){distortionNode();}

    // determine note duration
    var sustain = parseFloat(document.getElementById('sustain').value);

    // stop the oscillator smoothly to prevent click sound
    var quickFadeOut = gainNode.gain.setTargetAtTime(0, context.currentTime + sustain, 0.0015);

    // change key color on keypress

    // ...
}

// functionality for the second keyboard follows similar logic as playSound()

// reveal second keyboard section
function displayKeyboard2(lowersynth, uppersynth) {
    //...
}

Answer №1

When you push the audio output past its limits in digital audio, clipping occurs which can create a harsh sound. To prevent this, it is recommended to keep gain values below 1 and use a DynamicsCompressor on the output. This involves creating a DynamicsCompressorNode using context.createDynamicsCompressor(), connecting it to context.destination, and then routing notes through the compressor instead of directly to the destination. While compressor settings are subjective, the default values can help mitigate clipping issues.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Clicking does not trigger scrollIntoView to work properly

I'm facing an issue with a button that is supposed to scroll the page down to a specific div when clicked. I implemented a scrollIntoView function in JavaScript and attached it to the button using onClick. Although the onClick event is functioning as ...

The initial item in a pagination/list is double-parsed on an AJAX website using Selenium 3.0.2, Firefox webdriver, and BeautifulSoup 4.5.1

For the past three days, I've been facing a frustrating issue with both Selenium and Bs4. While I suspect Selenium (or my code) to be the culprit. Like many others before me, I'm attempting to scrape data from this website: I'm moving from ...

Error: The function registerUser from require(...) is not defined

I am facing an issue where I am trying to import the registerUser function inside router.post within the same file that houses its exported function (registerUser). However, when attempting to use it outside of this module, I receive the following error: ...

Configuring vue-jest: Does anyone know how to set up aliases for template/script src attributes in Vue?

Dependencies: "@vue/cli-plugin-unit-jest": "^4.5.13", "@vue/test-utils": "^1.2.1", "vue-jest": "^3.0.7" I am dealing with an application that utilizes an alias (referred to as "foo") de ...

D3.js: Exploring the beauty of layered legends

I have a question regarding creating legends with triangle shapes. Specifically, I am trying to create two triangles representing "Yes" and "No". However, when I run the code below, the triangles end up overlapping each other. In an attempt to separate t ...

Leveraging jQuery Ajax and MySQL to generate dynamic HTML content

I'm in the process of creating a unique photo gallery that utilizes dynamic features. Instead of relying on constant HTML/PHP refreshing for updates, I am incorporating jQuery to handle dynamic MYSQL queries. As a beginner, I've managed to creat ...

Retrieving the value of a JavaScript variable from an HTML document using Python

I am looking to extract the value of myJSONObject from an HTML document that includes javascript code with a JSON object. Here is an example snippet: <html> <head> </head> <body> <script type="text/javascript"> ...

Video background mute feature malfunctioning

I've searched through numerous resources and reviewed various solutions for this issue, yet I still haven't been able to figure it out. Could someone please guide me on how to mute my youtube embedded video? P.s. I am a beginner when it comes to ...

Firefox MediaSourceExtension now has enhanced mp3 support

Currently exploring the integration of adaptive and progressive audio streaming in the browser without the need for plugins. MSE is the HTML5 API that I've been anticipating, now available in FF 42. However, I'm encountering issues with audio fo ...

yii CGridView refresh trigger an influx of Ajax requests

Does anyone know why the yii cgridview refresh button triggers multiple ajax calls? Upon refreshing, I have noticed that it initiates several ajax calls (this time it's 3, but sometimes it's 4 or even 5) GET http://localhost/ijob-css/index.php/ ...

3D Animation for All Browsers

I'm currently working on creating a small browser-based game and I've been experimenting with animations to get the desired effect. So far, the animation works well in Opera and Edge, although there is a slight cropping issue in Edge. Unfortunat ...

Update the jQuery script tag with new content - rewrite everything

I am facing an issue with jquery. I need to change the link to src only when "document.write" is present. Below is my code: myscript.js document.write("TEST ABCD"); test.html <html> <body> <button id="example">click me</button&g ...

xhttp.load path for server-side module

I'm currently working on developing a node package and in my JavaScript code, I have the following: const calcHtml = './calc.html'; const xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function () { if (this.readyState == 4) { ...

The problem of interpreting JSON using the JavaScript eval() function

Here is the JSON string provided : { "name":"Ruby on Rails Baseball Jersey", "price":"19.99", "id":"1025786064", "image":"" }, { "name":"Ruby on Rails Baseball Jersey", "price":"19.99", "id":"1025786064", "image":"" }, { "name ...

How to determine the presence of 'document' in Typecsript and NextJS

Incorporating NextJS means some server-side code rendering, which I can manage. However, I'm facing a challenge when trying to check for set cookies. I attempted: !!document && !!document.cookie as well as document !== undefined && ...

Implementing an onclick event listener in combination with an AJAX API call

I'm really struggling with this issue. Here's the problem I'm facing: I have a text area, and I need to be able to click on a button to perform two tasks: Convert the address text into uppercase Loop through the data retrieved from an API ...

Javascript: struggling with focus loss

Looking for a way to transform a navigation item into a search bar upon clicking, and revert back to its original state when the user clicks elsewhere. The morphing aspect is working correctly but I'm having trouble using 'blur' to trigger t ...

Pinia throws a useStore is not callable error

I have been trying to resolve the issue with (0 , pinia__WEBPACK_IMPORTED_MODULE_1__.useStore) is not a function but unfortunately, I haven't been able to find a solution. Can anyone point out what mistake I am making? Here is my store.js code: im ...

What could be the reason for the function providing the value of just the initial input?

Why am I only getting "White" when I click on the colors? I can't seem to get any other values to appear on the screen. I'm confused about what mistake I might be making here. var x = document.getElementById("mySelect").value; function myFunc ...

issue with non-existent value in v-for loop when using functional template refs

Scenario I am currently developing a personalized filtering feature. This feature allows users to add n filters that are shown using a v-for loop in the template. Users have the ability to modify input values and remove filters as needed. Challenge Issue ...