FAMSrecalc

This is a FM, AM and sync oscillator in which the modulation frequencies and carrier frequencies are recalculated based upon the "wanted" frequencies set by the pitch inputs. The module can thus play "chords" where the 2nd and 3rd note of the chord are created by FM and AM modulation (and thus also creating overtones based on the FM/AM modulation). The internal sync-oscillator is a soft-sync, of which the dampening factor is controlled by the softsync frequency. The lower the softsync dampening, the less influence the sync has on the carrier and modulation oscillators.
Author: Remco van der Most
License: BSD
Github: sss/osc/FAMSrecalc.axo

Inlets

frac32 Pcar

frac32 PFmod

frac32 PAmod

frac32 PSync

frac32 FMWcar

frac32 FMWam

frac32 AM

Outlets

frac32buffer out

Parameters

frac32.s.map.pitch pitch

frac32.s.map FMWcar

frac32.s.map FMWam

frac32.s.map AM

frac32.s.map softsync

int32 OS

Declaration
uint32_t Phase[7];
uint32_t ofs[6];

int32_t nF[3];
int32_t fc3;
int32_t S1a;
int32_t S1b;
int32_t S2a;
int32_t S2b;
int32_t S2c;
int32_t S3;
int32_t val;
int i;
int j;
int32_t PV;
Control Rate
int32_t fc1a;
MTOFEXTENDED(param_pitch + inlet_Pcar, fc1a);
fc1a = fc1a / param_OS;
nF[0] = fc1a;
fc1a += nF[2];
int32_t FMWa = ___SMMUL(fc1a, param_FMWcar + inlet_FMWcar << 4);

int32_t fc1b;
MTOFEXTENDED(param_pitch + inlet_Pcar, fc1b);
fc1b = fc1b / param_OS;
nF[1] = fc1b;
fc1b -= nF[2];
int32_t FMWb = ___SMMUL(fc1b, param_FMWcar + inlet_FMWcar << 4);

int32_t fc2a;
MTOFEXTENDED(param_pitch + inlet_PFmod, fc2a);
fc2a = fc2a / param_OS;
fc2a += fc1a;

int32_t fc2b;
MTOFEXTENDED(param_pitch + inlet_PFmod, fc2b);
fc2b = fc2b / param_OS;
fc2b += fc1b;

int32_t fc2c;
MTOFEXTENDED(param_pitch + inlet_PFmod, fc2c);
fc2c = fc2c / param_OS;
fc2c += nF[2];

int32_t fc4;
MTOFEXTENDED(param_pitch + inlet_PAmod, fc3);
fc3 = fc3 / param_OS;
nF[2] = (nF[1] - fc3) / 2;
fc4 = (fc3 - nF[1]) / 2;
int32_t FMWc = ___SMMUL(fc4, param_FMWam + inlet_FMWam << 4);

int32_t AM = __SSAT(inlet_AM + param_AM, 28);
int32_t MIX = (1 << 27) - (AM > 0 ? AM : -AM);

int32_t Q;
MTOF((1 << 59), Q)
Q = Q / (1 + param_OS / 2);

int32_t Sfrq;
MTOFEXTENDED(param_pitch + inlet_PSync, Sfrq)
Sfrq = Sfrq / param_OS;
int32_t damp;
MTOF(__SSAT((param_softsync << 1) + param_pitch + inlet_PSync, 28), damp)
damp = damp / (1 + param_OS / 2);
Audio Rate
for (i = 0; i < param_OS; i++) {
  Phase[6] += Sfrq;

  for (j = 0; j < 6; j++) {
    ofs[j] = ___SMMLA(-ofs[j] << 1, damp, ofs[j]);
  }

  if (Phase[6] < PV) {
    for (j = 0; j < 6; j++) {
      ofs[j] += Phase[j];
      Phase[j] = 0;
    }
  }

  PV = Phase[6];
  Phase[0] += fc1a + (___SMMUL(S2a << 3, FMWa) << 3);
  Phase[1] += fc1b + (___SMMUL(S2b << 3, FMWb) << 3);

  SINE2TINTERP(Phase[0] + ofs[0], S1a)
  SINE2TINTERP(Phase[1] + ofs[1], S1b)
  S1a = (S1a >> 4);
  S1b = (S1b >> 4);

  Phase[2] += fc2a;
  Phase[3] += fc2b;
  Phase[4] += fc2c;

  SINE2TINTERP(Phase[2] + ofs[2], S2a)
  SINE2TINTERP(Phase[3] + ofs[3], S2b)
  SINE2TINTERP(Phase[4] + ofs[4], S2c)
  S2a = (S2a >> 4);
  S2b = (S2b >> 4);
  S2c = (S2c >> 4);

  Phase[5] += fc4 + (___SMMUL(S2c << 3, FMWc) << 3);

  SINE2TINTERP(Phase[5] + ofs[5], S3)
  S3 = (S3 >> 4);
  int32_t carrier = ___SMMUL(MIX << 3, S1a << 2) + ___SMMUL(AM << 3, S1b << 2);
  val = ___SMMLA(((___SMMUL(MIX << 3, carrier << 2) * 0 + carrier +
                   ___SMMUL(AM << 3, ___SMMUL(carrier << 3, S3 << 2) << 2)) -
                  val)
                     << 1,
                 Q, val);
}
outlet_out = val;

Privacy

© 2024 Zrna Research