polymaster latch

controls a polyphonic subpatch,and receives information about the current state of all voices inside that patch via 'polyhandler slave' unlike a 'normal' polyphonic subpatch, starting a note that is already playing will re-trigger that note,instead of playing that note with another voice. if 'kill' is enabled,notes that are on release will be stopped. 'polyhandler latch' references a table with information about the 'playback mode'. 'latchFlag' sets which value in that table defines the 'latch - mode'. in latch-mode,note-ons will toggle the respective note on and off, note-offs are ignored. 'blocksize' refers how big a block of parameters is for each voice, 'index' sets where inside that block the information about the 'playback mode' is stored
Author: Robert Schirmer
License: BSD
Github: rbrt/poly/polymaster latch.axo

Inlets

int32.positive note

int32.positive velo

int32.positive note number to stop

int32.positive startnote

bool32.rising stop it!

bool32.rising start

Outlets

int32.positive note

int32.positive velo

int32.positive target

Parameters

bool32.tgl kill notes on release

bool32.tgl ignoreZeroSlots

Attributes

combo polyphony

combo blocksize

objref playmode

spinner loopFlag

spinner index

Declaration
int8_t _note;
uint8_t _velo;
uint8_t pren;
uint8_t prev;
bool trig;
bool trigoff;
bool stop;
bool start;
uint8_t i;
uint8_t ii;
bool doit;
uint8_t target;
bool latch;

static const uint8_t LENGTHPOW = 5;
static const uint8_t POLY = attr_polyphony;
static const uint8_t BITS = 8;
static const uint8_t GAIN = 20;

uint8_t Rhold[POLY];
uint8_t Rrelease[POLY];
uint8_t Snote[POLY];
uint8_t Svelo[POLY];

uint8_t old_voice[POLY];
uint8_t old_voice_length;
Init
pren = 0;
prev = 0;
_note = 0;
_velo = 0;
stop = 0;
start = 0;
Control Rate
trig = 0;
trigoff = 0;

for (i = 0; i < old_voice_length; i++)
  if (!Rrelease[old_voice[i] - 1] || !old_voice[i]) {
    old_voice_length--;
    for (ii = i; ii < old_voice_length; ii++)
      old_voice[ii] = old_voice[ii + 1];
    break;
  }

if ((inlet_note != pren) || (inlet_velo != prev)) {
  pren = inlet_note;
  prev = inlet_velo;
  _velo = inlet_velo;
  _note = inlet_note;
  latch = (attr_playmode.array[(_note << attr_blocksize) + attr_index]) >=
          attr_loopFlag;
  if (_velo && ((attr_playmode.array[(_note << attr_blocksize) + attr_index]) ||
                !param_ignoreZeroSlots))
    trig = 1;
  if (!latch && !_velo)
    trigoff = 1;
}
TRIGGER : if (trig) {
  // FIRST,check if this is a retrigger-event or a latched note that's being
  // toggled
  for (i = 0; i < POLY; i++) {
    // is this note latched?
    if (latch) {
      if (Rhold[i] == (_note + 1)) {
        target = i;
        _velo = 0;
        doit = 1;
      }
      if (Rrelease[i] == (_note + 1)) {
        target = i;
        doit = 1;
      }
    }
    // is this note on release an will be retriggered?
    else if (Rrelease[i] == (_note + 1)) {
      target = i;
      // remove this voice from the old voices list
      for (ii = 0; ii < old_voice_length; ii++)
        if (old_voice[ii] == (target + 1))
          old_voice[ii] = 0;
      doit = 1;
    }
  }
  // if it's NOT a retrigger or a toggle-event,try to start a 'normal' voice..
  if (!doit) {
    for (i = 0; i < POLY; i++)
      if ((!Rhold[i]) && (!Rrelease[i])) {
        target = i;
        doit = 1;
      }
  }
  // if there are no empty voices available,try to STEAL a voice that's on
  // release
  if ((!doit && param_steal) && old_voice_length) {
    // set the target to the oldest voice
    target = old_voice[0] - 1;
    // remove that voice from the old voices list
    old_voice[0] = 0;
    doit = 1;
  }
}
// trigger off
if (trigoff) {
  for (i = 0; i < POLY; i++)
    if (Rhold[i] == (_note + 1)) {
      target = i;
      doit = 1;
      if (!latch) {
        // add the voice to the old voices list if it's NOT a loop
        old_voice[old_voice_length] = target + 1;
        old_voice_length++;
      }
    }
}

// stop
if (inlet_stop && (!stop)) {
  _note = inlet_stopnote;
  _velo = 0;
  pren = _note;
  prev = _velo;
  stop = 1;
  trigoff = 1;
  goto TRIGGER;
}
if (!inlet_stop)
  stop = 0;
// start
if (inlet_start && (!start)) {
  _note = inlet_startnote;
  _velo = 127;
  pren = _note;
  prev = _velo;
  start = 1;
  trig = 1;
  latch = 0;
  goto TRIGGER;
}
if (!inlet_start)
  start = 0;

if (doit) {
  doit = 0;
  Snote[target] = _note + 1;
  Svelo[target] = _velo;
  if (_velo)
    Rhold[target] = _note + 1;
  else
    Rhold[target] = 0;
}

outlet_note = _note;
outlet_velo = _velo;
outlet_target = target;

Privacy

© 2024 Zrna Research