switched

Switching drawbars at hammond intervals. Note that the key switches do not open/close at exactly the same moment, but are spread over maximum 2.666 milliseconds.
Author: Johannes Taelman
License: BSD
Github: jt/drawbars/switched.axo

Inlets

None

Outlets

None

Parameters

frac32.u.map 0: no velocity, 64: full velocity dependent

frac32.u.map 16', suboctave, -12ST

frac32.u.map 5 1/3', 5th, +7ST

frac32.u.map 8', unison, principal

frac32.u.map 4', 8th, octave, +12ST

frac32.u.map 2 2/3',12th, nazard, +19ST

frac32.u.map 2', 15th, blockflote, +24ST

frac32.u.map 1 3/5', 17th, tierce, +28ST

frac32.u.map 1 1/3', 19th, +31ST

frac32.u.map 1', 22nd, +36ST

Attributes

spinner startNote

spinner endNote

Declaration
static const int ntw = 128;
static const int nkeys = 128 + 48;
int16_t keys[nkeys];
int32_t *array;
uint32_t sustain_notes[4];
bool sustain_pedal;
static const uint32_t LENGTHPOW = 7;
static const uint32_t LENGTH = 1 << LENGTHPOW;
static const uint32_t LENGTHMASK = (1 << LENGTHPOW) - 1;
static const uint32_t BITS = 32;
static const uint32_t GAIN = 0;

int32_t r_array[ntw + 48];
int32_t velosense = 0;
const int keyoffset = 36;
int cycle = 0;

__attribute__((always_inline)) __STATIC_INLINE int32_t _SMLABB(int32_t op1,
                                                               int32_t op2,
                                                               int32_t op3) {
  int32_t result;
  __ASM volatile("smlabb %0, %1, %2, %3"
                 : "=r"(result)
                 : "r"(op1), "r"(op2), "r"(op3));
  return (result);
}

__attribute__((always_inline)) __STATIC_INLINE int32_t _SMLABT(int32_t op1,
                                                               int32_t op2,
                                                               int32_t op3) {
  int32_t result;
  __ASM volatile("smlabt %0, %1, %2, %3"
                 : "=r"(result)
                 : "r"(op1), "r"(op2), "r"(op3));
  return (result);
}

__attribute__((always_inline)) __STATIC_INLINE int32_t _SMLATB(int32_t op1,
                                                               int32_t op2,
                                                               int32_t op3) {
  int32_t result;
  __ASM volatile("smlatb %0, %1, %2, %3"
                 : "=r"(result)
                 : "r"(op1), "r"(op2), "r"(op3));
  return (result);
}

__attribute__((always_inline)) __STATIC_INLINE int32_t _SMLATT(int32_t op1,
                                                               int32_t op2,
                                                               int32_t op3) {
  int32_t result;
  __ASM volatile("smlatt %0, %1, %2, %3"
                 : "=r"(result)
                 : "r"(op1), "r"(op2), "r"(op3));
  return (result);
}
Init
array = &r_array[0];

int i;
for (i = 0; i < nkeys; i++) {
  keys[i] = 0;
}
for (i = 0; i < ntw; i++) {
  array[i] = 0;
}
Control Rate
velosense = param_velosense << 3;

param_f1 <<= 3;
param_f2 <<= 3;
param_f3 <<= 3;
param_f4 <<= 3;
param_f5 <<= 3;
param_f6 <<= 3;
param_f7 <<= 3;
param_f8 <<= 3;
param_f9 <<= 3;

int32_t f12 = (param_f1 >> 16) + (param_f2 & 0xFFFF0000);
int32_t f34 = (param_f3 >> 16) + (param_f4 & 0xFFFF0000);
int32_t f56 = (param_f5 >> 16) + (param_f6 & 0xFFFF0000);
int32_t f78 = (param_f7 >> 16) + (param_f8 & 0xFFFF0000);
int32_t f90 = (param_f9 >> 16);

int offset = cycle & 0x7;
cycle++;
int i;
for (i = offset << 1; i < nkeys; i += 16) {
  int32_t a1 = 0;
  int32_t a2 = 0;
  int32_t k12;

  k12 = *((int32_t *)&keys[i + 12 + keyoffset]);
  a1 = _SMLABB(k12, f12, a1);
  a2 = _SMLATB(k12, f12, a2);
  k12 = *((int32_t *)&keys[i - 7 + keyoffset]);
  a1 = _SMLABT(k12, f12, a1);
  a2 = _SMLATT(k12, f12, a2);

  k12 = *((int32_t *)&keys[i + keyoffset]);
  a1 = _SMLABB(k12, f34, a1);
  a2 = _SMLATB(k12, f34, a2);
  k12 = *((int32_t *)&keys[i - 12 + keyoffset]);
  a1 = _SMLABT(k12, f34, a1);
  a2 = _SMLATT(k12, f34, a2);

  k12 = *((int32_t *)&keys[i - 19 + keyoffset]);
  a1 = _SMLABB(k12, f56, a1);
  a2 = _SMLATB(k12, f56, a2);
  k12 = *((int32_t *)&keys[i - 24 + keyoffset]);
  a1 = _SMLABT(k12, f56, a1);
  a2 = _SMLATT(k12, f56, a2);

  k12 = *((int32_t *)&keys[i - 28 + keyoffset]);
  a1 = _SMLABB(k12, f78, a1);
  a2 = _SMLATB(k12, f78, a2);
  k12 = *((int32_t *)&keys[i - 31 + keyoffset]);
  a1 = _SMLABT(k12, f78, a1);
  a2 = _SMLATT(k12, f78, a2);

  k12 = *((int32_t *)&keys[i - 36 + keyoffset]);
  a1 = _SMLABB(k12, f90, a1);
  a2 = _SMLATB(k12, f90, a2);

  array[i] = a1;
  array[i + 1] = a2;
}
Midi Handler
if ((status == MIDI_NOTE_ON + attr_midichannel) && (data2)) {
  if ((data1 >= attr_startNote) && (data1 <= attr_endNote)) {
    keys[data1 + keyoffset] =
        __SMMLA(velosense, data2 << 24, 0x1FFFFFFF - (velosense >> 1)) >> 16;
    int j = data1 >> 5;
    int k = data1 & 0x01F;
    sustain_notes[j] |= 1 << k;
  }
} else if (((status == MIDI_NOTE_ON + attr_midichannel) && (!data2)) ||
           (status == MIDI_NOTE_OFF + attr_midichannel)) {
  if ((data1 >= attr_startNote) && (data1 <= attr_endNote)) {
    int j = data1 >> 5;
    int k = data1 & 0x01F;
    sustain_notes[j] &= ~(1 << k);
    if (!sustain_pedal) {
      keys[data1 + keyoffset] = 0;
    }
  }
} else if ((status == attr_midichannel + MIDI_CONTROL_CHANGE) &&
           (data1 == 64)) {
  if (data2 & 0x40) {
    sustain_pedal = 1;
    int16_t *p = &keys[0 * keyoffset];
  } else {
    sustain_pedal = 0;
    int j;
    uint32_t *ps = sustain_notes;
    uint32_t s = *ps;
    int16_t *p = &keys[keyoffset];
    for (j = 0; j < ntw;) {
      if (!(s & 1)) {
        *p = 0;
      }
      p++;
      s >>= 1;
      j++;
      if (!(j & 0x1F)) {
        ps++;
        s = *ps;
      }
    }
  }
}

Privacy

© 2024 Zrna Research