salinoII

Paraphonic Osc Bank inspired by existing string machine waveforms
Author: Smashed Transistors
License: LGPL
Github: tiar/oscBnk/salinoII.axo

Inlets

frac32 4Feet

frac32 8Feet

frac32 16Feet

frac32 A1

frac32 D1

frac32 S1

frac32 R1

frac32 A2

frac32 D2

frac32 S2

frac32 R2

frac32 Vibrato

frac32.bipolar lfo

Outlets

frac32buffer.bipolar out

frac32.positive keys

Declaration
#define NB_OCT 6
int32_t outLP;
int32_t phi[12];
int32_t dPhi[12];
// 6 octaves + one note (C to C)
int32_t envMix[12 * NB_OCT + 1];
int32_t env1[12 * NB_OCT + 1];
int32_t env2[12 * NB_OCT + 1];
int32_t coefEnv[12 * NB_OCT + 1];

bool att1[12 * NB_OCT + 1];
bool att2[12 * NB_OCT + 1];
bool gate[12 * NB_OCT + 1];

int32_t mixmax(int32_t v1, int32_t v2) {
  return v1 > v2 ? ___SMMUL(1431655765, 2 * v1 + v2)
                 : ___SMMUL(1431655765, 2 * v2 + v1);
}
Init
for (int n12 = 0; n12 < 12; n12++) {
  int32_t dp;
  MTOFEXTENDED((-40 << 21) + (n12 << 21), dp)
  dPhi[n12] = -dp;
  for (int oct = 0; oct < NB_OCT + (n12 == 0); oct++) {
    int32_t note = 12 * oct + n12;
    int32_t coef;
    MTOFEXTENDED(-note << 21, coef)
    coefEnv[note] = coef;
    env1[note] = env2[note] = 0;
    att1[note] = att2[note] = gate[note] = false;
  }
}
outLP = 0;
Control Rate
{
  int32_t cA1;
  MTOFEXTENDED(-2 * inlet_A1 + (1 << 27), cA1);
  int32_t cD1;
  MTOFEXTENDED((___SMMLA(-3 << 27, inlet_D1, +1 << 22) << 4), cD1);
  int32_t cR1;
  MTOFEXTENDED((___SMMLA(-3 << 27, inlet_R1, +1 << 22) << 4), cR1);

  for (int i = 0; i < 12 * NB_OCT + 1; i++) {
    if (att1[i]) {
      env1[i] = ___SMMLA(cA1, (3 << 26) - env1[i], env1[i]);
      if (env1[i] >= (1 << 27)) {
        att1[i] = false;
        env1[i] = (1 << 27) - 1;
      }
    } else {
      if (gate[i]) {
        env1[i] = ___SMMLA(cD1, inlet_S1 - env1[i], env1[i]);
      } else {
        env1[i] = ___SMMLS(cR1, env1[i], env1[i]);
      }
    }
  }
}

{
  int32_t cA2;
  MTOFEXTENDED(-2 * inlet_A2 + (1 << 27), cA2);
  int32_t cD2;
  MTOFEXTENDED((___SMMLA(-3 << 27, inlet_D2, +1 << 22) << 4), cD2);
  int32_t cR2;
  MTOFEXTENDED((___SMMLA(-3 << 27, inlet_R2, +1 << 22) << 4), cR2);
  for (int i = 0; i < 12 * NB_OCT + 1; i++) {
    if (att2[i]) {
      env2[i] = ___SMMLA(cA2, (3 << 26) - env2[i], env2[i]);
      if (env2[i] >= (1 << 27)) {
        att2[i] = false;
        env2[i] = (1 << 27) - 1;
      }
    } else {
      if (gate[i]) {
        env2[i] = ___SMMLA(cD2, inlet_S2 - env2[i], env2[i]);
      } else {
        env2[i] = ___SMMLS(cR2, env2[i], env2[i]);
      }
    }
  }
}

//  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _
int32_t coef8Feet = __SSAT(inlet_8Feet, 28) << 3; // q31
for (int i = 0; i < 12 * NB_OCT + 1; i++) {
  envMix[i] = ___SMMUL(mixmax(env1[i], env2[i]), coef8Feet) << 1;
}
// we add coef4Feet*env to the mix env above
int32_t coef4Feet = __SSAT(inlet_4Feet, 28) << 3; // q31
for (int i = 0; i < 12 * NB_OCT + 1 - 12; i++) {
  envMix[i + 12] = ___SMMLA(env1[i], coef4Feet, envMix[i + 12] >> 1) << 1;
}
// we add coef16Feet*env to the mix env below
int32_t coef16Feet = __SSAT(inlet_16Feet, 28) << 3; // q31
for (int i = 12; i < 12 * NB_OCT + 1; i++) {
  envMix[i - 12] = ___SMMLA((env2[i]), coef16Feet, envMix[i - 12] >> 1) << 1;
}

int32_t keys = 0;
for (int i = 0; i < 12 * NB_OCT + 1; i++) {
  keys += envMix[i] >> 5;
  envMix[i] = ___SMMUL(envMix[i], coefEnv[i]) << 7;
}
outlet_keys = keys;

// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
// pre loop to avoid differentiation glitches on parameter modulation
int32_t y1;
int32_t y0 = 0;
for (int n12 = 0; n12 < 12; n12++) {
  int32_t *e = envMix + n12;
  int32_t p = phi[n12];
  for (int oct = 0; oct < NB_OCT + (n12 == 0); oct++) {
    int32_t x = __USAT(p, 31);
    x = ___SMMUL(x, x);         // q30
    x = ___SMMLS(x, x, x >> 2); // q28
    y0 = ___SMMLA(x, *e, y0);
    e += 12;
    p -= 1 << 30;
    p <<= 1;
  }
}
int32_t dPhiM[12];
int32_t lfo = ___SMMUL(inlet_lfo, inlet_Vibrato) << 5;
for (int n12 = 0; n12 < 12; n12++) {
  dPhiM[n12] = ___SMMLA(lfo, dPhi[n12], dPhi[n12]);
}
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
// "srate"
for (int i = 0; i < BUFSIZE; i++) {
  for (int n12 = 0; n12 < 12; n12++) {
    phi[n12] += dPhiM[n12];
  }
  y1 = y0;
  y0 = 0;
  for (int n12 = 0; n12 < 12; n12++) {
    int32_t *e = envMix + n12;
    int32_t p = phi[n12];
    for (int oct = 0; oct < NB_OCT + (n12 == 0); oct++) {
      int32_t x = __USAT(p, 31);
      x = ___SMMUL(x, x);         // q30
      x = ___SMMLS(x, x, x >> 2); // q28
      y0 = ___SMMLA(x, *e, y0);
      e += 12;
      p -= 1 << 30;
      p <<= 1;
    }
  }

  outlet_out[i] = (y0 - y1) << 12;
}
Midi Handler
if (status == MIDI_NOTE_ON + attr_midichannel) {
  int n = ((data1 & 0x7F) - 24);
  if (n >= 0 && n < 12 * NB_OCT + 1) {
    if (data2 != 0) {
      gate[n] = true;
      att1[n] = true;
      att2[n] = true;
    } else {
      gate[n] = false;
      att1[n] = false;
      att2[n] = false;
    }
  }
  // gates[data1 & 0x7F] = data2 * coef1[data1];
} else if (status == MIDI_NOTE_OFF + attr_midichannel) {
  int n = ((data1 & 0x7F) - 24);
  if (n >= 0 && n < 12 * NB_OCT + 1) {
    gate[n] = false;
    att1[n] = false;
    att2[n] = false;
  }
  // gates[data1 & 0x7F] = 0;
} else if ((status == attr_midichannel + MIDI_CONTROL_CHANGE) &&
           (data1 == MIDI_C_ALL_NOTES_OFF)) {
  for (int i = 0; i < 12 * NB_OCT + 1; i++) {
    gate[i] = false;
    att1[i] = false;
    att2[i] = false;
  }
}

Privacy

© 2024 Zrna Research