Arrays in Reaktor, Part I
As is often the case, Part I of this series is a little slow, as I explain the purpose of the project and the problems we will encounter. Next week we’ll pick up the pace some, I promise!
An array is a module that can be used to store a large number of values. Arrays can have any number of uses, but a common one is storing incoming audio into a buffer for later use, such as in a delay line.
In Reaktor, there a number of ways to store large amounts of data – the Event and Audio Tables, the Tapedeck modules, and Core Arrays. While the other modules have their purposes, Core Arrays are more powerful than their Primary counterparts in that they allow for multiple access points of data, and can force an order of operations that would be difficult to replicate in Primary. We’ll get into why that’s important in just a bit.
[aside title = “Pro Tip”]Core Arrays can be more powerful than their primary counterparts[/aside]
There are several ways that a programmer may wish to manipulate data in an array. Examples include adding new values, deleting old ones, inserting values in between existing values, sorting data (such as from highest to lowest), etc.
Unfortunately, shortcomings within the Reaktor environment make many of these basic operations quite difficult. It is my intention to create a simple framework to manipulate data in this tutorial series. Eventually, I hope to use the framework to create a multi-breakpoint envelope, where the array holds information about the number of stages the user has specified.
It will be necessary to allow the user to delete and insert data points at will for this project, which makes it a perfect fit for the data framework I would like to build. If you are unfamiliar with the concept of a multi-breakpoint envelope, you can check the macro “Multi-BP Env” in Reaktor, or if you have Absynth, the envelopes in that are another example. There is also a tutorial series on envelopes here that fully outlines the different stages of an envelope.
Let’s tackle the different types of data operations one by one.
Adding a new element to an array can be done in any number of ways. There is a distinction between adding a new element to the end of an array (called adding) and adding a new element somewhere that another element is already stored (called insertion).
Adding is the simplest of our data operations, so we’ll tackle it first. I often like to start such a project by imagining a ‘black box’ macro that has inputs for each piece of information I need to accomplish something, and whatever outputs are necessary:
To add a new element, we need the value we want to add to the array, the current number of elements stored, and access to the array itself. The outputs are simply updated versions of the Idx and Data inputs. If data operations need to be done in a specific order, the outputs can be used to control the inputs of other macros, as we shall see eventually.
Now let’s think about what the inside of this macro should look like. We have a value (Idx) that gives the current number of objects stored in the array. We want to store the data in that index, and then increase the value of Idx by 1 – for example, if there are no elements currently stored, we store at index 0, then add 1 so the next element will be added at index 1.
Each event arriving at the value input will store to a new point in the array. One caveat is that the array must be large enough such that the value of Idx is not out of bounds. If Idx is greater than the array size, the data will overwrite the last element.
The easiest solution to this is simply to create an array way larger than you need – for example, if the array can hold 5000 elements, it seems unlikely that anybody would take the time to create that many stages of a multi-breakpoint envelope. If, for whatever reason, this is not a workable solution, you can also modify the structure slightly:
In this example, if there is no space left in the array, the input is simply ignored. Another common way to handle this problem is to simply wrap around the structure, so if the index is too large, simply start writing over the beginning of the array again. This type of array write is used quite commonly, especially with delay lines.
Despite being very similar, these are three distinct macros that can be used for different purposes. Any one of them can be connected like so:
This week we covered the easy stuff. Next time, we’ll be working with Primary iterators to control some more exciting and complex data operators. There are other problems to be solved as well, such as storing our arrays into Primary Snap Value Arrays, to allow them to be saved as snapshots.
Have a Question or Comment About This Tutorial?
Want to ask a question about this tutorial or perhaps you have something to add?
Click through to our forum post about this tutorial and join the conversation!
Visit: Arrays in Reaktor, Part I