polyFMOsc

4-voice "chord" oscillator with internal FM and source selection for each of the 8 internal oscillators and individual amplitude control for the 4 voices. *connect a non-bandlimited saw-LFO to the "morph" input to update note-values and morph between the internal oscillators. *connect an attenuated LFO to the "mod" input to generate swing for the "morph" input and an update offset between the 4 voices. connect note-patterns to the 4 "note(1-4)" inputs. eg. use the 4xRngCount2 module to send notes. Values will be scaled to key internally! fm(1-8) inputs control the FM width of each internal oscillator independently for ultimate sonic morphing! Glide generates a portamento for each oscillator, changing to another note. "fm" knob controls overall fm width between oscillators. "extFM" knob controls overall width of the incoming fm-width signals. "src(1-8) select the internal oscillator that is send to the oscillator (so first control is for osc1, 2nd for osc2, etc) **first 4 sources are the "combined 2-oscillator voices", last 8 sources are the individual 8 oscillators.
Author: Remco van der Most
License: BSD
Github: sss/osc/polyFMOsc.axo

Inlets

frac32 morph

frac32 mod

frac32 note1

frac32 note2

frac32 note3

frac32 note4

frac32 vol1

frac32 vol2

frac32 vol3

frac32 vol4

frac32 fm1

frac32 fm2

frac32 fm3

frac32 fm4

frac32 fm5

frac32 fm6

frac32 fm7

frac32 fm8

bool32 active

Outlets

frac32buffer out

Parameters

int32.hradio src1

int32.hradio src2

int32.hradio src3

int32.hradio src4

int32.hradio src5

int32.hradio src6

int32.hradio src7

int32.hradio src8

frac32.s.map.pitch pitch

frac32.s.map detune

frac32.s.map fm

frac32.s.map extfm

frac32.u.map glide

int32 key

Declaration
uint32_t phase[8];
int32_t wave[8];
int32_t freq[8];
int32_t fraq[8];
int i;
int32_t base[12] = {0, 0, 2, 2, 4, 5, 5, 7, 7, 9, 9, 11};
int32_t mix[12];
int32_t sum;
int m1trig[4];
int m2trig[4];
uint32_t note[4];
int32_t octave[4];
int32_t marph;
int32_t mirph;
int32_t LP1;
int32_t LP2;
int32_t HP;
int32_t amp[4];
int32_t omp[4];
int8_t sel[8];
int32_t fm[8];
int32_t follow;
int32_t morph;
Control Rate
if (inlet_active > 0) {
  morph = (inlet_morph + inlet_mod) & ((1 << 27) - 1);
  morph =
      morph < (1 << 26) ? morph << 1 : (1 << 27) - ((morph - (1 << 26)) << 1);
  morph = (morph - (1 << 26)) * 8 / 6 + (1 << 26);
  marph = marph + ((morph - marph) >> 1);
  morph = marph < 0 ? 0 : marph;
  morph = morph > (1 << 27) ? (1 << 27) : morph;

  note[0] = ((inlet_note1 + param_pitch) >> 21);
  note[1] = ((inlet_note2 + param_pitch) >> 21);
  note[2] = ((inlet_note3 + param_pitch) >> 21);
  note[3] = ((inlet_note4 + param_pitch) >> 21);
  int key = (param_key * 7) - (param_key * 7) / 12 * 12;
  for (i = 0; i < 4; i++) {
    omp[i] = omp[i] + ((amp[i] - omp[i]) >> 6);
    octave[i] = note[i] / 12;
    note[i] = note[i] - octave[i] * 12;
    note[i] = note[i] < 0 ? note[i] + 12 : note[i];
    note[i] = note[i] < 0 ? 0 : note[i];
    note[i] = note[i] >= 12 ? 0 : note[i];
    octave[i] = octave[i];
    if ((morph == 0) && (!(m1trig[i]))) {

      MTOFEXTENDED((((base[note[i]] + octave[i] * 12)) << 21) + (key << 21) +
                       ___SMMUL(param_detune << 3, i << 9),
                   fraq[i * 2])
      m1trig[i] = 1;
    } else if (!(morph == 0)) {
      m1trig[i] = 0;
    }
    if (!(morph == (1 << 27)) && (!(m2trig[i]))) {
      MTOFEXTENDED((((base[note[i]] + octave[i] * 12)) << 21) + (key << 21) +
                       ___SMMUL(param_detune << 3, (i * 2 + 1) << 8),
                   fraq[i * 2 + 1])
      m2trig[i] = 1;
    } else if ((morph == (1 << 27))) {
      m2trig[i] = 0;
    }
  }
  follow = (1 << 27) - param_glide;
  follow = ___SMMUL(follow << 3, follow << 2);
  for (i = 0; i < 8; i++) {
    freq[i] = freq[i] + ___SMMUL((fraq[i] - freq[i]) << 3, follow << 2);
  }

  amp[0] = inlet_vol1;
  amp[1] = inlet_vol2;
  amp[2] = inlet_vol3;
  amp[3] = inlet_vol4;
  sel[0] = param_src1;
  sel[1] = param_src2;
  sel[2] = param_src3;
  sel[3] = param_src4;
  sel[4] = param_src5;
  sel[5] = param_src6;
  sel[6] = param_src7;
  sel[7] = param_src8;

  for (i = 0; i < 8; i++) {
    fm[i] = param_fm;
  }
  fm[0] = fm[0] + inlet_fm1;
  fm[1] = fm[1] + inlet_fm2;
  fm[2] = fm[2] + inlet_fm3;
  fm[3] = fm[3] + inlet_fm4;
  fm[4] = fm[4] + inlet_fm5;
  fm[5] = fm[5] + inlet_fm6;
  fm[6] = fm[6] + inlet_fm7;
  fm[7] = fm[7] + inlet_fm8;
  for (i = 0; i < 8; i++) {
    fm[i] = ___SMMUL(param_extfm << 3,
                     ___SMMUL(fm[i] << 2, ___SMMUL(fm[i] << 3, fm[i] << 2) << 2)
                         << 2);
  }
}
Audio Rate
if (inlet_active > 0) {
  sum = 0;
  mirph = mirph + ((marph - mirph) >> 8);
  morph = mirph < 0 ? 0 : mirph;
  morph = morph > (1 << 27) ? (1 << 27) : morph;
  for (i = 0; i < 8; i++) {
    phase[i] += freq[i] + ___SMMUL(freq[i] << 3,
                                   ___SMMUL(fm[i] << 4, mix[sel[i]] << 3) << 3);
    SINE2TINTERP(phase[i], wave[i]);
    wave[i] = ___SMMUL(wave[i], omp[i >> 1] << 4);
    mix[i + 4] = wave[i] >> 5;
  }
  for (i = 0; i < 4; i++) {
    mix[i] = ___SMMUL(morph, wave[i * 2]) +
             ___SMMUL((1 << 27) - morph, wave[i * 2 + 1]);
    sum += mix[i];
  }
  LP1 = LP1 + (((sum >> 1) - LP1) >> 1);
  LP2 = LP2 + (((LP1)-LP2) >> 1);
  HP = HP + ((LP1 - HP) >> 12);
  outlet_out = LP1 - HP;
  // outlet_out=wave[0]>>5;
}

Privacy

© 2024 Zrna Research