FModifierEnvelope control_points add and remove missing in the API


for my speaker_tools addon I’d like to be able to add and remove control points to an fcurve envelope modifier using the python API. This is not currently available… Unfortunately there is rust apon the rust of my C / C++ skills. I can remember enough to read the code and / or step thru the debugger to see whats going on, but am more than a little stuck when it comes to adding new functions.

Some notes.

Currently the code to add a control point is in


the button function ( fmod_envelope_addpoint_cb) uses a binary search to add the new control point, at the current frame, in the correct order or do nothing if a point already exists on that frame. This appears to be excess overhead, as I can simply edit the frame of added points to be on same frame or out of order, without any major problems albeit I haven’t tested this with complex envelopes.

My suggestion would be scrap this, and simply sort the UI and have an alert flag when two or more control points exist with same frame.

Then define the control_points add and remove methods in


this is where I get more than a little stuck.

Any help, tips, pointers would be most appreciated. Even a simple example to add a method to the control points collection that prints to the console would be extremely handy.


I can have a look at it while I’m drinking my morning coffee (~10 hrs from now).

Those things can get tricky since you need to get them at the right rna ‘scope’ to get pointers to the parent struct and things like that and there’s no real rules to figure it out other than see how other functions are implemented.

You need to do something like this:

Index: source/blender/makesrna/intern/rna_fcurve.c
--- source/blender/makesrna/intern/rna_fcurve.c    (revision 53968)
+++ source/blender/makesrna/intern/rna_fcurve.c    (working copy)
@@ -108,6 +108,8 @@
 #include "BKE_depsgraph.h"
 #include "BKE_animsys.h"
+#include "DNA_anim_types.h"
 static void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
     ID *id = ptr->;
@@ -633,6 +635,14 @@
     calc_fcurve_range(fcu, range, range + 1, FALSE, FALSE);
+static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FMod_Envelope *env, float frame)
+    return NULL;
+void rna_FModifierEnvelope_points_remove(FMod_Envelope *env, ReportList *reports, struct FCM_EnvelopeData *point)
 static void rna_def_fmodifier_generator(BlenderRNA *brna)
@@ -770,6 +780,34 @@
     /*    - selection flags (not implemented in UI yet though) */
+static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, PropertyRNA *cprop)
+    StructRNA *srna;
+    FunctionRNA *func;
+    PropertyRNA *parm;
+    RNA_def_property_srna(cprop, "FModifierEnvelopeControlPoints");
+    srna = RNA_def_struct(brna, "FModifierEnvelopeControlPoints", NULL);
+    RNA_def_struct_sdna(srna, "FMod_Envelope");
+    RNA_def_struct_ui_text(srna, "Control Points", "Control points defining the shape of the envelope");
+    func = RNA_def_function(srna, "add", "rna_FModifierEnvelope_points_add");
+    RNA_def_function_ui_description(func, "Add a control point to a FModifierEnvelope");
+    parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "",
+                         "Frame to add this control-point", -FLT_MAX, FLT_MAX);
+    RNA_def_property_flag(parm, PROP_REQUIRED);
+    parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Newly created control-point");
+    RNA_def_function_return(func, parm);
+    func = RNA_def_function(srna, "remove", "rna_FModifierEnvelope_points_remove");
+    RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope");
+    RNA_def_function_flag(func, FUNC_USE_REPORTS);
+    parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove");
+    RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
 static void rna_def_fmodifier_envelope(BlenderRNA *brna)
     StructRNA *srna;
@@ -784,6 +823,7 @@
     RNA_def_property_collection_sdna(prop, NULL, "data", "totvert");
     RNA_def_property_struct_type(prop, "FModifierEnvelopeControlPoint");
     RNA_def_property_ui_text(prop, "Control Points", "Control points defining the shape of the envelope");
+    rna_def_fmodifier_envelope_control_points(brna, prop);
     /* Range Settings */
     prop = RNA_def_property(srna, "reference_value", PROP_FLOAT, PROP_NONE);

@Uncle Entity.

Having probs with that patch using tortoise SVN on win32. After fixing a spaces for tabs issue, It comes up with a line mismatch. Could you zip up and post a file with the patch and resultant merge file?

Your help is much appreciated.

Huh, I guess BA messed up the tabs. The line mismatch was probably my fault though since I hand edited it to get rid of a commented out line. (1.16 KB)

Woooooooooo Hooooooooooooo

finally got this working… Thankyou once again for your help Uncle Entity, I wouldn’t have got anywhere without it.

The only feature I was unable to work out was how to make the current scene frame the default for add(frame) but dilligaf.

Here is the patch. Any testers would be most appreciated.

>>> fc =[0]

>>> fc.modifiers[0].type

>>> cp = fc.modifiers[0].control_points.add(
Add a control point to a FModifierEnvelope

>>> cp = fc.modifiers[0].control_points.add(55)
>>> cp['SoundAction.005']...FModifierEnvelopeControlPoint

>>> cp.frame

>>> fc.modifiers[0].control_points.remove(
Remove a control-point from an FModifierEnvelope

>>> fc.modifiers[0].control_points.remove(cp)

Attachments (1.69 KB)

In svn as of r54222

Big thanks to Uncle Entity, ideasman_42 and Aligorith for their help.