Jul 08 2012

Reaktor and the Partials Framework : Deconstructing the Raw Receiver

Category: Reaktor,Tutorialsmarv @ 6:50 pm

As part of the process of learning the Partials Framework im going to try and deconstruct some of the fundamental components to see how they work internally. This first series will focus on the Event Bus part of the framework.

All the files for this article are available in the archive you can download here.

If you haven’t read the documentation available with the partials framework then I suggest you read the ‘Event Blocks and the { b } Event Bus.pdf’ before reading the rest of this as it assumes you have a rough idea about the Event Bus system.

Raw Receiver

Im going to start with the ‘raw receiver’  which is part of the multiplexing -> core library. The purpose of this core macro is to ‘unmarshal’ messages sent on the event bus. It picks the messages apart into the header (id, length) and data and then distributes that data for further processing. Here’s what the macro looks like :

The one input is the event bus input, conventionally labelled { b } in the Partials Framework and 4 outputs :

  1. ID : The ID of the message.
  2. # : the length of the data block
  3. [] : current index into the data block, zero based
  4. $ : data value at the current index

These are symbols that you will see a lot in the partials framework so its worth getting used to what they generally mean.

In the download linked above there is a new version of the raw receiver in which I have renamed some of the ports and blocks to correspond more closely to their purpose in this situation, i’ll refer to this version throughout.

Going inside the raw receiver macro there are 3 macros used to do the work :

  1. Value Delay
  2. State Router
  3. State Action

These macros work together to function as a finite state machine. The Value Delay and State Router are relatively simple but are important to understand because they rely on some fundamental aspects of Core processing.

If you look at the original raw receiver macro you’ll see that some of the ports are labelled 0,1 and 2. These are state IDs and correspond to what state the machine is in. In the renamed version the ports use the names of the states (data, id, #) so you can see which data goes where.

The raw receiver has 3 states when unmarshalling a message that correspond to the 3 pieces of an Event Bus message. The initial state is 1 and is for the message ID, the next state is 2 and is for the message length and finally state 0 is for the data portion of the message. Both header parts of an Event Bus message (ID and length a.k.a #) are single integer values so the state machine is only in states 1 and 2 for the duration of one event each. State 0 lasts for as many events are in the data block, as specified by the # value.

As you might imagine any messages which don’t fit the correct format, such as not enough or too many data events, will almost certainly break the state machine

Now lets look at how each piece works and its role within the state machine.

Value Delay

The Value Delay is almost identical to the ‘Latch’ macro, except the OBC connection between the read and write memory blocks is connected the other way around. In the latch the write is the master and read is the slave but in the Value Delay the read is the master and the write is the slave. If you read the Core Reference docs on page 87 it says

One could ask what the difference is between master and slave. From the point of view of owning the shared object (in this case memory), there is no difference. However, as you may remember from a previous section of this manual, there is a rule that upstream mod­ules are processed before downstream modules when processing simultaneous events.

So whenever simultaneous events occur at the two inputs the latch will first write the event value and then read, i.e. store this new value and send out the new value, whereas the value delay will first read what is stored and then write the new value which means it will send out the old value and store the new one ready for the next clock event. Hence the name ‘value delay’.

A small test ensemble that demonstrates this is available in the download linked at the top of the article.

In the context of this state machine, the value delay is used to send the state ID to the state router. By delaying the output of the value until the next event in the message stream arrives this allows the state machine to define an initial state (in this case its actually 1) , process that event and then set the new state ID ready for when the next incoming event from the message stream arrives.

State Router

The State Router is the simplest piece of the puzzle and as its name implies does state based routing. Functionally its equivalent to the Router M->1 primary module. The state id input is for the state ID (in the original it is called []) and the $ input takes the event stream from the bus. As discussed earlier the 1 state is the ID output, the 2 state is for the data length and 0 is for data events. In the original the ports are named according to the state id’s : 0,1 and 2 but i’ve edited mine to reflect their purpose. I’ve included an ensemble in the download pack which has a raw receiver with these renamed ports (Raw Receiver – Renamed)

State Action

The State Action macro contains the heart of the state machine, its purpose is to both deliver the unmarshalled data to the appropriate output ports and to determine when a state change should occur. Inside it looks like this (again some of the ports have been renamed for clarity)

The inputs correspond to the states, so 0 is the message data, 1 is the id and 2 is the data length. I’ll start with the id state as that is the initial state of the machine. When the id event is received it is sent to both the ‘states’ macro and directly to the id output. The states macro is where the state transition logic happens. If you look inside its a very simple setup :

Note, i’ve added labels to the inputs which aren’t in the original macro. The ‘EOM’ input stands for End of Message and is a trigger sent when the whole message has been processed / consumed.

Starting from the right hand side there is a merge module with a constant 1 as its last input. This is used to define the initial state of the state machine, the 1 event will be sent during initialization to prepare the value delay with the right state ID.

The other 3 macros define the state transitions, so as the id event comes in it triggers the middle value macro which outputs 2 as the new state id. Next when the length event occurs the first value macro outputs 0 to transition into the data state and finally when the EOM event occurs the state machine returns to the starting state of 1. This just continues in a cycle as each message is handled. For example, with a message containing 2 data events there would be 2 header events and 2 data events. id, length, data_0 and data_1. The state of the machine would be 1,2,0,0 and then back to 1 ready for the next message.

Stepping back up a level to the State Action macro you’ll see that most of the work is the handling and output of the data events which happens in the { b } count macro. The actual output of data events is handled just the same as id and #, they’re just sent directly to the output. This means that the { b } count macro is responsible for 2 things : sending the data index out via the [] port  and sending the EOM event to trigger the transition from the data state (0) back to the initial state (1 : the id event state).

To be able to do both of these it has to count the incoming data events, hence the name :)

Inside it looks like this :

The increment macro just keeps count of data events and the ‘is EOM’ (renamed from init in the original) checks if the data index is equal to the length – 1. The increment macro is quite interesting inside and worth working out what its actually doing.

The # (length) event comes in at the top port, labelled 0. The reason its labelled zero is because it resets the counter inside this macro to zero. As you can see the read module doesn’t have an OBC connection, it just sends a zero out when an event arrives at the zero input. The other 3 memory modules are all OBC connected, which means they operate on the same piece of memory. The first write at the top writes the 0 when the # appears to reset the counter, then when a data event arrives at the second input, the current value is read from memory and sent to the output to be used as the data index, but its also written back into memory via the + 1 module which increments the internal counter. Of course this macro could be re-used anytime you need an event counter with a reset.

And that just about wraps it up, when the increment macro sends out an index value which is equal to # – 1, the { b} count macro send the EOM trigger to return the state machine back to the starting state and the next message can be processed.

The download contains 2 ensembles, 1 is the already mentioned Raw Receiver Renamed, which is just the raw receiver core macro with the renamed items. The other (Raw Receiver Test Setup) is a more complete ensemble which shows how to create a message and also contains a couple of event watchers so you can see exactly how the state transitions occur and how the data appears at the outputs.

One Response to “Reaktor and the Partials Framework : Deconstructing the Raw Receiver”

  1. marv says:

    Note : there is a thread on the NI Reaktor Forum here : http://www.native-instruments.com/forum/showthread.php?p=1057832

    Feel free to comment anywhere you like. :)

Leave a Reply