Osc_Bnk_I_lock

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

Inlets

frac32.bipolar lfo1

frac32.bipolar lfo2

frac32.bipolar lfo3

Outlets

frac32buffer.bipolar out

Parameters

frac32.u.map lfoDepth

frac32.s.map.kdecaytime.exp Attack

frac32.s.map.kdecaytime.exp Release

int32 Max Key

int32 Min Key

Attributes

combo type

combo algo

Declaration
float dp[128]; // delta phase

float p[128];
float coef1[128]; // for gain compensation in DPW algo
float gates[128];
float env[128];
float z[BUFSIZE];
float z1, z2, fz;
float lfo[12];

const float type_l[11] = {0.0f,  0.0f, 0.2f, 0.2f, 0.75f, 0.5f,
                          0.25f, 1.0f, 0.0f, 0.0f, -1.0f};
const float type_r[11] = {0.0f,  0.25f, 0.25f, 0.5f,  0.25f, 0.5f,
                          0.75f, 0.5f,  1.0f,  0.11f, 0.5f};

const float l = type_l[attr_type];
const float r = type_r[attr_type];

const float a = (l - 1) / r;
const float K = -0.5f * (l + 1) * r;
const float b = 1.0f + K;
const float A = 0.5 * (l - 1) / r;
const float C = -((1.0f / 3) * A * r * r * r + 0.5 * r * r - 0.5f * K + K * r);
const float C_K = C - K;

int syncRefresh = 0;
Init
// _____________________________________________________________________
int i, j;
for (i = 0; i < 128; i++) {
  p[i] = gates[i] = env[i] = 0.0f;
}
z1 = z2 = fz = 0.0f;
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
dp[0] = 1.7032914407591056E-4f;
dp[1] = 1.804574420422344E-4f;
dp[2] = 1.9118799994622893E-4f;
dp[3] = 2.0255663002739644E-4f;
dp[4] = 2.1460127403181634E-4f;
dp[5] = 2.2736212983919527E-4f;
dp[6] = 2.4088178561955362E-4f;
dp[7] = 2.5520536196728464E-4f;
dp[8] = 2.703806624869435E-4f;
dp[9] = 2.8645833333333333E-4f;
dp[10] = 3.0349203223833975E-4f;
dp[11] = 3.2153860758862255E-4f;
for (i = 12; i <= 127; i++) {
  dp[i] = 2 * dp[i - 12];
  if (attr_algo == 3) {
    coef1[i] = ((1 << 24) / 127.0f) / (dp[i]);
  } else if (attr_algo == 2) {
    coef1[i] = ((1 << 25) / 127.0f) / (dp[i]);
  } else {
    coef1[i] = ((1 << 25) / 127.0f);
  }
}
Control Rate
int minKey = param_Min_space_Key < param_Max_space_Key ? param_Min_space_Key
                                                       : param_Max_space_Key;
int maxKey = param_Min_space_Key >= param_Max_space_Key ? param_Min_space_Key
                                                        : param_Max_space_Key;
float attack = 1.0f - param_Attack / ((float)((1UL << 31) - 1));
float release = 1.0f - param_Release / ((float)((1UL << 31) - 1));
// attack = attack>1?1:attack;
// release = release>1?1:release;
// _____________________________________________________________________
int i, j;
for (j = 0; j < BUFSIZE; j++) {
  z[j] = 0;
}
float lfoDepth = param_lfoDepth * (1.0f / (1 << 27));
lfo[0] = 1.0f + lfoDepth * inlet_lfo1 * (0.03f / (1 << 27));
lfo[1] = 1.0f - lfoDepth * inlet_lfo1 * (0.021f / (1 << 27));
lfo[2] = 1.0f + lfoDepth * inlet_lfo1 * (0.023f / (1 << 27));
lfo[3] = 1.0f - lfoDepth * inlet_lfo2 * (0.029f / (1 << 27));
lfo[4] = 1.0f + lfoDepth * inlet_lfo2 * (0.02f / (1 << 27));
lfo[5] = 1.0f + lfoDepth * inlet_lfo3 * (0.015f / (1 << 27));
lfo[6] = 1.0f - lfoDepth * inlet_lfo3 * (0.02f / (1 << 27));
lfo[7] = 1.0f + lfoDepth * inlet_lfo1 * (0.029f / (1 << 27));
lfo[8] = 1.0f - lfoDepth * inlet_lfo3 * (0.022f / (1 << 27));
lfo[9] = 1.0f + lfoDepth * inlet_lfo1 * (0.021f / (1 << 27));
lfo[10] = 1.0f + lfoDepth * inlet_lfo2 * (0.03f / (1 << 27));
lfo[11] = 1.0f - lfoDepth * inlet_lfo2 * (0.027f / (1 << 27));

// resync (lock) of phases to avoid drift caused by calc inaccuracies
/*float pRef = p[minKey + syncRefresh];
for(i = syncRefresh + 12; i<= maxKey; i+=12){
        pRef*=2;
        if(pRef>=1)
          pRef -= 1;
        p[i] = pRef;
}
syncRefresh++;
if(syncRefresh>=12)
  syncRefresh = 0;
*/

// DPW anti ali
if (attr_algo == 2) {
  // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  int i12 = 0;
  for (i = minKey; i <= maxKey; i++) {
    float _env = env[i];
    env[i] += (gates[i] > env[i] ? attack : release) * (gates[i] - env[i]);
    // if(env[i]<0.01f) continue;
    float denv = (env[i] - _env) * (1.0f / BUFSIZE);
    float _dp = dp[i] * lfo[i12];
    i12++;
    if (i12 >= 12)
      i12 = 0;
    float _p = p[i];
    for (j = 0; j < BUFSIZE; j++) {
      _env += denv;
      _p += _dp;
      // branchless code, more cpu but constant 72% for 61 notes
      _p -= (_p > 1);
      z[j] += _env * (K * _p + C_K + (_p < r) * (K + _p * (1 + A * _p)));
      /*
       // code with branching => less cpu but cpu variations => glitches
       // 74% for 61+24 notes
        if(_p>1) _p--;
        float tmp;
        if(_p>r)
          tmp = K * _p + C_K;
        else
          tmp = C + _p * (1+K + A * _p);
        z[j] += _env * tmp;*/
    }
    p[i] = _p;
  }
  // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  for (j = 0; j < BUFSIZE; j++) {
    outlet_out[j] = (int32_t)(z[j] - z1);
    z1 = z[j];
  }
} else

{
  // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  int i12 = 0;
  for (i = minKey; i <= maxKey; i++) {
    float _env = env[i];
    env[i] += (gates[i] > env[i] ? attack : release) * (gates[i] - env[i]);
    float denv = (env[i] - _env) * (1.0f / BUFSIZE);
    float _p = p[i];
    float _dp = dp[i] * lfo[i12];
    i12++;
    if (i12 >= 12)
      i12 = 0;
    for (j = 0; j < BUFSIZE; j++) {
      _env += denv;
      _p += _dp;
      _p -= (_p > 1);
      z[j] += _env * (K + (_p < r) * (1 + a * _p));
    }
    p[i] = _p;
  }
  // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  for (j = 0; j < BUFSIZE; j++) {
    outlet_out[j] = (int32_t)(z[j]);
  }
}
Midi Handler
if (status == MIDI_NOTE_ON + attr_midichannel) {
  // gates[data1 & 0x7F] = data2 * coef1[data1];
  gates[data1 & 0x7F] =
      data2 == 0 ? 0
                 : 100 * coef1[data1]; // <---------------------Fixed velocity
} else if (status == MIDI_NOTE_OFF + attr_midichannel) {
  gates[data1 & 0x7F] = 0;
} else if ((status == attr_midichannel + MIDI_CONTROL_CHANGE) &&
           (data1 == MIDI_C_ALL_NOTES_OFF)) {
  for (int i = 0; i < 128; i++)
    gates[data1 & 0x7F] = 0;
}

Privacy

© 2024 Zrna Research