ASREnvelope Node type to animate the Loudness of a continuous Sound, and other Things.
I started with an ADSR Envelope (Attack, Decay, Sustain, Release) but i have since removed Decay because the Attack Curve can easily represent both Attack and Decay.
Question
My work-in-progress Node of type ASREnvelope stores 2 versions of the Release Curve:
Inspector Property release_curve
Private variable _scaled_release_curve
The private copy is derived from the public original, using this function:
Note how this function copies each value from the original Curve before it scales the result.
I want to duplicate the whole Curve instead of its singular values
but i don’t know how to do that without changing the original Curve too.
Curve inherits duplicate() from Resource, so release_curve.duplicate() gives you an independent copy with the points, tangents, tangent modes, and the domain and value ranges already carried across. Editing the copy leaves the original alone.
That collapses the function down to a duplicate plus one pass over the points:
_scaled_release_curve = release_curve.duplicate()
for i in _scaled_release_curve.get_point_count():
var y := _scaled_release_curve.get_point_position(i).y
_scaled_release_curve.set_point_value(i, _scale_value.call(y))
set_point_value() only writes the Y, so the X offsets stay put without you rebuilding each point.
Building on top of your answer, my goal was to refactor the function so that i could use it for both Curves (Attack and Decay).
It’s typewritten like this now:
var _scale_curve: Callable = func(curve: Curve) -> Curve:
var _scale_point_value: Callable = func(value: float) -> float:
return remap(
value,
curve.sample(curve.get_max_domain()),
curve.sample(curve.get_min_domain()),
curve.sample(curve.get_max_domain()),
sample,
)
var _output_curve: Curve = curve.duplicate()
for _point in curve.get_point_count():
var _y : float = curve.get_point_position(_point).y
_output_curve.set_point_value(
_point, _scale_point_value.call(_y)
)
return _output_curve
Notes:
The function no longer changes the _scaled_release_curveby itself.
It now returns a scaled version of the input curve,
so this line outside the function sets _scaled_release_curve:
I remembered that i started coding this Add‑on before Godot 4.4.
Godot 4.4 added the min_domain and max_domain properties to Curve,
so i changed the Lookup of Curves’ first Position and last Position to a simpler Way,
how i would have done it if i started the Project today.