1

When trying to implement an ADSR envelop its easy to implement ADS Attack, Decay and Sustain as the timing of all those values are known at the same time. However if attempting to implement the Release part of this envelop I'm running into trouble.

The problem is that I've note on and note off events which are scheduled ahead of time. However AudioParams.linearRampToValueAtTime however only takes two arguments the time that the ramp should end and the value that it should end at.

How does one then produce a ramp that begins at a certain time?

/**
 * @param attack {int}
 * @param decay {int}
 * @param sustain {number} 0-100 percentage of overall level
 * @param release {int} time for volume to reach 0
 */
 function ADSR(attack, decay, sustain, release) {
    this.attack  = attack;
    this.decay   = decay;
    this.sustain = sustain;
    this.release = release;

    function applyTo(audioParam, time) {
        audioParam.linearRampToValueAtTime(1, time+attack);
        audioParam.linearRampToValueAtTime(this.sustain/100, time+attack+decay);
    }
    this.applyTo = applyTo;

    function applyRelease(audioParam, time, audioNode) {
        // here I want to apply the release starting at the time given
        // ending at time + this.time
    } 
    return time;
}
Wes
  • 6,697
  • 6
  • 34
  • 59

1 Answers1

2

According to the spec events are calculated in order, so if you have a setValueAtTime scheduled before a rampToValueAtTime the ramp will get calculated after that:

audioParam.setValueAtTime(audioParam.value, time);
audioParam.linearRampToValueAtTime(0, time+this.time);

If you are looking for something that ramps while keeping the current value in mind (the time to ramp depends on the difference between the value right now and the given target value), I recommend you to use the setTargetAtTime system. This should be usefull as the spec mentions it is for example useful in your situation:

Start exponentially approaching the target value at the given time with a rate having the given time constant. Among other uses, this is useful for implementing the "decay" and "release" portions of an ADSR envelope.

This calculates with a timeConstant, which defines how much time it should take to ramp to 1 - 1/e (around 63.2%).Use it like

audioParam.setTargetAtTime(<target_value>, <start_Time>, <timeConstant>);

The higher the time constant, the slower the transition is. I recommend you play around with the value to see what fits for your situation.

MarijnS95
  • 4,703
  • 3
  • 23
  • 47
  • The problem is I'd need to know what the value should be. Imagine the note was shorter than the attack+delay times. Then the release should only work from the current value of the param (gain in this exact case). I.e. the volume should be a smooth curve. – Wes May 11 '14 at 10:53
  • You mean the 1 value? `audioParam.value` – MarijnS95 May 11 '14 at 11:03
  • I'll try that out. I wonder if the cancel scheduled values A keeps the current value and B schedules new values aftewards – Wes May 11 '14 at 11:49
  • According to the spec it cancels ALL scheduled values after the given time. I have to test it, but I think that if a ramp starts BEFORE the given time it just keeps on going. – MarijnS95 May 11 '14 at 11:57
  • @Wes Is your problem solved now? As you might know the SO system works based on questioners that accept answers, so other users encountering the same answers can easily see if the answer solved the problem or that they'd better move on looking somewhere else. If it is not solved, please drop a comment to ask for more information/explanation. – MarijnS95 May 15 '14 at 15:22
  • I've been really busy at work. I've upvoted as its helpful but untested so I haven't accepted. – Wes May 15 '14 at 15:42
  • @Wes aha okay, thank you. I was checking all my answers wether there were any that required some attention (I have answered a lot of questions from new users lately, and neither one of them responded). – MarijnS95 May 15 '14 at 15:45
  • @MarijnS95 "I think that if a ramp starts BEFORE the given time it just keeps on going" - I don't think this is true. Just tested in latest Chrome (42) and it seems that the last value is retained, but the progression stops. It probably schedules future values, just as we do on the other side of the API. – Nikolay Tsenkov Apr 23 '15 at 05:46
  • @NikolayTsenkov I'll test that out too on the latest version. IIRC it wasn't like that a year ago (when I made the comment). – MarijnS95 Apr 23 '15 at 09:04