-
Notifications
You must be signed in to change notification settings - Fork 5
3.2 Assign a UI control to multiple families
As of Koala v2.1.4, it is possible for the Developer to assign a single UI control to more than one Family. In order to be able to do this, you have to create your Families according to a specific set of instructions.
The following paragraphs will include some bitwise maths. In case you are not familiar with bitwise, don't freak out: Koala is going to take care of pretty much everything for you.
Let's dig into the concept of Family Masks. A Mask is a Family ID whose value is a power of 2. Koala features a set of pre-defined constants to let you assign these Tags as Family IDs. Please refer to this page for more info about these constants.
The concept behind this is: you can use bitwise values in order to access additional processing facilities (at a cost, which will be discussed further) such as:
- Create Subfamilies
- Create "folders of Families"
- Assign tags to Families
- Being able to process multiple Families at once
You can do pretty much anything you like, depending to how you want to organise your UI controls.
Like we said, Family Masks are simply some Family IDs whose value is powers of 2. Why are they power of 2? Let's see how bitwise operations work.
The powerful thing about bitwise is that you can use a single variable to load multiple sets of information. When dealing with bitwise, you don't care about the actual numeric value of a variable: the important thing is the bit representation of that value.
Powers of 2's bit representation follows this scheme (the bit representation is limited to 8 bits in this case; note that the last value has a whole set of zeroes after the shown bits!):
Dec number | Hex | Bit | Power of 2 |
---|---|---|---|
1 | 0x1 | 0000 0001 | 2^0 |
2 | 0x2 | 0000 0010 | 2^1 |
4 | 0x4 | 0000 0100 | 2^2 |
8 | 0x8 | 0000 1000 | 2^3 |
16 | 0x10 | 0001 0000 | 2^4 |
32 | 0x20 | 0010 0000 | 2^5 |
64 | 0x40 | 0100 0000 | 2^6 |
128 | 0x80 | 1000 0000 | 2^7 |
... | ... | ... | ... |
-2147483648 | 0x80000000 | 1000 0000 ... | -2^31 |
As you can see, each power of 2's bit representation is a long set of zeroes with only one '1'. Keep this in mind, as this is the base of everything.
Note that the last possible value is negative. We will cover this in a moment.
Using bitwise operators, we can combine, compare or process in any way two different powers of 2. The result will be interesting indeed.
Let's declare two Families that use Masks:
create_family(FAMILY_1, MASK.1)
create_family(FAMILY_2, MASK.2)
According to the table above, MASK.1
's value is 0x1
, while MASK.2
's value is 0x2
. We can combine these two Masks using the bitwise operator .or.
. The OR operator basically sums bit-by-bit two values:
Operands | Bit |
---|---|
MASK.1 |
0000 0001 |
MASK.2 |
0000 0010 |
MASK.1 .or. MASK.2 |
0000 0011 |
If you compare MASK.1
and MASK.2
bit-by-bit, you should come to realise that if at least one of the bit in the comparison is 1, the result of the .or.
operation on that particular bit will be 1. The only case where the result of the operation is 0 is when both the bits in the comparison are 0.
Consider, for instance, the bits in position 1 (all the way to the right). MASK.1
's bit in position 1 is 1; MASK.2
's bit in position 1 is 0; the result of the OR operation for that particular bit is 1, because at least one of the two bits in the comparison has value 1.
Bit in pos. 1 | |
---|---|
MASK.1 |
1 |
MASK.2 |
0 |
MASK.1 .or. MASK.2 |
1 |
So in order to apply a bitwise operator over two binary values, you have to perform a bit-by-bit comparison. The result of the comparison of each bit is the resulting bit mask.
Back to our Families now. We declared two Families using MASK.1
and MASK.2
as IDs. According to the operations above, we can assign a UI control both to FAMILY_1 (whose ID is MASK.1
) and to FAMILY_2 (whose ID is MASK.2
). This can be accomplished using the .or.
bitwise operator:
create_knob(knob_1, FAMILY_1 .or. FAMILY_2, 0, 100, 0, 10000, 0, 1, NOT_PERSISTENT, KNOB_UNIT_NONE, "This is a Knob")
Now, any modification we make either on FAMILY_1 or on FAMILY_2 will be applied to this knob as well. For instance, if we use the following Koala function:
shift_family(FAMILY_1, 0, 70)
knob_1
will be shifted by 70 px on Y-axis, because it belongs to FAMILY_1
too.
On the other hand, if you want to access to more than one Family at a time, you may use:
shift_family(FAMILY_1 .or. FAMILY_2, 0, 70)
This operation will shift every UI control belonging to any of the chosen Families by 70 px on Y-axis. So in this case every UI control belonging either to FAMILY_1
or to FAMILY_2
will be shifted.
The most evident bottleneck when dealing with this kind of processing is pretty simple and logical, but let's take a quick trip into some additional bitwise maths in order to understand the issue.
As of today, Kontakt is a 32-bit application. When you declare an integer variable in Kontakt, its value can be either positive or negative, meaning that Kontakt allows you to declare signed integer variables. The sign of each possible value is represented by the bit all the way to the left (Most Significant Bit). Consider the following bit values:
0111 1111 1111 1111 1111 1111 1111 1111 // _MAX_KSP_VALUE: equals to 2^31 - 1
1000 0000 0000 0000 0000 0000 0000 0000 // _MIN_KSP_VALUE: equals to -2^31
These two values are the edge values that can be represented in Kontakt. Any value greater (or smaller) than these cannot be represented, because there are simply not enough bits to represent it.
Let's translate this matter into bitmasks and Masks. Like we said before, each Mask is a power of 2 value, whose bit representation includes all zeroes except for a single, individual 1. The Masks system works merely on this principle. Since in Kontakt we have only 32-bit integers, we are limited to 32 maximum Masks. There are simply not enough bits to represent more than 32 Masks.
Remember when I told you to note that the latest available mask is negative? Now you know why!
You should be aware of that when dealing with instruments with lots of graphics, although if you organise the controls in Families and "Subfamilies" you should be good in any possible way.