D♭ Tutorial: BATCH FUNCTIONS

The previous tutorial introduced the @ operator to access the attributes of entities. In this tutorial we will learn to use functions in a similar fashion. Just as @velocity = 0.3 sets the gain for all entities in the working set, the @ prefix can be used to apply a function to all entities in the working set. In the end of this tutorial, we will be able to produce a sequence of tones.

Split (with count)

Each entity has a span attribute. It represents the tone duration in seconds.

0
C-1
Code Editor
0.000
0
C-1
Code Editor
0.000

Next to span, each entity has a time property as well. It determines when the tone will be played. It is basically an offset from the song start in seconds.

time is rarely used directly in code. Most of the time, functions like Split take care of setting it properly. Split is the first function of D♭ you encounter. It divides an entity into a sequence of shorter entities, so that in sum they cover the whole span of the original entity.

0
C-1
Code Editor
0.000

Now we finally hear more than a single tone, but playing a shorter version of the input tone four times is not very exciting. Then can be called on the result of Split in order to directly manipulate the produced entites. For example, we may shorten them even more.

0
C-1
Code Editor
0.000

Then consumes a transformer function. It is applied to all entities produced by the Split. Note that as a result of the Split, the span values of all four entities equal 1 second at the time of the compound multiplication *= .

The transformer may be also used with an Indexer parameter that allows easy distinction of the produced entities. The indexer has two basic data properties: Index and Max. The latter carries the highest index number in this Split call.

0
C-1
Code Editor
0.000

The Indexer also offers a few computed properties that come handy in common situations: Relative represents the index progress in the range of [0, 1], IsFirst, IsLast, IsEven and IsOdd are self-explanatory.

To keep the syntax simple, Indexer is implicitly casted to an int if used without any of its properties. In the following example, this is demonstrated by the expression 1 + idx. It shortens the span with increasing index. Note the addition of one to avoid division by zero.

0
C-1
Code Editor
0.000

Split (with lengths)

Instead of a regular division resulting in equally sized entities, Split can also take an array of relative durations and distribute the available time span proportionally. Alternatively, the durations can be also passed as separate method parameters. The following sequence will sound like a famous Morse code.

0
C-1
Code Editor
0.000

There is an even more advanced concept that involves three different sizing types that can mix together: FILL, REL, ABS. So far the spans were just relative to each other. This would correspond to the FILL mode. The FILL mode involves normalization of the values so that they exactly fit the duration of the input entity.

0
C-1
Code Editor
0.000

REL has a higher priority than FILL. The values are relative to the duration of the input entity. If their sum is > 1.0 (i.e. the input duration), normalization is applied to the relative items to scale them down so that they exactly cover the input duration and at the same time all fills are neglected. If the sum of REL items is < 1.0, the unoccupied space is assigned to the FILL items. If there are no FILL items, then REL items are scaled up to cover the whole input duration.

0
C-1
Code Editor
0.000

ABS has the same priority like REL. The values are in absolute time units, i.e. in seconds. If the sum of ABS and REL items is higher than the available span, normalization is applied to scale them down and all fills are neglected. Otherwise, either fills are used to cover the unoccupied space or, if no fills are persent, then ABS and REL items are scaled up to match the input duration.

0
C-1
Code Editor
0.000

Advanced sizing modes FILL, REL and ABS are useful for higher structuring of music pieces with complex structures where further layers of splitting follow. The examples above with single notes are provided just as toy examples for easy demonstration.

Batch processing

D♭ functions are also called batch functions as they process all entities in the working set in a single batch. Without going into any formal details, note that there is a relation to L-Systems.

The following example demonstrates the power of batch processing of the whole working set. The first Split divides the span into parts that could correspond to measures. In the spirit of batch processing the second Split divides each of the measures into beats.

0
C-1
Code Editor
0.000

We can use both indexes to make the rhythm a bit more interesting. Every second measure will double the third beat.

0
C-1
Code Editor
0.000

There are a few more built-in functions which will be introduced in this and in the following tutorials, but most of the functions you will design by yourself as custom functions.

Custom Functions

Just like with attributes, you can define custom functions and apply them to the entities. When calling custom functions they need by prefixed with @ just like the built-in commands. The folowing example shows the custom function Bursts.

0
C-1
Code Editor
0.000

The usage of Bursts can be integrated into the Then transformer. We can omit measureIndex as a helper attribute and make it directly an argument of 'Bursts`.

0
C-1
Code Editor
0.000

The usage of Bursts can be improved even more. It can be directly passed as the transformer by replacing int measureIndex by Indexer idx. Note that Bursts is passed as a function reference, hence the @ prefix must be omitted. Otherwise, it would be executed right away (i.e. its result would be expected to be passed to Then) which would result in an error.

0
C-1
Code Editor
0.000

Watch out for invalid function names. Some identifiers are reserved for other data structures. Using them as custon function names would result in an error. These are names of helper structures like: Melody, Rhythm which will be iontroduced in some of the intermediate tutorials or built-in functions like Split or Rest. The following example demonstrates the situation when a custom function name conflicts with a helper structure resulting in an error.

0
C-1
Code Editor
0.000

Rest

All the entites we generated so far were actual sounds. But music contains many rests that serve different purposes: they grant time to breate, they convey rhythm, they switch off instruments to produce certain colors.

The Rest function simply converts entites to rests. They keep all attributes, but one: chord, which is discussed in the harmony tutorial, gets a special value to represent the rest. This is a much better practice than a full removal of an entity, as only the original chord information gets lost, but anything else is preserved.

0
C-1
Code Editor
0.000

Done

As Split produces many entities, it is sometimes usefull to mark some of them terminals. That means that they are considered to be in their final state and no more D♭ function or attribute assignemnt can change them. As if they would be deactivated.

In the following example Done is used to deactivate bursts with an odd number of tones. Done bursts will not be played by the french horn.

0
C-1
Code Editor
0.000

Use Done with caution, it can easily cause confusion in case you forget about it or some one else working with your code misses it. Usually there are better ways to deal with exclusion of a subset of entities. Local temporary exclusion should be preferred over Done. For example, the previous example can be rewritten using a local conditional.

0
C-1
Code Editor
0.000

In the next tutorial we will utilize the attributes and functions for producing simple melodies.