DyadBLIT

Author: Smashed Transistors
License: LGPL
Github: tiar/oscBnk/DyadBLIT.axo

Inlets

frac32.bipolar vib0

frac32.bipolar vib1

frac32.bipolar vib2

frac32.positive waveform

Outlets

frac32buffer.bipolar out

Parameters

frac32.u.map L

frac32.s.map.kdecaytime.exp A

frac32.s.map.kdecaytime.exp R1

frac32.s.map.kdecaytime.exp R2

Declaration
int32_t y[8], v, integ;
uint8_t i;

int8_t gates[128];
int32_t envs[8 * 12];
int32_t envc[8 * 12];
uint16_t spl;

int8_t dyad[256] = {
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3, 7, 6, 7, 5, 7, 6, 7, 4,
    7, 6, 7, 5, 7, 6, 7, 2, 7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3,
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 1, 7, 6, 7, 5, 7, 6, 7, 4,
    7, 6, 7, 5, 7, 6, 7, 3, 7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 2,
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3, 7, 6, 7, 5, 7, 6, 7, 4,
    7, 6, 7, 5, 7, 6, 7, 0, 7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3,
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 2, 7, 6, 7, 5, 7, 6, 7, 4,
    7, 6, 7, 5, 7, 6, 7, 3, 7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 1,
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3, 7, 6, 7, 5, 7, 6, 7, 4,
    7, 6, 7, 5, 7, 6, 7, 2, 7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, 3,
    7, 6, 7, 5, 7, 6, 7, 4, 7, 6, 7, 5, 7, 6, 7, -1};

class BLIT {
public:
  int32_t sgn[8];
  int32_t env[8];
  int32_t val[8];
  uint32_t per = 5 << 10;
  uint16_t nextSpl = 0;
  uint32_t next = 0;
  uint8_t cpt = 0;
  void setF(float f) { per = (uint32_t)(48000.0f * (1 << (6 + 10)) / f); }
  void init(float f) {
    setF(f);
    for (int i = 0; i < 8; i++) {
      env[i] = 0;
      val[i] = 0;
      sgn[i] = 1;
    }
  }
  void proc(uint16_t spl, int8_t *dyad, int32_t *y, int i) {
    if (spl == nextSpl) {
      int8_t oct = dyad[cpt];

      sgn[oct] *= -1;
      int32_t ampli = sgn[oct] * env[oct] - val[oct];
      val[oct] += ampli;
      // select the band limited pulse according to subsample time since the
      // transition
      const int16_t *t = tiar_bli_8_64 + 8 * (((next >> 10) & 63));
      // add the selected band limited pulse to the output 8 taps
      for (int j = 0; j <= 7; j++) {
        y[(i - j) & 7] += ampli * t[j];
      }

      next += per;
      cpt++;
      if (cpt == 255) { // skip the last one
        cpt = 0;
        next += per;
      }
      nextSpl = (next >> (6 + 10)) & 65535;
    }
  }
};

BLIT blit[12];
Init
y[0] = y[1] = y[2] = y[3] = y[4] = y[5] = y[6] = y[7] = v = integ = 0;
i = 0;

spl = 0;

float f = 4186.009f * 4;
for (int i = 0; i < 12; i++) {
  blit[i].init(f);
  f *= 1.059463094f;
}

for (int i = 0; i < 128; i++) {
  gates[i] = 0;
}
for (int i = 0; i < 8 * 12; i++) {
  envs[i] = 0;
}
Control Rate
float vib0 = inlet_vib0 * 1e-10f;
float vib1 = inlet_vib1 * 1e-10f;
float vib2 = inlet_vib2 * 1e-10f;
float f = 4186.009f * 4;
for (int i = 0; i < 12; i += 3) {
  blit[i].setF(f * vib0 + f);
  f *= 1.059463094f;
  blit[i + 1].setF(f * vib1 + f);
  f *= 1.059463094f;
  blit[i + 2].setF(f * vib2 + f);
  f *= 1.059463094f;
}

float envTot = 0;
for (int i = 0; i < 8 * 12; i++) {
  int32_t b = envs[i];
  if (gates[24 + i] > 10)
    envs[i] = ___SMMLA(0x7FFFFFFF - param_A, (100 << 20) - b, b >> 1)
              << 1; // ascending
  else if (b > param_L)
    envs[i] = ___SMMUL(b, param_R1) << 1;
  else
    envs[i] = ___SMMUL(b, param_R2) << 1;
  envTot += envs[i];
}
int32_t comp = arm::float_to_q(10000000 / sqrtf(envTot + (1 << 27)), 27);
for (int i = 0; i < 8 * 12; i++) {
  envc[i] = ___SMMUL(envs[i], comp);
}

for (int i = 0; i < 12; i++) {
  for (int oct = 0; oct < 8; oct++) {
    blit[i].env[oct] = (envc[i + 12 * oct] >> 12);
  }
  int32_t coef = __USAT(inlet_waveform, 27) >> (11 - 3);
  for (int j = 1; j < 8; j++) {
    for (int oct = j; oct < 8; oct++) {
      blit[i].env[oct] =
          ___SMMLA(coef, envc[i + 12 * oct - j * 12], blit[i].env[oct]);
    }
    coef >>= 1;
  }
}
Audio Rate
for (int note = 0; note < 12; note++) {
  blit[note].proc(spl, dyad, y, i);
}

spl++;

outlet_out = integ += y[i]; // output integrator
y[i] = 0;
i = (i + 1) & 7;
Midi Handler
if (status == MIDI_NOTE_ON + attr_midichannel) {
  gates[data1 & 0x7F] = data2 ? 100 : 0;
} else if (status == MIDI_NOTE_OFF + attr_midichannel) {
  gates[data1 & 0x7F] = 0;
} else if ((status == attr_midichannel + MIDI_CONTROL_CHANGE) &&
           (data1 == MIDI_C_ALL_NOTES_OFF)) {
  for (int i = 0; i < 128; i++)
    gates[data1 & 0x7F] = 0;
}

Privacy

© 2024 Zrna Research