lfoSmall

Clock-synced quad LFO Selected LFO's settings only change when a parameter is moved. Select selects between the 4 LFO's to edit their parameters. NOTE THOUGH: 0-15=LFO1 16-31=LFO2 32-47=LFO3 48-64=LFO4 Rate is quantized to ratio's based on 2, 3 and 5. It goes through: 1, 5/4, 4/3, 3/2. Each time this row has ended, the ratio-base restarts and multiplies the rate by one power of 2 more. Level controls the level of the currently selected LFO.
Author: Remco van der Most
License: BSD
Github: sss/lfo/lfoSmall.axo

Inlets

bool32 clock

bool32 save

bool32 load

int32 preset

int32 div1

int32 div2

int32 div3

int32 div4

Outlets

frac32 out1

frac32 out2

frac32 out3

frac32 out4

frac32 rate

Parameters

int32 preset

frac32.u.map select

frac32.s.map rate

frac32.s.map level

int32.hradio wave

bool32.mom save

bool32.mom load

Attributes

combo total

Declaration
static const uint32_t LENGTH = 16;
int32_t *array;

char C[64];
int offset;
int pval;
int strig;
int ltrig;

int i;
// int32_t m[4];
// int32_t v[4];
// int32_t S[4];
// int32_t O[4];
uint32_t Time;
int mtrig;
uint64_t count;
float32_t A[4];
int32_t sine[4];
uint32_t phase[4];
int Div[4];
int32_t pr;
int32_t pv;
int32_t pw;

int32_t tri(uint32_t P1, int instance) {
  int32_t temp = P1 + (1 << 30);
  temp = temp > 0 ? temp : -temp;
  sine[instance] = (temp - (1 << 30)) << 1;
}
Init
static int32_t _array[LENGTH] __attribute__((section(".sdram")));
array = &_array[0];

strcpy(&C[0], "0:/lfo000.tab");
offset = strlen("lfo");
pval = 0;

A[0] = 1;
A[1] = (float32_t)5 / 4;
A[2] = (float32_t)4 / 3;
A[3] = (float32_t)3 / 2;
for (i = 0; i < 16; i++) {
  array[i] = 0;
}
Control Rate
int16_t preset = param_preset + inlet_preset;
if (preset != pval) {
  pval = preset;
  int i = preset;
  int i0 = i / 10;
  C[offset + 2] = '0' + i - 10 * i0;
  i = i0;
  i0 = i / 10;
  C[offset + 1] = '0' + i - 10 * i0;
  i = i0;
  i0 = i / 10;
  C[offset + 0] = '0' + i - 10 * i0;
}
int save = inlet_save + param_save;
int load = inlet_load + param_load;
if ((save > 0) && !strig) {
  strig = 1;
  FIL FileObject;
  FRESULT err;
  UINT bytes_written;
  err = f_open(&FileObject, &C[0], FA_WRITE | FA_CREATE_ALWAYS);
  if (err != FR_OK) {
    report_fatfs_error(err, &C[0]);
    return;
  }
  int rem_sz = sizeof(*array) * LENGTH;
  int offset = 0;
  while (rem_sz > 0) {
    if (rem_sz > sizeof(fbuff)) {
      memcpy((char *)fbuff, (char *)(&array[0]) + offset, sizeof(fbuff));
      err = f_write(&FileObject, fbuff, sizeof(fbuff), &bytes_written);
      rem_sz -= sizeof(fbuff);
      offset += sizeof(fbuff);
    } else {
      memcpy((char *)fbuff, (char *)(&array[0]) + offset, rem_sz);
      err = f_write(&FileObject, fbuff, rem_sz, &bytes_written);
      rem_sz = 0;
    }
  }
  if (err != FR_OK)
    report_fatfs_error(err, &C[0]);
  err = f_close(&FileObject);
  if (err != FR_OK)
    report_fatfs_error(err, &C[0]);
} else if (!(save > 0))
  strig = 0;

if ((load > 0) && !ltrig) {
  ltrig = 1;
  FIL FileObject;
  FRESULT err;
  UINT bytes_read;
  err = f_open(&FileObject, &C[0], FA_READ | FA_OPEN_EXISTING);
  if (err != FR_OK) {
    report_fatfs_error(err, &C[0]);
    return;
  }
  int rem_sz = sizeof(*array) * LENGTH;
  int offset = 0;
  while (rem_sz > 0) {
    if (rem_sz > sizeof(fbuff)) {
      err = f_read(&FileObject, fbuff, sizeof(fbuff), &bytes_read);
      if (bytes_read == 0)
        break;
      memcpy((char *)(&array[0]) + offset, (char *)fbuff, bytes_read);
      rem_sz -= bytes_read;
      offset += bytes_read;
    } else {
      err = f_read(&FileObject, fbuff, rem_sz, &bytes_read);
      memcpy((char *)(&array[0]) + offset, (char *)fbuff, bytes_read);
      rem_sz = 0;
    }
  }
  if (err != FR_OK) {
    report_fatfs_error(err, &C[0]);
    return;
  };
  err = f_close(&FileObject);
  if (err != FR_OK) {
    report_fatfs_error(err, &C[0]);
    return;
  };
} else if (!(load > 0))
  ltrig = 0;

Div[0] = inlet_div1;
Div[1] = inlet_div2;
Div[2] = inlet_div3;
Div[3] = inlet_div4;
for (i = 0; i < 4; i++) {
  Div[i] = Div[i] > 0 ? Div[i] : 1;
}

int sel = param_select >> 25;
if (!(pr == param_rate)) {
  array[sel] = ___SMMUL(param_rate << 3, attr_total - 1 << 2);
  array[sel + 12] = (array[sel] >> 2) - (array[sel] > 0 ? 0 : 1);
  array[sel] = array[sel] & 3;
}

if (!(pv == param_level)) {
  array[sel + 4] = param_level;
}
if (!(pw == param_wave)) {
  array[sel + 8] = param_wave;
}

float32_t rate = ((float32_t)(Time)) / 48000;
rate = (((float32_t)(1 << 31) / 1500) / rate);

for (i = 0; i < 4; i++) {
  if (array[i + 12] > 0) {
    phase[i] += (((int32_t)(rate * A[array[i]])) << array[i + 12]) / Div[i];
  } else {
    phase[i] += (((int32_t)(rate * A[array[i]])) >> -array[i + 12]) / Div[i];
  }
  if (array[i + 8] == 0) {
    SINE2TINTERP(phase[i], sine[i])
  }
  if (array[i + 8] == 1) {
    tri(phase[i], i);
  }
  if (array[i + 8] == 2) {
    sine[i] = phase[i];
  }
  if (array[i + 8] == 3) {
    sine[i] = -phase[i];
  }
  if (array[i + 8] == 4) {
    sine[i] = ((phase[i]) & ((1 << 32) - 1)) > (1 << 31) ? ((1 << 31) - 1)
                                                         : -(1 << 31) + 1;
  }
  sine[i] = ___SMMUL((sine[i] >> 1) + ((array[i + 4] > 0 ? 1 : 0) << 30),
                     array[i + 4] << 1 + (array[i + 4] > 0 ? 0 : 1));
}

outlet_out1 = sine[0];
outlet_out2 = sine[1];
outlet_out3 = sine[2];
outlet_out4 = sine[3];
pr = param_rate;
pv = param_level;
Audio Rate
if ((inlet_clock > 0) && !mtrig) {
  mtrig = 1;
  Time = count;
  count = 0;
} else if (inlet_clock == 0) {
  mtrig = 0;
}
count += 1;

Privacy

© 2024 Zrna Research