salino

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

Inlets

frac32 4Feet

frac32 8Feet

frac32 16Feet

frac32 Attack

frac32 Release

frac32 RevLevel

frac32 RevDuration

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 + 13];
int32_t env[12 * NB_OCT + 13];
int32_t envRev[12 * NB_OCT + 13];
int32_t envTarget[12 * NB_OCT + 13];
int32_t coefEnv[12 * NB_OCT + 13];
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;
    env[note] = 0;
    envTarget[note] = 0;
    envRev[note] = 0;
  }
}
outLP = 0;
Control Rate
int32_t coefA = inlet_Attack * 2 - (64 << 21);
MTOF(-coefA, coefA);
int32_t coefR = inlet_Release * 2 - (64 << 21);
MTOF(-coefR, coefR);
int32_t coefRevA = inlet_RevDuration - (24 << 21);
MTOF(-coefRevA, coefRevA);
int32_t coefRevR = inlet_RevDuration - (0 << 21);
MTOF(-coefRevR, coefRevR);
int32_t revLevel = inlet_RevLevel << 4;
for (int i = 0; i < 12 * NB_OCT + 1; i++) {
  int32_t delta = envTarget[i] - env[i];
  env[i] = ___SMMLA(delta > 0 ? coefA : coefR, delta, env[i]);

  delta = ___SMMLA(envTarget[i] << 1, revLevel, -envRev[i]);
  envRev[i] = ___SMMLA(delta > 0 ? coefRevA : coefRevR, delta, envRev[i]);
}
//  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _
int32_t coef8Feet = __SSAT(inlet_8Feet, 28) << 4; // q31
for (int i = 0; i < 12 * NB_OCT + 1; i++) {
  envMix[i] = ___SMMUL(env[i] + envRev[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(env[i] + envRev[i], coef4Feet, envMix[i + 12] >> 1)
                   << 1;
}
// we add coef4Feet*env to the mix env below
int32_t coef16Feet = __SSAT(inlet_16Feet, 28) << 4; // q31
for (int i = 12; i < 12 * NB_OCT + 1; i++) {
  envMix[i - 12] =
      ___SMMLA((env[i] + envRev[i]) << 1, coef16Feet, envMix[i - 12] >> 1) << 1;
}
int32_t keys = 0;
for (int i = 0; i < 12 * NB_OCT + 1; i++) {
  keys += envTarget[i] != 0 ? 1 << 21 : 0;
}
outlet_keys = keys;
//_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
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 = p & 0x7FFFFFFF; //q31
            int32_t y = ___SMMUL(x, x)<<1; //q30
             y = ___SMMUL(y, y); //q30
            y = ___SMMLS(y, y, x>>3);//q28
            y0 = ___SMMLA(y, *e, y0);
*/

    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]);
}

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 = p & 0x7FFFFFFF; //q31
              int32_t y = ___SMMUL(x, x)<<1; //q30
               y = ___SMMUL(y, y); //q30
              y = ___SMMLS(y, y, x>>3);//q28
              y0 = ___SMMLA(y, *e, y0);
*/

      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 out = (y0 - y1) << 13;
  outLP = ___SMMLA(0x10000000, out - outLP, outLP);
  // outlet_out[i] = __SSAT(outLP, 27)+__SSAT(out-outLP, 27);
  outlet_out[i] = __SSAT(out / 2 + __SSAT(out, 28), 30);
}
Midi Handler
if (status == MIDI_NOTE_ON + attr_midichannel) {
  int n = ((data1 & 0x7F) - 24);
  if (n >= 0 && n < 12 * NB_OCT + 1) {
    envTarget[n] = data2 != 0 ? coefEnv[n] : 0;
  }
  // 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) {
    envTarget[n] = 0;
  }
  // 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++)
    envTarget[i] = 0;
}

Privacy

© 2024 Zrna Research