The Processing Cycle
Thanks to Robin Gareus' advice and help, Zrythm uses a processing algorithm that depends on an acyclic graph of ports. This algorithm splits processing jobs into threads and processes each node until the terminal nodes are reached and there are no more "trigger nodes". The algorithm is explained in detail below.
The processing Graph is an acyclic graph of GraphNode's. The graph is re-created every time there is a change in connections. When the graph gets (re)created, it goes through the project and finds all nodes that should be added to it and adds them, then creates NUM_CPU_CORES - 1 threads for processing trigger nodes (see below).
When these ports are connected, during processing, the signals from the source port are summed into the destination port. What this means in practice depends on the PortType. For audio, the signal is simply added to the existing one. For event/MIDI ports, the MidiEvent's from the source port are appended to the events of the destination port.
Processors are the other type of node in the graph and have input ports routing to them and output ports being routed from them. Unlike Port nodes, which simply sum their inputs, processors apply some processing to their inputs and update their outputs. Examples are TrackProcessor, Fader and Plugin.
Input ports routed to processors are processed in the same way as any other Port, in that they simply sum their inputs. When the processor does its processing, its input ports are already filled in and ready to use.
When the processor finishes processing, it writes the output into its output ports. A processor routes to output Port's in the graph.
Terminal nodes are nodes that don't route to any other node.
Trigger nodes are nodes that should be processed first. When they are processed, they are marked as processed and the reference count of the nodes they point to is decremented. When the reference count of a node becomes 0 (meaning it has no incoming connections), it becomes a trigger node. When the graph is constructed, it must have at least 1 trigger node.
When there are no more trigger nodes left, the processing cycle is completed.