Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I correctly cancel a currently changing AudioParam in the Web Audio API

I'm trying to implement volume envelopes that can restart on any given moment, even if it's already in the middle of a param-movement but I can't figure out how to do this without clicks in the resulting audio (which seem to be somewhat irregular with regards to when they occur).

Is this even possible? I see that AudioParam.cancelScheduledValues() "cancels all scheduled future changes to the AudioParam", but I'm not sure what happens on a change that is currently going.

This is the code I'm using to start/restart the volume envelope.

var now = context.currentTime;
var currentVol = gain.gain.value;
gain.gain.cancelScheduledValues(now);
gain.gain.setValueAtTime(currentVol, now);
gain.gain.exponentialRampToValueAtTime(1, now + volAttack);
gain.gain.exponentialRampToValueAtTime(0.000001, now + volAttack + volDecay);
like image 265
Eindbaas Avatar asked Jan 09 '16 14:01

Eindbaas


People also ask

How do I close audio context?

The close() method of the AudioContext Interface closes the audio context, releasing any system audio resources that it uses.

What does Web Audio API do?

The Web Audio API provides a powerful and versatile system for controlling audio on the Web, allowing developers to choose audio sources, add effects to audio, create audio visualizations, apply spatial effects (such as panning) and much more.


3 Answers

I find custom curves work more reliably and are more controllable

function expCurve(start, end) {
    var count = 10;
    var t = 0;
    var curve = new Float32Array(count + 1);
    start = Math.max(start, 0.0000001);
    end = Math.max(end, 0.0000001);
    for (var i = 0; i <= count; ++i) {
        curve[i] = start * Math.pow(end / start, t);
        t += 1/count;
    }
    return curve;
}


gain.gain.cancelScheduledValues(0);
var currentVol = gain.gain.value;
var now = context.currentTime;
gain.gain.setValueCurveAtTime(expCurve(currentVol, 1), now, volAttack);
gain.gain.setValueCurveAtTime(expCurve(1, 0), now + volAttack, volDecay);
like image 83
Esailija Avatar answered Oct 11 '22 16:10

Esailija


After asking at the slack Web Audio channel, they explained to me that this is a known issue of the current spec.

Here is the link to the issue at GitHub: https://github.com/WebAudio/web-audio-api/issues/344

So the short answer is that stopping ramps halfway through is currently not supported. So as a workaround, they have to be controlled at every segment.

like image 28
Luis Crespo Avatar answered Oct 11 '22 16:10

Luis Crespo


I believe you may be looking for cancelAndHoldAtTime(). According to MDN:

The cancelAndHoldAtTime() property of the AudioParam interface cancels all scheduled future changes to the AudioParam but holds its value at a given time until further changes are made using other methods.

The added ability to hold the value until further changes are made seem to be what you are looking for. I'm using the web audio API to create an amplitude envelope right now and it seems to be working.

Note: as of August 2022, this function is only implemented in Chrome and Safari. See the compatibility table on MDN for updates. It does appear to be part of the official spec so it should be implemented across modern browsers eventually.

like image 22
intcreator Avatar answered Oct 11 '22 16:10

intcreator