polymaster

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.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

int32 test

Parameters

bool32.tgl kill notes on release

Attributes

combo polyphony

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;

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;
// 'thin' the old voice list if voices are done with release or got stolen
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;
  if (_velo)
    trig = 1;
  else
    trigoff = 1;
}
TRIGGER : if (trig) {
  // retrig
  for (i = 0; i < POLY; i++) {
    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;
      // add the voice to the old voices list
      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;
  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;
outlet_test = old_voice_length;

Privacy

© 2024 Zrna Research