8voice64step

8 voice 64 step sequencer. select "usb host port 1" in the dropdown to connect to the Launchpad (only tested with Launchpad S). Via the top-row of buttons the first, second, third, ... 8 steps can be selected (each row represents a single voice -> all 8 voices are displayed at once). Via the side-row of buttons the first, second, third, ... voice can be selected (the 64 buttons represent the whole sequence). push a button to enable/disable step. Via the toggle button of the UI you can choose to sync to an extern midi clock.
Author: Beat Rossmy
License: BSD
Github: beat/midi/ctrl/lpad/seq/8voice64step.axo

Inlets

bool32.rising trigger next step

Outlets

bool32 gateA

bool32 gateB

bool32 gateC

bool32 gateD

bool32 gateE

bool32 gateF

bool32 gateG

bool32 gateH

Parameters

bool32.tgl sync to extern midi clock

Attributes

combo device

Declaration
bool externSync;

int32_t pos;
int32_t pos_shadow;
bool triggered;

int8_t voice;
int8_t part;
uint64_t pattern[8];

uint8_t top;
uint8_t lastTop;
uint8_t side;
uint8_t lastSide;
uint64_t matrix;
uint64_t lastMatrix;

uint64_t line;
uint64_t dot;

void outputMatrix(uint64_t last, uint64_t current) {
  uint64_t difference = last ^ current;
  if (difference != 0) {
    for (int b = 0; b < 64; b++) {
      if ((difference >> b) & 1 == 1) {
        if ((current >> b) & 1 == 1)
          MidiSend3((midi_device_t)attr_device, MIDI_NOTE_ON + 0,
                    (b / 8) * 16 + (b % 8), 127);
        else
          MidiSend3((midi_device_t)attr_device, MIDI_NOTE_OFF + 0,
                    (b / 8) * 16 + (b % 8), 0);
      }
    }
  }
}

void outputTop(uint8_t last, uint8_t current) {
  uint8_t difference = last ^ current;
  if (difference != 0) {
    for (int b = 0; b < 8; b++) {
      if ((difference >> b) & 1 == 1) {
        if ((current >> b) & 1 == 1)
          MidiSend3((midi_device_t)attr_device, MIDI_CONTROL_CHANGE + (0 & 0xF),
                    104 + b, 63);
        else
          MidiSend3((midi_device_t)attr_device, MIDI_CONTROL_CHANGE + (0 & 0xF),
                    104 + b, 0);
      }
    }
  }
}

void outputSide(uint8_t last, uint8_t current) {
  uint8_t difference = last ^ current;
  if (difference != 0) {
    for (int b = 0; b < 8; b++) {
      if ((difference >> b) & 1 == 1) {
        if ((current >> b) & 1 == 1)
          MidiSend3((midi_device_t)attr_device, MIDI_NOTE_ON + 0, b * 16 + 8,
                    127);
        else
          MidiSend3((midi_device_t)attr_device, MIDI_NOTE_OFF + 0, b * 16 + 8,
                    0);
      }
    }
  }
}

void allLedsOff() {
  MidiSend3((midi_device_t)attr_device, MIDI_CONTROL_CHANGE + (0 & 0xF), 0, 0);
}
Init
pos = 0;
pos_shadow = -1;
triggered = false;

line = 0x0101010101010101;
dot = 0x0000000000000001;

voice = -1;
part = 0;

top = 0;
lastTop = 0;
matrix = 0;
lastMatrix = 0;

allLedsOff();
Control Rate
externSync = param_sync;

if (true) {
  outlet_gateA =
      ((pattern[7] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateB =
      ((pattern[6] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateC =
      ((pattern[5] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateD =
      ((pattern[4] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateE =
      ((pattern[3] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateF =
      ((pattern[2] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateG =
      ((pattern[1] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
  outlet_gateH =
      ((pattern[0] >> pos) & 0x1 == 1 && pos_shadow % 6 < 2) ? 0x07FFFFFF : 0;
}

if (externSync == 0 && inlet_triggerIn && !triggered) {
  pos_shadow++;
  pos = (pos_shadow / 6) % 64;
  triggered = true;
  // LogTextMessage("position:%d",0x1<<pos);
}

if (triggered) {
  /*PARTVIEW*/
  if (part >= 0) {
    /*MATRIX*/
    matrix = 0;
    uint64_t mask = 0xFF;
    for (int y = 0; y < 8; y++) {
      matrix = matrix |
               (((pattern[y] & (mask << (part * 8))) >> (part * 8)) << (y * 8));
    }
    if ((part + 1) * 8 > pos && part * 8 <= pos)
      matrix = matrix | (line << (pos % 8));
    outputMatrix(lastMatrix, matrix);
    lastMatrix = matrix;

    /*TOP*/
    top = 0x1 << part;
    top = top | (0x1 << (pos / 8));
    outputTop(lastTop, top);
    lastTop = top;

    /*SIDE*/
    side = 0;
    outputSide(lastSide, side);
    lastSide = side;
  }
  /*VOICEVIEW*/
  else {
    /*MATRIX*/
    matrix = pattern[voice] | dot << pos;
    outputMatrix(lastMatrix, matrix);
    lastMatrix = matrix;

    /*TOP*/
    top = 0;
    outputTop(lastTop, top);
    lastTop = top;

    /*SIDE*/
    side = 0x1 << voice;
    outputSide(lastSide, side);
    lastSide = side;
  }
}

if (!inlet_triggerIn && triggered) {
  triggered = false;
}
Midi Handler
if (externSync == 1) {
  if (status == MIDI_TIMING_CLOCK) {
    pos_shadow++;
    pos = (pos_shadow / 6) % 64;
    triggered = true;
  } else if (status == MIDI_START) {
    pos = 0;
    pos_shadow = -1;
    // triggered = true;
    LogTextMessage("START");
  } else if (status == MIDI_STOP) {
    pos = -1;
    // triggered = true;
    LogTextMessage("STOP");
  }
}

if ((status == MIDI_NOTE_ON + attr_midichannel) && (data2)) {
  int y = data1 / 16;
  int x = data1 % 16;
  uint64_t target = 1;
  if (part > -1) {
    if (y < 8 && x < 8)
      pattern[y] = pattern[y] ^ (target << ((part * 8) + x));
  } else if (voice > -1) {
    if (y < 8 && x < 8)
      pattern[voice] = pattern[voice] ^ (target << (x + y * 8));
  }
  if (x == 8) {
    part = -1;
    voice = y;
  }
} else if ((status & 0xF0) == MIDI_CONTROL_CHANGE) {
  voice = -1;
  part = data1 - 104;
}

Privacy

© 2023 Zrna Research