Now that you’ve seen how events travel through individual nodes, let’s look at the bigger picture: how they travel through a composition.
Quartz Composer provides less control than Vuo does over when patches execute. Patches typically execute in sync with a framerate, not in response to events. Patches typically execute one at a time, unless a patch has been specially programmed to do extra work in the background.
This section is about Vuo's mechanisms for control flow and concurrency.
Each event travels through a composition following a simple set of rules:
An event travels forward through cables and nodes. Along each cable, it travels from the output port to the input port. Within each node, it travels from the input ports to the output ports (unless it’s blocked). An event never travels backward or skips around.
One event can’t overtake another. If multiple events are traveling through the same cables and nodes, they stay in order.
An event can split. If there are multiple cables coming out of a trigger port or other output ports, then the event travels through each cable simultaneously.
An event can rejoin. If the event has previously split and gone down multiple paths of nodes and cables, and those paths meet with multiple cables going into one node, then the split event rejoins at that node. The node waits for all pieces of the split event to arrive before it executes.
An event can be blocked. If the event hits an event wall or door on an input port, then although it will cause the node to execute, it may not transmit through the node.
An event can travel through each cable at most once. If a composition could allow an event to travel through the same cable more than once, then the composition is not allowed to run. It has an infinite feedback loop error.
Let’s look at how those those rules apply to some actual compositions.
The simplest event flow in a composition is through a straight line of nodes, like the composition below.
In this composition, the Fired trigger port fires an event every 1 second. Each event travels along cables and through the Count node, then the integer-to-text type converter node, then Display Console Window node. The event is never split or blocked.
When you run a composition in Vuo, multiple nodes can execute at the same time. This takes advantage of your multicore processor to make your composition run faster.
In this composition, the two Count nodes are independent of each other, so it’s OK for them to execute at the same time. When the Fire Periodically node fires an event, the upper Count node might execute before the lower one, or the lower one might execute before the upper one, or they might execute at the same time. It doesn’t matter! What matters is that the Add node waits for input from both of the Count nodes before it executes.
The Add node executes just once each time Fire Periodically fires an event. The event branches off to the Count nodes and joins up again at Add.
In this composition, the Add node executes each time either Fire Periodically node fires an event. If one of the Add node’s inputs receives an event, it doesn’t wait for the other input. It goes ahead and executes.
If the two Fire Periodically nodes fire an event at nearly the same time, then the Count nodes can execute in either order or at the same time. But once the first event reaches the Add node, the second event is not allowed to overtake it. (Otherwise, the second event could overwrite the data on the cable from Add to Display Console Window before the first event has a chance to reach Display Console Window.) The second event can’t execute Add or Display Console Window until the first event is finished.
Compare this composition to the one above it. Since in this composition the Fire Periodically nodes can execute in either order, or at the same time, the results are unpredictable. When you want to ensure events are executed by separate nodes at the same time, use the same event.
You can use a feedback loop to do something repeatedly or iteratively. An iteration happens each time a new event travels around the feedback loop.
This composition uses a feedback loop to keep track of a count, which it prints upon a console window: 1, 2, 3, 4, . . .
The first time the Fire Periodically node fires an event, the inputs of Add are 0 and 1, and the output is 1. The sum, as a data-and-event, travels along the cable to the Hold Value node. The new value is held at the New Value port, and the event is blocked, as you can see from its event wall; Hold Value doesn’t transmit events from its New Value port to any output ports.
The second time the Fire Periodically node fires an event, the inputs of Add are 1 (from the Hold Value node) and 1. The third time, the inputs are 2 and 1. And so on.
Each event is only allowed to travel once through a feedback loop. When it comes back to the first node of the feedback loop, it needs to be blocked by a walled input port. If your composition isn’t set up like this, then Vuo will tell you there’s an infinite feedback loop and won’t allow your composition to run.
The above composition is an example of an infinite feedback loop. Any event from the Fire Periodically node would get stuck forever traveling in the feedback loop from the Add node’s Sum port back to the Item 1 port. Because there’s no event wall in the feedback loop, there’s nothing to stop the event. Every feedback loop needs a node like Hold Value to block events from looping infinitely.
If your composition has an infinite feedback loop, there are several ways you can fix it. Let’s walk through a composition where you encounter a feedback loop, and look at ways to solve it.
You can use Vuo’s Blend Images node to blend two images together. This first composition creates one checkerboard image, and the image moves across the window because events from the Fired trigger port are incrementing the count that becomes the X value of the 2D point that is the center of the checkerboard.
But you want to see the effect of taking the produced image from the Blend Images node and feeding it back into the Foreground input port of the node. If you try that, you see that you create an infinite feedback loop, because there is no event wall on the Foreground input port to stop an event from entering the node a second time.
So, let’s introduce a Hold Value and connect the output from the Blend Images to the New Value input port of the Hold Value node and the output from the Hold Value node to the Foreground input port of the Blend Images node. Now, what event source can we use? The composition has two nodes with trigger ports, the Fire Periodically and the Render Image to Window.
One strategy is to see if you can use the same trigger port that is already providing events to the node that will be part of the feedback loop. So, you can connect up the Fired trigger port to the refresh port of the Hold Value node.
This works. An event from the Fire Periodically node travels through the Count node to the Make Checkerboard Image node, to the Blend Images Node. The same event travels through a separate cable to the Hold Value node, and then to the Blend Images node. There the two events are joined.
Notice that the first event through the Hold Value node will output the value present at the Initial Value port (which has no image present), and the second event will output the value present at the New Value port. It’s not until the second event with its data reaches the Blended Images node that two images are blended. This is not important in this composition because the time between the first and second events reaching the node is small, but properly initializing your Hold Value nodes and understanding when the New Value port’s data will arrive may be important in other compositions you create.
What about using the trigger port from the Render Image to Window node? When you look at your composition, using an event from a different trigger port may work better. So, a second strategy is to see if you can use the trigger port of another node in your composition to provide events to your Hold Value node’s refresh port. This composition uses the events that are generated by the Render Image to Window node’s Requested Frame trigger port.
In this case, you can use the same stream of events into the Count’s Increment port, simplifying your composition. Using events from a Rendered Frame trigger port is usually the best way to provide events for any type of animation in your composition.
A third approach is to insert a Spin Off Event node into your composition to generate a separate event. This is covered in the section Run slow parts of the composition in the background.
In most cases, an event needs to travel through all of the cables leading up to a node before it can reach the node itself. (The one exception is the node that starts and ends a feedback loop, since it has some cables leading into the feedback loop and some coming back around the loop.) A problem can arise if the nodes and cables in a composition are connected in a way that makes it impossible for an event to travel through all the cables leading up to a node before reaching the node itself. This problem is called a deadlocked feedback loop. If your composition has one, Vuo will tell you so and won’t allow your composition to run.
This composition is an example of a deadlocked feedback loop. Because the top Hold Value node could receive an event from the Fire on Start node through the cable from the bottom Hold Value node, the top Hold Value node needs to execute after the bottom one. But because the bottom Hold Value node could receive an event from the Fire on Start node through the cable from the top Hold Value node, the bottom Hold Value node needs to execute after the top one. Since each Hold Value node needs to execute after the other one, it’s impossible for an event to travel through the composition. To fix a deadlocked feedback loop, you need to remove some of the nodes or cables involved.
You can control how your composition executes by controlling the flow of events. The way that you connect nodes with cables — whether in a straight line, a feedback loop, or branching off in different directions — controls the order in which nodes execute. The way that you fire and block events — with trigger ports and with event walls and doors — controls when different parts of your composition will execute.
Each event that’s fired from a trigger port has its own unique identity. The event can branch off along different paths, and those paths can join up again at a node downstream. When the same event joins up, the joining node will wait for the event to travel along all incoming paths and then execute just once. But if two different events come into a node, the node will execute twice. So if you want to make sure that different parts of your composition are exactly in sync, make sure they’re using the same event.