Andromatic Sequencing Logic
I have been studying the behaviour of Andromatic together with my fellow media archeologist Derek Holzer. In the video above I’m going through the workings of the Andromatic sequencer. In this post I attempt to explain this sequencer in more detail. The usage of pitch, gain and sustain knobs is not included here. Only how switch positions are used in generating different sequences.
Step modes and sequencer sections
Andromatic has an unconventional 10-step sequencer. For each step a switch is used to set the mode of the step. Possible modes are:
- BREAK (up)
- COUNT (middle)
- SHIFT (down)
First step of the sequencer differs from the rest. Possible modes for that are:
- BREAK (up)
- RESET (middle)
- COUNT (down)
The sequencer can have one ten step long section or several smaller and independent sections in series. There are three possible sections:
- Counter: one or more steps in COUNT mode. (For example CCCC)
- Shift register: the first step in BREAK mode, followed by steps in SHIFT mode. (BSSS)
- Alternating shift register: the first step in COUNT mode, followed by steps in SHIFT mode. (CSSS)
For example, if switches are set as CCCBSSSCSS, the sequencer is divided into three sections: CCC (3-bit counter), BSSS (4-bit shift register) and CSS (3-bit alternating shift register).
First section is always driven by the Andromatic master clock. Other sections will be iterated when the last step of the previous section falls from 1 to 0. In the example above, the 4-bit shift register will iterate when step 3 switches off:
011 1000 000
111 1000 000
000 0100 000 (2nd section will be triggered)
…
111 0001 000
000 1000 100 (both 2nd and 3rd sections will be triggered)
Besides triggering, data doesn’t flow from section to section.
Counter
A 3-bit counter (CCC) would cycle through the following set of combinations. Each combination will match to a binary representation of a number. The counter will count up numbers up from 0, then it will fold back to 0:
CCC
000 (0)
100 (1)
010 (2)
110 (3)
001 (4)
101 (5)
011 (6)
111 (7)
000 (0) (trig next section)
It is worth noting that each step in a counter section will be toggling half the rate of the previous step.
If we would use the full sequencer for one 10-bit counter section, we would count through numbers from 0 to 1023.
Shift register
When triggered, a shift register section (BSSS) will shift the memory contents one step to the right. Last bit will be cycled back to the beginning:
BSSS
1000
0100
0010
0001
1000 … (trig next section)
With different starting combination we could have:
BSSS
1100
0110
0011
1001
1100 … (trig next section)
Note that BREAK mode works similarly to SHIFT mode. It is a SHIFT mode step used to set the loop point (and beginning) of the register. Therefore it can only appear as the first step of a shift register section. Likewise the first step of the shift register section can not be set as SHIFT. This explains why SHIFT mode is not available for step 1.
Alternating shift register
This section type is most likely a byproduct of previously presented section types and not something that was considered when sequencer logic was put together. Still it can give quite useful results.
If the first step of a shift register section is a COUNT step (CSSS…) an infinitive row of alternating bits (1010101010…) will be shifted through the register. The output would be:
CSSSSSS
0000000
1000000
0100000
1010000
0101000
1010100
0101010
1010101
After the register is full, we keep on alternating last two arrangements:
0101010 (trig next section)
1010101
If a counter section is followed by a toggle shift register section, the last COUNT step should be considered to be part of a shift register section. For example CCCCCCSSSS is a 5-bit counter section (CCCCC) followed by a 5-bit toggle shift register section (CSSSS). The toggle shift section will iterate when the 5th step switches off.
Initialising
When the first step is set to RESET mode, all steps will be initialised as follows:
- SHIFT and COUNT steps will be set to 0
- BREAK (and RESET) step will be set to 1
For instance, switches set to RSSSBSSCBS will force the state to 1000100010.
Note: Steps in BREAK and RESET mode are internally wired differently than SHIFT and COUNT steps. In practice it means that switching the mode between these two groups will invert the state of those steps. For instance if a step is in COUNT mode:
- If state was 0 and the mode changed to BREAK, state will be 1.
- If state was 1 and the mode changed to BREAK, state will be 0.
Step 1 on mode RESET will always be set to 1. Changing mode to:
- BREAK, will keep it set up to 1
- COUNT, will set it to 0
Logic behind this wiring is that it forces the first step of a shift register to be 1 while forcing the remaining steps to be 0. Which is the typical starting position of all shift register based sequencer designs.
Software implementation
I wrote simple command line software for generating Andromatic sequences. The software will generate new states as long as it finds a loop point and will then print the sequence out. You can download the software from my Gitlab repository at:
https://gitlab.com/jarkesia/andromatic
Once compiled you can run it like this:
./andromatic BSSSSSC
BSSSSSC
1000000
0100000
0010000
0001000
0000100
0000010
1000001
0100001
0010001
0001001
0000101
0000011
1000000 => (0)
Sequence length: 12 steps.
The main logic of the program is inside this loop. It is worth noting that each step can be processed without truly knowing the context (the section type) it happens to be in.
while (true) {
bool shift = true;
bool df = true; // Data Forward DF
bool prevState = state[0];
bool tmp;
for (int i = 0; i < steps; i++) {
switch (mode[i]) {
case COUNT:
prevState = state[i];
if (df) {
state[i] = !state[i];
}
shift = df;
break;
case SHIFT:
tmp = state[i];
if (shift) {
state[i] = prevState;
}
prevState = tmp;
break;
case BREAK:
prevState = state[i];
if (df) {
int8_t b = i + 1;
while ( (b < steps) && (mode[b] == SHIFT) ) {
b++;
}
state[i] = state[b - 1];
}
shift = df;
break;
case RESET:
state[i] = 1;
shift = false;
df = false;
break;
}
df = (prevState != state[i]) && (state[i] == 0);
}
step++;
}