Clockworx Music Nodes - some issues to solve

Hi, I have a problem, here is my code for one node:

class AudioTimeNode(bpy.types.Node):
    bl_idname = "AudioTimeNode"
    bl_label = "Time Info"
    bl_icon = "SPEAKER"

    time_num: bpy.props.FloatProperty(name="Time")
    frame_num: bpy.props.FloatProperty(name="Frame")

    def init(self, context):
        self.outputs.new("FloatNodeSocket", "Time")

    def draw_buttons(self, context, layout):
        layout.prop(self, "time_num")

    def execute(self):
        self.time_num = (
            bpy.context.scene.frame_current / bpy.context.scene.render.fps
        ) * bpy.context.scene.render.fps_base
        return self.time_num

This one feeds the values into my debug node, but this one:

class AudioControlNode(bpy.types.Node):
    bl_idname = "AudioControlNode"
    bl_label = "CM Control"
    bl_icon = "SPEAKER"

    cm_data = {}

    bpm : IntProperty(name="BPM", default=60)
    time_sig_num: IntProperty(name="Time Sig N", default=4)
    time_sig_den: IntProperty(name="Time Sig D", default=4)
    note_den : IntProperty(name="Note Denom.",min=1,default=16,max=64)
    message : StringProperty(name="Message")

    def init(self, context):
        self.outputs.new("GenericNodeSocket", "CM Data")

    def draw_buttons(self, context, layout):
        layout.label(text="Clockworx Control Node")
        layout.context_pointer_set("audionode", self)
        layout.operator("node.execute_start")
        layout.operator("node.execute_stop")
        layout.label(text="CM Constants")
        layout.prop(self, "bpm")
        layout.prop(self, "time_sig_num")
        layout.prop(self, "time_sig_den")
        layout.prop(self, "note_den")
        layout.operator("node.set_constants")
        layout.prop(self, "message")

    def execute(self):
        print(self.cm_data)
        return self.cm_data

Does not, I am confused as to why this is as the print statement prints the data:

Here is the Blender view:

The lower debug shows nothing, but the other two work. Does anyone have any thoughts as to what might be wrong. I have made my own new Node Editor to make music using Aud library.

Cheers, Clock.

EDIT:

I also have other nodes for Integers, Floats, Booleans, etc. that also all work fine.

Also I don’t seem to be able to output to two output sockets, both always have the same result although I send two variables in the return line separated by a comma, this is also driving me mad…

This section of nodes works fine, I am just so confused:

OK, no answers, hmmm. I’ll try again:

If I have an operator on a node, how do I tell the operator which node it is on?

Hmmm it seems nobody knows anything about nodes, does someone know where I might get some help in understanding the process, of course I can read the API docs, but I cannot find any examples, or even brief notes on principles.

I have managed to write my own node editor and a shed load of nodes to do stuff like build animations from MIDI files, make sounds from MIDI files, make procedural sounds, but my original question remains unanswered and that makes me very sad. :cry:

Some pictures:

Cheers, Very Sad Clock. :frowning_face: :sob:

This node reads the notes as drawn in the 3D view and makes a sound from them, that can be added to VSE, or added to the node tree and then filtered, or otherwise messed with before adding to VSE:

I am surprised nobody knows where to get a basic understanding of node building…

Cheers, Clock.

I think you should call someone to attention on this your thread, simply those who understand about nodes it have not seen it …

inevitably comes to my mind @jacqueslucke as an expert in nodes

1 Like

I think custom nodes currently have a lot of limitations, in that they are mostly UI elements in the node editor and don’t really support processing incoming data into outgoing data. The “everything nodes” project is probably going to help improve this situation, but right now you probably have to pull some tricks to get working what you want to do.

1 Like

@clockmender The execute method is called by your own code and not part of Blender’s API. I can’t tell why this is not behaving as it should. Maybe you can provide a link to your repository?
Also note that cm_data = {} defines a class property in AudioControlNode which is very different from the other properties like bpm, …

If I have an operator on a node, how do I tell the operator which node it is on?

You have to pass the node tree name, and the node name into the operator. Then you can find the node in the operator again.

2 Likes

Thanks for the replies chaps. Currently I am in VĂ«sterĂĄs airport on my way home, hence I have to type this on my phone. I have a handle that runs the execute function on frame change, but it only ever seems to pass one value, although it passes it twice!

Were this animation nodes I would know exactly what to do, but I am in the dark a lot here trying to figure out what drives what.

Once I get home I will upload the project to GitHub, it is early days for this still so some code is not up to standard yet.

Cheers, Clock

@jacqueslucke @PaulMelis.

I have done some cleaning of the code and uploaded to my Github:

I still have some issues that I should like some help with please:

  1. How to output multiple variables to multiple output sockets, I don’t seem to be able to find a way to do this. Outputting to one socket seems fairly straight forward, but I should like to output more than one socket as you can with Animations Nodes.

  2. Getting the node tree to execute either all the time, or at specified time intervals, or maybe only the nodes that have an execute, or sound_out function. I have worked out how to get the node tree to execute nodes with a specified function at frame change.

  3. How to place a UI menu in ONLY the Clockworx Node Editor, I am having trouble achieving this. This would be a good place for me to put checkboxes to control the node tree execution options I think.

  4. Stopping users connecting sockets that are not the same type.

I am very new to this, so some guidance as to where I am going wrong would be greatly appreciated.

In the meantime I have achieved a sound “Slicer” that allows the slicing of sounds into sections and then re-assembles them in a user defined order with an option to reverse some of them:

I also have a primate DAW function working that makes a sound from the “notes” as shown in the 3D View and then allows them to be added to the VSE:

Thanks for any help you can offer, like where to start looking for a process, whilst I can read the API, it does not give me a process to follow.

Cheers, Clock. :tumbler_glass:

EDIT:

I solved the issue of getting the parent node of an Operator BTW.

Help!!!

I want to put a poll on my menu so it only shows if it is in my new Node Editor, I know a need this:

def poll(cls, context):
    # Find the name of the editor
    return name == "Clockworx Node Editor"

Can someone tell me what to replace the commented line with please?

I have got this far with animating from a MIDI file, but I don’t want the menu to show in any other Node Editors:

Cheers, Clock.

can you assign a custom property to an area type? If so a combination of that plus a NODE_EDITOR check would be my guess, though I suspect custom properties cannot be applied to areas

return context.area.type == ’NODE_EDITOR’
1 Like

Hmm, apparently you can’t:

print(context.area["Test"])

TypeError: this type doesn't support IDProperties

So the type test is good, but the menu shows in all Node Editors, maybe I have to live with this…

EDIT:

This poll doesn’t work either, but the text in the execute works:

class CM_OT_ExecuteStartOperator(bpy.types.Operator):
    bl_idname = "cm_audio.execute_start"
    bl_label = "CM Execute Start"

    @classmethod
    def poll(cls, context):
        return "start_clock" not in bpy.app.handlers.frame_change_post

    def execute(self, context):
        scene = context.scene
        cm = scene.cm_pg
        if "start_clock" not in bpy.app.handlers.frame_change_post:
            bpy.app.handlers.frame_change_post.append(start_clock)
        view_lock()
        return {"FINISHED"}

Curious?

EDIT:

Well not so curious, of course I should not have put the function in quotes - blithering idiot clock!

Some updates:

)

I can now import keyboards, and build frets for guitars. I ave added menus to both the Node Editor and 3d View, progress is still on-going and not all updates are on my GitHub yet,

Cheers, Clock.

You can use context.space_data.tree_type to determine if your node editor is active (see in AN).

bpy.app.handlers.frame_change_post is a list of functions, not a list of strings. So the check "start_clock" not in bpy.app.handlers.frame_change_post does not make a lot of sense. You could check if the function is in the list, but it would probably be better to just use a separate global variable for that.

1 Like

Yes, I was being dumb, I changed it to this:

return start_clock not in bpy.app.handlers.frame_change_post

And it now works, thank you, I will look at how AN does this…

Thanks, Clock.

Brilliant Sir! This works:

class CM_PT_PanelDesign(Panel):
    bl_idname = "CM_PT_Menu_Node"
    bl_label = "CMN Operations"
    bl_space_type = "NODE_EDITOR"
    bl_region_type = "UI"
    bl_category = "CMN"
    bl_options = {'DEFAULT_CLOSED'}

    @classmethod
    def poll(cls, context):
        if context.space_data.tree_type != "AudioNodeTree":
            return False
        else:
            return True

    def draw(self, context):
        layout = self.layout
        cm_pg = context.scene.cm_pg
       # etc. etc.

Thank you so much! Clock. :tumbler_glass:

Even shorter:

@classmethod
def poll(cls, context):
    return context.space_data.tree_type == "AudioNodeTree"
2 Likes

You should still poll for the area type in addition (or guard it with hasattr), because if your space data doesn’t have a tree type attribute it will throw an exception.

1 Like

Roger Wilco!

@classmethod
    def poll(cls, context):
        return (context.space_data.tree_type == "cm_AudioNodeTree" and
            context.area.type == "NODE_EDITOR")

Thanks! Clock.

If you want to check it, you should first check the area type and then the tree type. Otherwise it does not help.

In any case, this check should not be necessary here afaik, because bl_space_type = "NODE_EDITOR" for the panel.