Attack and decay volume envelopes are interpolated linearly.

Issue #63 resolved
Somni created an issue

Any instrument that makes use of the volume attack or decay envelope beyond a tiny amount winds up having its volume set to almost nothing for most of the duration of the state, making it seem like it’s not playing at all for a while. This makes it sound off-beat, particularly noticeable on the “Slow Strings” instrument in any given GM SoundFont.

After some investigating, I discovered this block of code in ADSR.gd that determined the volume state of the instrument, at line 146:

var pre_state:Bank.VolumeState = use_state[state_number-1]
var s:float = ( state.time - self.timer ) / ( state.time - pre_state.time )
var t:float = 1.0 - s
self.current_volume_db = pre_state.volume_db * s + state.volume_db * t
break

It seems that the purpose here is to linearly interpolate between one volume state and the other. The reason why the majority of the attack envelope sounds silent is because decibels aren’t linear, hence the volume is usually in some range between -144.0 and -40.0, which is virtually silent or really hard to hear, esp. with other instruments going on at the same time; only once we start to move between the -40.0 to 0 range does the instrument become audible, hence why it seems to still gradually appear, just late and very quickly. So I decided to try interpolating the volumes by first converting them to linear, and then converting back to decibels:

self.current_volume_db = linear2db(lerp(db2linear(pre_state.volume_db), db2linear(state.volume_db), t))

Which solves the problem for the most part, except it makes every instrument echo too much. To solve that, I applied this fix only to the attack envelope and the decay envelope:

...
var t:float = 1.0 - s
if not self.releasing and all_states > 2 and (state_number == 1 or state_number == 2):
    self.current_volume_db = linear2db(lerp(db2linear(pre_state.volume_db), db2linear(state.volume_db), t))
else:
    self.current_volume_db = pre_state.volume_db * s + state.volume_db * t

Now the attack envelope is correctly ramping up linearly, the decay envelope is correctly ramping down linearly, and other envelopes continue to work as expected. Listen for the difference in the attached MIDI, with and without the fix; I also included a small SoundFont for uniformity in testing.

This fixes a number of other strange-sounding instruments, too. Any instrument that made use of attack or decay should sound a lot more on-the-beat now.

Comments (1)

  1. Log in to comment