// ----
// ---- file   : osc_hh_v1.cpp
// ---- author : bsp
// ---- legal  : Distributed under terms of the MIT license (https://opensource.org/licenses/MIT)
// ----
// ----          Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// ----          associated documentation files (the "Software"), to deal in the Software without restriction, including 
// ----          without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// ----          copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 
// ----          the following conditions:
// ----  
// ----          The above copyright notice and this permission notice shall be included in all copies or substantial 
// ----          portions of the Software.
// ----
// ----          THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// ----          NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// ----          IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// ----          WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
// ----          SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ----
// ---- info   : auto-generated by "Cycle"
// ----           $ g++ -Wall -Wno-unused-function -Wno-unused-variable -I../../tksampler -c osc_hh_v1.cpp -o osc_hh_v1.o
// ---- created: 08Dec2023 13:45:57
// ----
// ----
// ----

#include <plugin.h>

#include <stdlib.h>
#include <math.h>
#include <string.h>


#define OVERSAMPLE_FACTOR  16.0f

#define PARAM_TUNE_1             0
#define PARAM_TUNE_2             1
#define PARAM_TUNE_3             2
#define PARAM_TUNE_4             3
#define PARAM_TUNE_5             4
#define PARAM_LEVEL              5
#define PARAM_WIDTH              6
#define PARAM_VSYNC              7
#define NUM_PARAMS               8
static const char *loc_param_names[NUM_PARAMS] = {
   "tune_1",                  // 0: TUNE_1
   "tune_2",                  // 1: TUNE_2
   "tune_3",                  // 2: TUNE_3
   "tune_4",                  // 3: TUNE_4
   "tune_5",                  // 4: TUNE_5
   "level",                   // 5: LEVEL
   "width",                   // 6: WIDTH
   "vsync",                   // 7: VSYNC

};
static float loc_param_resets[NUM_PARAMS] = {
   0.5f,                      // 0: TUNE_1
   0.5f,                      // 1: TUNE_2
   0.5f,                      // 2: TUNE_3
   0.5f,                      // 3: TUNE_4
   0.5f,                      // 4: TUNE_5
   0.0f,                      // 5: LEVEL
   0.0f,                      // 6: WIDTH
   0.0f,                      // 7: VSYNC

};

#define NUM_MODS                 0
static const char *loc_mod_names[NUM_MODS] = {

};

typedef struct osc_hh_v1_info_s {
   st_plugin_info_t base;
} osc_hh_v1_info_t;

typedef struct osc_hh_v1_shared_s {
   st_plugin_shared_t base;
   float params[NUM_PARAMS];

} osc_hh_v1_shared_t;

typedef struct osc_hh_v1_voice_s {
   st_plugin_voice_t base;
   float             sample_rate;
   float             note_speed_fixed;
   float             note_speed_cur;
   float             note_speed_inc;
   float             note_cur;
   float             note_inc;
   float             mods[NUM_MODS];

   float tmp1_pos;
   float tmp2_amt;
   float tmp5_pos;
   float tmp6_amt;
   float tmp9_pos;
   float tmp10_amt;
   float tmp13_seq;
   float tmp14_seq;
   float tmp15_seq;
   float tmp16_seq;
   float tmp17_seq;
   float tmp18_seq;
   float tmp19_seq;
   float tmp20_seq;
   float tmp21_seq;
   float tmp22_seq;
   float tmp23_seq;
   float tmp24_seq;
   float tmp25_seq;
   float tmp26_seq;
   float tmp27_seq;
   float tmp28_seq;
   float tmp29_seq;
   float tmp30_seq;
   float tmp31_seq;
   float tmp32_seq;
   float tmp33_seq;
   float tmp34_seq;
   float tmp35_seq;
   float tmp36_seq;
   float tmp37_seq;
   float tmp38_seq;
   float tmp39_seq;
   float tmp40_seq;
   float tmp41_seq;
   float tmp42_seq;
   float tmp43_seq;
   float tmp44_seq;
   float tmp45_seq;
   float tmp46_seq;
   float tmp47_seq;
   float tmp48_pul_phase;
   float tmp49_pul_speed;
   float tmp50_freq;
   float tmp51_pul_tmp;
   float tmp52_phase;
   float tmp53_sin_phase;
   float tmp54_sin_speed;
   float tmp55_freq;
   float tmp56_sin_tmp;
   float tmp57_vsync;
   float tmp58_width;
   float tmp59_seq;
   float tmp60_seq;
   float tmp61_pul_phase;
   float tmp62_pul_speed;
   float tmp63_freq;
   float tmp64_pul_tmp;
   float tmp65_phase;
   float tmp66_sin_phase;
   float tmp67_sin_speed;
   float tmp68_freq;
   float tmp69_sin_tmp;
   float tmp70_vsync;
   float tmp71_width;
   float tmp72_seq;
   float tmp73_seq;
   float tmp74_pul_phase;
   float tmp75_pul_speed;
   float tmp76_freq;
   float tmp77_pul_tmp;
   float tmp78_phase;
   float tmp79_sin_phase;
   float tmp80_sin_speed;
   float tmp81_freq;
   float tmp82_sin_tmp;
   float tmp83_vsync;
   float tmp84_width;
   float tmp85_seq;
   float tmp86_seq;
   float tmp87_pul_phase;
   float tmp88_pul_speed;
   float tmp89_freq;
   float tmp90_pul_tmp;
   float tmp91_phase;
   float tmp92_sin_phase;
   float tmp93_sin_speed;
   float tmp94_freq;
   float tmp95_sin_tmp;
   float tmp96_vsync;
   float tmp97_width;
   float tmp98_seq;
   float tmp99_seq;
   float tmp100_pul_phase;
   float tmp101_pul_speed;
   float tmp102_freq;
   float tmp103_pul_tmp;
   float tmp104_phase;
   float tmp105_sin_phase;
   float tmp106_sin_speed;
   float tmp107_freq;
   float tmp108_sin_tmp;
   float tmp109_vsync;
   float tmp110_width;
   float tmp111_seq;
   float var_x;
   float var_v_speed_1;
   float var_v_speed_2;
   float var_v_speed_3;
   float var_v_speed_4;
   float var_v_speed_5;
   float var_v_level_1;
   float var_v_level_2;
   float var_v_level_3;
   float var_v_level_4;
   float var_v_level_5;
   float var_v_pw_1;
   float var_v_pw_2;
   float var_v_pw_3;
   float var_v_pw_4;
   float var_v_pw_5;
   float var_v_vs_1;
   float var_v_vs_2;
   float var_v_vs_3;
   float var_v_vs_4;
   float var_v_vs_5;

   float macrovar_m_level_lv1;
   float macrovar_m_level_lv2;
   float macrovar_m_level_lv3;
   float macrovar_m_level_lv4;
   float macrovar_m_level_lv5;
   float macrovar_m_width_w1;
   float macrovar_m_width_w2;
   float macrovar_m_width_w3;
   float macrovar_m_width_w4;
   float macrovar_m_width_w5;
   float macrovar_m_vsync_vs1;
   float macrovar_m_vsync_vs2;
   float macrovar_m_vsync_vs3;
   float macrovar_m_vsync_vs4;
   float macrovar_m_vsync_vs5;

} osc_hh_v1_voice_t;

static const float macrovalues_m_level[(32 * 5)/*160*/] = {
   /*    0 */ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    1 */ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    2 */ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    3 */ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    4 */ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    5 */ 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    6 */ 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    7 */ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    8 */ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*    9 */ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*   10 */ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   11 */ 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   12 */ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   13 */ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   14 */ 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   15 */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   16 */ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   17 */ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   18 */ 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   19 */ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   20 */ 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   21 */ 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   22 */ 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   23 */ 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   24 */ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   25 */ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   26 */ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   27 */ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   28 */ 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   29 */ 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   30 */ 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
   /*   31 */ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
};

static const float macrovalues_m_width[(32 * 5)/*160*/] = {
   /*    0 */ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    1 */ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    2 */ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    3 */ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    4 */ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    5 */ 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    6 */ 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    7 */ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    8 */ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*    9 */ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*   10 */ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   11 */ 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   12 */ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   13 */ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   14 */ 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   15 */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   16 */ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   17 */ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   18 */ 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   19 */ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   20 */ 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   21 */ 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   22 */ 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   23 */ 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   24 */ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   25 */ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   26 */ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   27 */ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   28 */ 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   29 */ 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   30 */ 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
   /*   31 */ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
};

static const float macrovalues_m_vsync[(32 * 5)/*160*/] = {
   /*    0 */ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    1 */ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 
   /*    2 */ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    3 */ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 
   /*    4 */ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    5 */ 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 
   /*    6 */ 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    7 */ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 
   /*    8 */ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*    9 */ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 
   /*   10 */ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   11 */ 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 
   /*   12 */ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   13 */ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 
   /*   14 */ 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   15 */ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 
   /*   16 */ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   17 */ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 
   /*   18 */ 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   19 */ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
   /*   20 */ 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   21 */ 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 
   /*   22 */ 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   23 */ 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 
   /*   24 */ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   25 */ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 
   /*   26 */ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   27 */ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
   /*   28 */ 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   29 */ 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 
   /*   30 */ 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
   /*   31 */ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 
};

#define loop(X)  for(unsigned int i = 0u; i < (X); i++)
#define clamp(a,b,c) (((a)<(b))?(b):(((a)>(c))?(c):(a)))

static inline float mathLerpf(float _a, float _b, float _t) { return _a + (_b - _a) * _t; }
static inline float mathClampf(float a, float b, float c) { return (((a)<(b))?(b):(((a)>(c))?(c):(a))); }
static inline float mathMinf(float a, float b) { return (a<b)?a:b; }
static inline float mathMaxf(float a, float b) { return (a>b)?a:b; }
static inline float mathAbsMaxf(float _x, float _y) { return ( ( (_x<0.0f)?-_x:_x)>((_y<0.0f)?-_y:_y)?_x:_y ); }
static inline float mathAbsMinf(float _x, float _y) { return ( ((_x<0.0f)?-_x:_x)<((_y<0.0f)?-_y:_y)?_x:_y ); }
static inline float frac(float _x) { return _x - ((int)_x); }

static inline float winLinear(const float *_s, float _index) {
   int idx = (int)_index;
   float r = _index - (float)idx;
   return mathLerpf(_s[idx], _s[idx+1], r);
}

static float ffrac_s(float _f) { int i; if(_f >= 0.0f) { i = (int)_f; return _f - (float)i; } else { i = (int)-_f; return 1.0f - (-_f - (float)i); } }

#define USE_CYCLE_SINE_TBL  defined
static float cycle_sine_tbl_f[16384];

static float loc_bipolar_to_scale(const float _t, const float _div, const float _mul) {
   // t (-1..1) => /_div .. *_mul
   
   float s;

   if(_t < 0.0f)
   {
      s = (1.0f / _div);
      s = 1.0f + (s - 1.0f) * -_t;
      if(s < 0.0f)
         s = 0.0f;
   }
   else
   {
      s = _mul;
      s = 1.0f + (s - 1.0f) * _t;
   }
   
   return s;
}

static void loc_prepare(st_plugin_voice_t *_voice);

void loc_prepare(st_plugin_voice_t *_voice) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   ST_PLUGIN_VOICE_SHARED_CAST(osc_hh_v1_shared_t);

   float out = 0.0f;
   // -------- lane "prepare" modIdx=0
   
   // -- mod="$p_tune_1" dstVar=out
   out = shared->params[PARAM_TUNE_1] * 2.0f - 1.0f;
   
   // -- mod="bts" dstVar=out
   out = loc_bipolar_to_scale(out, 16.0f, 24.0f);
   
   // -- mod="sto v_speed_1" dstVar=out
   voice->var_v_speed_1 = out;
   
   // -- mod="$p_tune_2" dstVar=out
   out = shared->params[PARAM_TUNE_2] * 2.0f - 1.0f;
   
   // -- mod="bts" dstVar=out
   out = loc_bipolar_to_scale(out, 16.0f, 24.0f);
   
   // -- mod="sto v_speed_2" dstVar=out
   voice->var_v_speed_2 = out;
   
   // -- mod="$p_tune_3" dstVar=out
   out = shared->params[PARAM_TUNE_3] * 2.0f - 1.0f;
   
   // -- mod="bts" dstVar=out
   out = loc_bipolar_to_scale(out, 16.0f, 24.0f);
   
   // -- mod="sto v_speed_3" dstVar=out
   voice->var_v_speed_3 = out;
   
   // -- mod="$p_tune_4" dstVar=out
   out = shared->params[PARAM_TUNE_4] * 2.0f - 1.0f;
   
   // -- mod="bts" dstVar=out
   out = loc_bipolar_to_scale(out, 16.0f, 24.0f);
   
   // -- mod="sto v_speed_4" dstVar=out
   voice->var_v_speed_4 = out;
   
   // -- mod="$p_tune_5" dstVar=out
   out = shared->params[PARAM_TUNE_5] * 2.0f - 1.0f;
   
   // -- mod="bts" dstVar=out
   out = loc_bipolar_to_scale(out, 16.0f, 24.0f);
   
   // -- mod="sto v_speed_5" dstVar=out
   voice->var_v_speed_5 = out;
   
   // -- mod="mac" dstVar=out
   
   // ---- mod="mac" input "pos" seq 1/1
   
   // -- mod="$p_level" dstVar=voice->tmp1_pos
   voice->tmp1_pos = shared->params[PARAM_LEVEL];
   voice->tmp1_pos = ffrac_s(voice->tmp1_pos) * 32;
   voice->tmp2_amt = ffrac_s(voice->tmp1_pos);
   int tmp3_idx;
   tmp3_idx = int(voice->tmp1_pos) * 5;
   int tmp4_idx_n;
   tmp4_idx_n = (tmp3_idx + 5) % 160;
   voice->macrovar_m_level_lv1 = mathLerpf(macrovalues_m_level[tmp3_idx + 0], macrovalues_m_level[tmp4_idx_n + 0], voice->tmp2_amt);
   voice->macrovar_m_level_lv2 = mathLerpf(macrovalues_m_level[tmp3_idx + 1], macrovalues_m_level[tmp4_idx_n + 1], voice->tmp2_amt);
   voice->macrovar_m_level_lv3 = mathLerpf(macrovalues_m_level[tmp3_idx + 2], macrovalues_m_level[tmp4_idx_n + 2], voice->tmp2_amt);
   voice->macrovar_m_level_lv4 = mathLerpf(macrovalues_m_level[tmp3_idx + 3], macrovalues_m_level[tmp4_idx_n + 3], voice->tmp2_amt);
   voice->macrovar_m_level_lv5 = mathLerpf(macrovalues_m_level[tmp3_idx + 4], macrovalues_m_level[tmp4_idx_n + 4], voice->tmp2_amt);
   
   // -- mod="mac" dstVar=out
   
   // ---- mod="mac" input "pos" seq 1/1
   
   // -- mod="$p_width" dstVar=voice->tmp5_pos
   voice->tmp5_pos = shared->params[PARAM_WIDTH];
   voice->tmp5_pos = ffrac_s(voice->tmp5_pos) * 32;
   voice->tmp6_amt = ffrac_s(voice->tmp5_pos);
   int tmp7_idx;
   tmp7_idx = int(voice->tmp5_pos) * 5;
   int tmp8_idx_n;
   tmp8_idx_n = (tmp7_idx + 5) % 160;
   voice->macrovar_m_width_w1 = mathLerpf(macrovalues_m_width[tmp7_idx + 0], macrovalues_m_width[tmp8_idx_n + 0], voice->tmp6_amt);
   voice->macrovar_m_width_w2 = mathLerpf(macrovalues_m_width[tmp7_idx + 1], macrovalues_m_width[tmp8_idx_n + 1], voice->tmp6_amt);
   voice->macrovar_m_width_w3 = mathLerpf(macrovalues_m_width[tmp7_idx + 2], macrovalues_m_width[tmp8_idx_n + 2], voice->tmp6_amt);
   voice->macrovar_m_width_w4 = mathLerpf(macrovalues_m_width[tmp7_idx + 3], macrovalues_m_width[tmp8_idx_n + 3], voice->tmp6_amt);
   voice->macrovar_m_width_w5 = mathLerpf(macrovalues_m_width[tmp7_idx + 4], macrovalues_m_width[tmp8_idx_n + 4], voice->tmp6_amt);
   
   // -- mod="mac" dstVar=out
   
   // ---- mod="mac" input "pos" seq 1/1
   
   // -- mod="$p_vsync" dstVar=voice->tmp9_pos
   voice->tmp9_pos = shared->params[PARAM_VSYNC];
   voice->tmp9_pos = ffrac_s(voice->tmp9_pos) * 32;
   voice->tmp10_amt = ffrac_s(voice->tmp9_pos);
   int tmp11_idx;
   tmp11_idx = int(voice->tmp9_pos) * 5;
   int tmp12_idx_n;
   tmp12_idx_n = (tmp11_idx + 5) % 160;
   voice->macrovar_m_vsync_vs1 = mathLerpf(macrovalues_m_vsync[tmp11_idx + 0], macrovalues_m_vsync[tmp12_idx_n + 0], voice->tmp10_amt);
   voice->macrovar_m_vsync_vs2 = mathLerpf(macrovalues_m_vsync[tmp11_idx + 1], macrovalues_m_vsync[tmp12_idx_n + 1], voice->tmp10_amt);
   voice->macrovar_m_vsync_vs3 = mathLerpf(macrovalues_m_vsync[tmp11_idx + 2], macrovalues_m_vsync[tmp12_idx_n + 2], voice->tmp10_amt);
   voice->macrovar_m_vsync_vs4 = mathLerpf(macrovalues_m_vsync[tmp11_idx + 3], macrovalues_m_vsync[tmp12_idx_n + 3], voice->tmp10_amt);
   voice->macrovar_m_vsync_vs5 = mathLerpf(macrovalues_m_vsync[tmp11_idx + 4], macrovalues_m_vsync[tmp12_idx_n + 4], voice->tmp10_amt);
   
   // -- mod="1" dstVar=out
   out = 1.0f;
   
   // -- mod="m_level.lv1" dstVar=out
   voice->tmp13_seq = voice->macrovar_m_level_lv1;
   out -= voice->tmp13_seq;
   
   // -- mod="0.75" dstVar=out
   voice->tmp14_seq = 0.75f;
   out *= voice->tmp14_seq;
   
   // -- mod="0.25" dstVar=out
   voice->tmp15_seq = 0.25f;
   out += voice->tmp15_seq;
   
   // -- mod="sto v_level_1" dstVar=out
   voice->var_v_level_1 = out;
   
   // -- mod="1" dstVar=out
   out = 1.0f;
   
   // -- mod="m_level.lv2" dstVar=out
   voice->tmp16_seq = voice->macrovar_m_level_lv2;
   out -= voice->tmp16_seq;
   
   // -- mod="0.75" dstVar=out
   voice->tmp17_seq = 0.75f;
   out *= voice->tmp17_seq;
   
   // -- mod="0.25" dstVar=out
   voice->tmp18_seq = 0.25f;
   out += voice->tmp18_seq;
   
   // -- mod="sto v_level_2" dstVar=out
   voice->var_v_level_2 = out;
   
   // -- mod="1" dstVar=out
   out = 1.0f;
   
   // -- mod="m_level.lv3" dstVar=out
   voice->tmp19_seq = voice->macrovar_m_level_lv3;
   out -= voice->tmp19_seq;
   
   // -- mod="0.75" dstVar=out
   voice->tmp20_seq = 0.75f;
   out *= voice->tmp20_seq;
   
   // -- mod="0.25" dstVar=out
   voice->tmp21_seq = 0.25f;
   out += voice->tmp21_seq;
   
   // -- mod="sto v_level_3" dstVar=out
   voice->var_v_level_3 = out;
   
   // -- mod="1" dstVar=out
   out = 1.0f;
   
   // -- mod="m_level.lv4" dstVar=out
   voice->tmp22_seq = voice->macrovar_m_level_lv4;
   out -= voice->tmp22_seq;
   
   // -- mod="0.75" dstVar=out
   voice->tmp23_seq = 0.75f;
   out *= voice->tmp23_seq;
   
   // -- mod="0.25" dstVar=out
   voice->tmp24_seq = 0.25f;
   out += voice->tmp24_seq;
   
   // -- mod="sto v_level_4" dstVar=out
   voice->var_v_level_4 = out;
   
   // -- mod="1" dstVar=out
   out = 1.0f;
   
   // -- mod="m_level.lv5" dstVar=out
   voice->tmp25_seq = voice->macrovar_m_level_lv5;
   out -= voice->tmp25_seq;
   
   // -- mod="0.75" dstVar=out
   voice->tmp26_seq = 0.75f;
   out *= voice->tmp26_seq;
   
   // -- mod="0.25" dstVar=out
   voice->tmp27_seq = 0.25f;
   out += voice->tmp27_seq;
   
   // -- mod="sto v_level_5" dstVar=out
   voice->var_v_level_5 = out;
   
   // -- mod="m_width.w1" dstVar=out
   out = voice->macrovar_m_width_w1;
   
   // -- mod="0.4" dstVar=out
   voice->tmp28_seq = 0.4f;
   out *= voice->tmp28_seq;
   
   // -- mod="0.5" dstVar=out
   voice->tmp29_seq = 0.5f;
   out += voice->tmp29_seq;
   
   // -- mod="sto v_pw_1" dstVar=out
   voice->var_v_pw_1 = out;
   
   // -- mod="m_width.w2" dstVar=out
   out = voice->macrovar_m_width_w2;
   
   // -- mod="0.4" dstVar=out
   voice->tmp30_seq = 0.4f;
   out *= voice->tmp30_seq;
   
   // -- mod="0.5" dstVar=out
   voice->tmp31_seq = 0.5f;
   out += voice->tmp31_seq;
   
   // -- mod="sto v_pw_2" dstVar=out
   voice->var_v_pw_2 = out;
   
   // -- mod="m_width.w3" dstVar=out
   out = voice->macrovar_m_width_w3;
   
   // -- mod="0.4" dstVar=out
   voice->tmp32_seq = 0.4f;
   out *= voice->tmp32_seq;
   
   // -- mod="0.5" dstVar=out
   voice->tmp33_seq = 0.5f;
   out += voice->tmp33_seq;
   
   // -- mod="sto v_pw_3" dstVar=out
   voice->var_v_pw_3 = out;
   
   // -- mod="m_width.w4" dstVar=out
   out = voice->macrovar_m_width_w4;
   
   // -- mod="0.4" dstVar=out
   voice->tmp34_seq = 0.4f;
   out *= voice->tmp34_seq;
   
   // -- mod="0.5" dstVar=out
   voice->tmp35_seq = 0.5f;
   out += voice->tmp35_seq;
   
   // -- mod="sto v_pw_4" dstVar=out
   voice->var_v_pw_4 = out;
   
   // -- mod="m_width.w5" dstVar=out
   out = voice->macrovar_m_width_w5;
   
   // -- mod="0.4" dstVar=out
   voice->tmp36_seq = 0.4f;
   out *= voice->tmp36_seq;
   
   // -- mod="0.5" dstVar=out
   voice->tmp37_seq = 0.5f;
   out += voice->tmp37_seq;
   
   // -- mod="sto v_pw_5" dstVar=out
   voice->var_v_pw_5 = out;
   
   // -- mod="m_vsync.vs1" dstVar=out
   out = voice->macrovar_m_vsync_vs1;
   
   // -- mod="1" dstVar=out
   voice->tmp38_seq = 1.0f;
   out += voice->tmp38_seq;
   
   // -- mod="7" dstVar=out
   voice->tmp39_seq = 7.0f;
   out *= voice->tmp39_seq;
   
   // -- mod="sto v_vs_1" dstVar=out
   voice->var_v_vs_1 = out;
   
   // -- mod="m_vsync.vs2" dstVar=out
   out = voice->macrovar_m_vsync_vs2;
   
   // -- mod="1" dstVar=out
   voice->tmp40_seq = 1.0f;
   out += voice->tmp40_seq;
   
   // -- mod="7" dstVar=out
   voice->tmp41_seq = 7.0f;
   out *= voice->tmp41_seq;
   
   // -- mod="sto v_vs_2" dstVar=out
   voice->var_v_vs_2 = out;
   
   // -- mod="m_vsync.vs3" dstVar=out
   out = voice->macrovar_m_vsync_vs3;
   
   // -- mod="1" dstVar=out
   voice->tmp42_seq = 1.0f;
   out += voice->tmp42_seq;
   
   // -- mod="7" dstVar=out
   voice->tmp43_seq = 7.0f;
   out *= voice->tmp43_seq;
   
   // -- mod="sto v_vs_3" dstVar=out
   voice->var_v_vs_3 = out;
   
   // -- mod="m_vsync.vs4" dstVar=out
   out = voice->macrovar_m_vsync_vs4;
   
   // -- mod="1" dstVar=out
   voice->tmp44_seq = 1.0f;
   out += voice->tmp44_seq;
   
   // -- mod="7" dstVar=out
   voice->tmp45_seq = 7.0f;
   out *= voice->tmp45_seq;
   
   // -- mod="sto v_vs_4" dstVar=out
   voice->var_v_vs_4 = out;
   
   // -- mod="m_vsync.vs5" dstVar=out
   out = voice->macrovar_m_vsync_vs5;
   
   // -- mod="1" dstVar=out
   voice->tmp46_seq = 1.0f;
   out += voice->tmp46_seq;
   
   // -- mod="7" dstVar=out
   voice->tmp47_seq = 7.0f;
   out *= voice->tmp47_seq;
   
   // -- mod="sto v_vs_5" dstVar=out
   voice->var_v_vs_5 = out;
} /* end prepare */

static unsigned int loc_copy_chars(char *_d, const unsigned int _dSize, const char *_s) {
   unsigned int r = 0u;
   if(NULL != _d)
   {
      // Write min(dSize,len(s)) characters to 'd'
      char *d = _d;
      if(NULL != _s)
      {
         const char *s = _s;
         for(;;)
         {
            if(r < _dSize)
            {
               char c = s[r++];
               *d++ = c;
               if(0 == c)
                  break;
            }
            else
            {
               if(r > 0u)
                  d[-1] = 0;  // force ASCIIZ
               break;
            }
         }
      }
      else
      {
         if(_dSize > 0u)
         {
            _d[0] = 0;
            r = 1u;
         }
      }
   }
   else
   {
      // Return total length of source string
      if(NULL != _s)
      {
         const char *s = _s;
         for(;;)
         {
            char c = s[r++];
            if(0 == c)
               break;
         }
      }
   }
   return r;
}

static unsigned int loc_copy_floats(float              *_d,
                                    const unsigned int  _dSize,
                                    const float        *_s,
                                    const unsigned int  _sNum
                                    ) {
   unsigned int r = 0u;
   if(NULL != _d)
   {
      // Write min(dSize,sNum) characters to 'd'
      if(NULL != _s)
      {
         unsigned int num = (_sNum > _dSize) ? _dSize : _sNum;
         memcpy((void*)_d, (const void*)_s, num * sizeof(float));
         r = num;
      }
   }
   else
   {
      // Query total number of presets
      r = _sNum;
   }
   return r;
}

static const char *ST_PLUGIN_API loc_get_param_name(st_plugin_info_t *_info,
                                                    unsigned int      _paramIdx
                                                    ) {
   (void)_info;
   return loc_param_names[_paramIdx];
}

static const char *ST_PLUGIN_API loc_get_param_group_name(st_plugin_info_t *_info,
                                                          unsigned int      _paramGroupIdx
                                                          ) {
   (void)_info;
   const char *r = NULL;
   static const char *groupNames[2] = { "tune", "shape" };
   if(_paramGroupIdx < 2u)
      r = groupNames[_paramGroupIdx];
   return r;
}

static unsigned int ST_PLUGIN_API loc_get_param_group_idx(st_plugin_info_t *_info,
                                                          unsigned int      _paramIdx
                                                          ) {
   (void)_info;
   unsigned int r = ~0u;
   static unsigned int groupIndices[NUM_PARAMS] = { 0, 0, 0, 0, 0, 1, 1, 1 };
   r = groupIndices[_paramIdx];
   return r;
}

static float ST_PLUGIN_API loc_get_param_reset(st_plugin_info_t *_info,
                                               unsigned int      _paramIdx
                                               ) {
   (void)_info;
   return loc_param_resets[_paramIdx];
}

static float ST_PLUGIN_API loc_get_param_value(st_plugin_shared_t *_shared,
                                               unsigned int        _paramIdx
                                               ) {
   ST_PLUGIN_SHARED_CAST(osc_hh_v1_shared_t);
   return shared->params[_paramIdx];
}

static void ST_PLUGIN_API loc_set_param_value(st_plugin_shared_t *_shared,
                                              unsigned int        _paramIdx,
                                              float               _value
                                              ) {
   ST_PLUGIN_SHARED_CAST(osc_hh_v1_shared_t);
   shared->params[_paramIdx] = _value;
}

static unsigned int ST_PLUGIN_API loc_query_dynamic_param_preset_values(st_plugin_shared_t *_shared,
                                                                        const unsigned int  _paramIdx,
                                                                        float              *_retValues,
                                                                        const unsigned int  _retValuesSize
                                                                        ) {
   ST_PLUGIN_SHARED_CAST(osc_hh_v1_shared_t);
   unsigned int r = 0u;

   return r;
}

static unsigned int ST_PLUGIN_API loc_query_dynamic_param_preset_name(st_plugin_shared_t *_shared,
                                                                      const unsigned int  _paramIdx,
                                                                      const unsigned int  _presetIdx,
                                                                      char               *_retBuf,
                                                                      const unsigned int  _retBufSize
                                                                      ) {
   ST_PLUGIN_SHARED_CAST(osc_hh_v1_shared_t);
   unsigned int r = 0u;

   return r;
}

static const char *ST_PLUGIN_API loc_get_mod_name(st_plugin_info_t *_info,
                                                  unsigned int      _modIdx
                                                  ) {
   (void)_info;
   return loc_mod_names[_modIdx];
}

static void ST_PLUGIN_API loc_set_sample_rate(st_plugin_voice_t *_voice,
                                              float              _sampleRate
                                              ) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   voice->sample_rate = _sampleRate;
}

static void ST_PLUGIN_API loc_note_on(st_plugin_voice_t  *_voice,
                                      int                 _bGlide,
                                      unsigned char       _note,
                                      float               _vel
                                      ) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   ST_PLUGIN_VOICE_SHARED_CAST(osc_hh_v1_shared_t);
   (void)_bGlide;
   (void)_note;
   (void)_vel;
   if(!_bGlide)
   {
      memset((void*)voice->mods, 0, sizeof(voice->mods));
#ifdef OVERSAMPLE_FACTOR
      voice->note_speed_fixed = (0.5f / (voice->sample_rate * OVERSAMPLE_FACTOR));
#else
      voice->note_speed_fixed = (0.5f / voice->sample_rate);
#endif // OVERSAMPLE_FACTOR


      voice->tmp48_pul_phase = 0.0f;
      voice->tmp53_sin_phase = 0.0f;
      voice->tmp61_pul_phase = 0.0f;
      voice->tmp66_sin_phase = 0.0f;
      voice->tmp74_pul_phase = 0.0f;
      voice->tmp79_sin_phase = 0.0f;
      voice->tmp87_pul_phase = 0.0f;
      voice->tmp92_sin_phase = 0.0f;
      voice->tmp100_pul_phase = 0.0f;
      voice->tmp105_sin_phase = 0.0f;

      voice->var_x = 0.0f;
      voice->var_v_speed_1 = 0.0f;
      voice->var_v_speed_2 = 0.0f;
      voice->var_v_speed_3 = 0.0f;
      voice->var_v_speed_4 = 0.0f;
      voice->var_v_speed_5 = 0.0f;
      voice->var_v_level_1 = 0.0f;
      voice->var_v_level_2 = 0.0f;
      voice->var_v_level_3 = 0.0f;
      voice->var_v_level_4 = 0.0f;
      voice->var_v_level_5 = 0.0f;
      voice->var_v_pw_1 = 0.0f;
      voice->var_v_pw_2 = 0.0f;
      voice->var_v_pw_3 = 0.0f;
      voice->var_v_pw_4 = 0.0f;
      voice->var_v_pw_5 = 0.0f;
      voice->var_v_vs_1 = 0.0f;
      voice->var_v_vs_2 = 0.0f;
      voice->var_v_vs_3 = 0.0f;
      voice->var_v_vs_4 = 0.0f;
      voice->var_v_vs_5 = 0.0f;
      voice->macrovar_m_level_lv1 = 0;
      voice->macrovar_m_level_lv2 = 0;
      voice->macrovar_m_level_lv3 = 0;
      voice->macrovar_m_level_lv4 = 0;
      voice->macrovar_m_level_lv5 = 0;
      voice->macrovar_m_width_w1 = 0;
      voice->macrovar_m_width_w2 = 0;
      voice->macrovar_m_width_w3 = 0;
      voice->macrovar_m_width_w4 = 0;
      voice->macrovar_m_width_w5 = 0;
      voice->macrovar_m_vsync_vs1 = 0;
      voice->macrovar_m_vsync_vs2 = 0;
      voice->macrovar_m_vsync_vs3 = 0;
      voice->macrovar_m_vsync_vs4 = 0;
      voice->macrovar_m_vsync_vs5 = 0;


   }
}

static void ST_PLUGIN_API loc_set_mod_value(st_plugin_voice_t *_voice,
                                            unsigned int       _modIdx,
                                            float              _value,
                                            unsigned           _frameOffset
                                            ) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   (void)_frameOffset;
   voice->mods[_modIdx] = _value;
}

static void ST_PLUGIN_API loc_prepare_block(st_plugin_voice_t *_voice,
                                            unsigned int       _numFrames,
                                            float              _freqHz,
                                            float              _note,
                                            float              _vol,
                                            float              _pan
                                            ) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   ST_PLUGIN_VOICE_SHARED_CAST(osc_hh_v1_shared_t);
   (void)_note;
   (void)_vol;
   (void)_pan;

#ifdef OVERSAMPLE_FACTOR
   float noteSpeed = _freqHz / (voice->sample_rate * OVERSAMPLE_FACTOR);
#else
   float noteSpeed = _freqHz / voice->sample_rate;
#endif // OVERSAMPLE_FACTOR


   if(_numFrames > 0u)
   {
      // lerp
      float recBlockSize = (1.0f / _numFrames);
      voice->note_speed_inc = (noteSpeed - voice->note_speed_cur) * recBlockSize;
      voice->note_inc       = (_note - voice->note_cur) * recBlockSize;

      loc_prepare(&voice->base);
   }
   else
   {
      // initial params/modulation (first block, not rendered)
      voice->note_speed_cur = noteSpeed;
      voice->note_speed_inc = 0.0f;
      voice->note_cur       = _note;
      voice->note_inc       = 0.0f;

      loc_prepare(&voice->base);
   }

   // printf("xxx note_cur=%f\n", voice->note_cur);
}

static void ST_PLUGIN_API loc_process_replace(st_plugin_voice_t  *_voice,
                                              int                 _bMonoIn,
                                              const float        *_samplesIn,
                                              float              *_samplesOut, 
                                              unsigned int        _numFrames
                                              ) {
   (void)_bMonoIn;
   (void)_samplesIn;

   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);
   ST_PLUGIN_VOICE_SHARED_CAST(osc_hh_v1_shared_t);

   // Mono output (replicate left to right channel)
   unsigned int j = 0u;
   unsigned int jStep = _bMonoIn ? 1u : 2u;
   unsigned int k = 0u;
   for(unsigned int i = 0u; i < _numFrames; i++)
   {
      float out = _samplesIn[j];
      j += jStep;
#ifdef OVERSAMPLE_FACTOR
      float outOS = 0.0f;
#endif // OVERSAMPLE_FACTOR

#ifdef OVERSAMPLE_FACTOR
      for(unsigned int osi = 0u; osi < OVERSAMPLE_FACTOR; osi++)
#endif // OVERSAMPLE_FACTOR
      {
         float tmp_f;
         float tmp2_f;
         
         // ========
         // ======== lane "out" modIdx=0
         // ========
         
         // -- mod="pul" dstVar=out
         
         // ---- mod="pul" input "freq" seq 1/1
         
         // -- mod="$v_speed_1" dstVar=voice->tmp50_freq
         voice->tmp50_freq = voice->var_v_speed_1;
         voice->tmp49_pul_speed = voice->note_speed_cur * voice->tmp50_freq;
         
         // ---- mod="pul" input "phase" seq 1/1
         
         // -- mod="sin" dstVar=voice->tmp52_phase
         
         // ---- mod="sin" input "freq" seq 1/1
         
         // -- mod="0.0001" dstVar=voice->tmp55_freq
         voice->tmp55_freq = 0.0001f;
         voice->tmp54_sin_speed = voice->note_speed_cur * voice->tmp55_freq;
         voice->tmp56_sin_tmp = (voice->tmp53_sin_phase);
         voice->tmp56_sin_tmp = ffrac_s(voice->tmp56_sin_tmp);
         voice->tmp52_phase = cycle_sine_tbl_f[(unsigned short)(16384 * voice->tmp56_sin_tmp)&16383u];
         voice->tmp53_sin_phase = ffrac_s(voice->tmp53_sin_phase + voice->tmp54_sin_speed);
         
         // ---- mod="pul" input "vsync" seq 1/1
         
         // -- mod="$v_vs_1" dstVar=voice->tmp57_vsync
         voice->tmp57_vsync = voice->var_v_vs_1;
         
         // ---- mod="pul" input "width" seq 1/1
         
         // -- mod="$v_pw_1" dstVar=voice->tmp58_width
         voice->tmp58_width = voice->var_v_pw_1;
         voice->tmp51_pul_tmp = ((voice->tmp48_pul_phase + voice->tmp52_phase));
         voice->tmp51_pul_tmp = voice->tmp51_pul_tmp * voice->tmp57_vsync;
         voice->tmp51_pul_tmp = ffrac_s(voice->tmp51_pul_tmp);
         out = (voice->tmp51_pul_tmp >= voice->tmp58_width) ? 1.0f : -1.0f;
         voice->tmp48_pul_phase = ffrac_s(voice->tmp48_pul_phase + voice->tmp49_pul_speed);
         
         // -- mod="$v_level_1" dstVar=out
         voice->tmp59_seq = voice->var_v_level_1;
         out *= voice->tmp59_seq;
         
         // -- mod="pul" dstVar=out
         
         // ---- mod="pul" input "freq" seq 1/1
         
         // -- mod="$v_speed_2" dstVar=voice->tmp63_freq
         voice->tmp63_freq = voice->var_v_speed_2;
         voice->tmp62_pul_speed = voice->note_speed_cur * voice->tmp63_freq;
         
         // ---- mod="pul" input "phase" seq 1/1
         
         // -- mod="sin" dstVar=voice->tmp65_phase
         
         // ---- mod="sin" input "freq" seq 1/1
         
         // -- mod="0.0003" dstVar=voice->tmp68_freq
         voice->tmp68_freq = 0.0003f;
         voice->tmp67_sin_speed = voice->note_speed_cur * voice->tmp68_freq;
         voice->tmp69_sin_tmp = (voice->tmp66_sin_phase);
         voice->tmp69_sin_tmp = ffrac_s(voice->tmp69_sin_tmp);
         voice->tmp65_phase = cycle_sine_tbl_f[(unsigned short)(16384 * voice->tmp69_sin_tmp)&16383u];
         voice->tmp66_sin_phase = ffrac_s(voice->tmp66_sin_phase + voice->tmp67_sin_speed);
         
         // ---- mod="pul" input "vsync" seq 1/1
         
         // -- mod="$v_vs_2" dstVar=voice->tmp70_vsync
         voice->tmp70_vsync = voice->var_v_vs_2;
         
         // ---- mod="pul" input "width" seq 1/1
         
         // -- mod="$v_pw_2" dstVar=voice->tmp71_width
         voice->tmp71_width = voice->var_v_pw_2;
         voice->tmp64_pul_tmp = ((voice->tmp61_pul_phase + voice->tmp65_phase));
         voice->tmp64_pul_tmp = voice->tmp64_pul_tmp * voice->tmp70_vsync;
         voice->tmp64_pul_tmp = ffrac_s(voice->tmp64_pul_tmp);
         voice->tmp60_seq = (voice->tmp64_pul_tmp >= voice->tmp71_width) ? 1.0f : -1.0f;
         voice->tmp61_pul_phase = ffrac_s(voice->tmp61_pul_phase + voice->tmp62_pul_speed);
         
         // -- mod="$v_level_2" dstVar=voice->tmp60_seq
         voice->tmp72_seq = voice->var_v_level_2;
         voice->tmp60_seq *= voice->tmp72_seq;
         out += voice->tmp60_seq;
         
         // -- mod="pul" dstVar=out
         
         // ---- mod="pul" input "freq" seq 1/1
         
         // -- mod="$v_speed_3" dstVar=voice->tmp76_freq
         voice->tmp76_freq = voice->var_v_speed_3;
         voice->tmp75_pul_speed = voice->note_speed_cur * voice->tmp76_freq;
         
         // ---- mod="pul" input "phase" seq 1/1
         
         // -- mod="sin" dstVar=voice->tmp78_phase
         
         // ---- mod="sin" input "freq" seq 1/1
         
         // -- mod="0.0005" dstVar=voice->tmp81_freq
         voice->tmp81_freq = 0.0005f;
         voice->tmp80_sin_speed = voice->note_speed_cur * voice->tmp81_freq;
         voice->tmp82_sin_tmp = (voice->tmp79_sin_phase);
         voice->tmp82_sin_tmp = ffrac_s(voice->tmp82_sin_tmp);
         voice->tmp78_phase = cycle_sine_tbl_f[(unsigned short)(16384 * voice->tmp82_sin_tmp)&16383u];
         voice->tmp79_sin_phase = ffrac_s(voice->tmp79_sin_phase + voice->tmp80_sin_speed);
         
         // ---- mod="pul" input "vsync" seq 1/1
         
         // -- mod="$v_vs_3" dstVar=voice->tmp83_vsync
         voice->tmp83_vsync = voice->var_v_vs_3;
         
         // ---- mod="pul" input "width" seq 1/1
         
         // -- mod="$v_pw_3" dstVar=voice->tmp84_width
         voice->tmp84_width = voice->var_v_pw_3;
         voice->tmp77_pul_tmp = ((voice->tmp74_pul_phase + voice->tmp78_phase));
         voice->tmp77_pul_tmp = voice->tmp77_pul_tmp * voice->tmp83_vsync;
         voice->tmp77_pul_tmp = ffrac_s(voice->tmp77_pul_tmp);
         voice->tmp73_seq = (voice->tmp77_pul_tmp >= voice->tmp84_width) ? 1.0f : -1.0f;
         voice->tmp74_pul_phase = ffrac_s(voice->tmp74_pul_phase + voice->tmp75_pul_speed);
         
         // -- mod="$v_level_3" dstVar=voice->tmp73_seq
         voice->tmp85_seq = voice->var_v_level_3;
         voice->tmp73_seq *= voice->tmp85_seq;
         out += voice->tmp73_seq;
         
         // -- mod="pul" dstVar=out
         
         // ---- mod="pul" input "freq" seq 1/1
         
         // -- mod="$v_speed_4" dstVar=voice->tmp89_freq
         voice->tmp89_freq = voice->var_v_speed_4;
         voice->tmp88_pul_speed = voice->note_speed_cur * voice->tmp89_freq;
         
         // ---- mod="pul" input "phase" seq 1/1
         
         // -- mod="sin" dstVar=voice->tmp91_phase
         
         // ---- mod="sin" input "freq" seq 1/1
         
         // -- mod="0.0007" dstVar=voice->tmp94_freq
         voice->tmp94_freq = 0.0007f;
         voice->tmp93_sin_speed = voice->note_speed_cur * voice->tmp94_freq;
         voice->tmp95_sin_tmp = (voice->tmp92_sin_phase);
         voice->tmp95_sin_tmp = ffrac_s(voice->tmp95_sin_tmp);
         voice->tmp91_phase = cycle_sine_tbl_f[(unsigned short)(16384 * voice->tmp95_sin_tmp)&16383u];
         voice->tmp92_sin_phase = ffrac_s(voice->tmp92_sin_phase + voice->tmp93_sin_speed);
         
         // ---- mod="pul" input "vsync" seq 1/1
         
         // -- mod="$v_vs_4" dstVar=voice->tmp96_vsync
         voice->tmp96_vsync = voice->var_v_vs_4;
         
         // ---- mod="pul" input "width" seq 1/1
         
         // -- mod="$v_pw_4" dstVar=voice->tmp97_width
         voice->tmp97_width = voice->var_v_pw_4;
         voice->tmp90_pul_tmp = ((voice->tmp87_pul_phase + voice->tmp91_phase));
         voice->tmp90_pul_tmp = voice->tmp90_pul_tmp * voice->tmp96_vsync;
         voice->tmp90_pul_tmp = ffrac_s(voice->tmp90_pul_tmp);
         voice->tmp86_seq = (voice->tmp90_pul_tmp >= voice->tmp97_width) ? 1.0f : -1.0f;
         voice->tmp87_pul_phase = ffrac_s(voice->tmp87_pul_phase + voice->tmp88_pul_speed);
         
         // -- mod="$v_level_4" dstVar=voice->tmp86_seq
         voice->tmp98_seq = voice->var_v_level_4;
         voice->tmp86_seq *= voice->tmp98_seq;
         out += voice->tmp86_seq;
         
         // -- mod="pul" dstVar=out
         
         // ---- mod="pul" input "freq" seq 1/1
         
         // -- mod="$v_speed_5" dstVar=voice->tmp102_freq
         voice->tmp102_freq = voice->var_v_speed_5;
         voice->tmp101_pul_speed = voice->note_speed_cur * voice->tmp102_freq;
         
         // ---- mod="pul" input "phase" seq 1/1
         
         // -- mod="sin" dstVar=voice->tmp104_phase
         
         // ---- mod="sin" input "freq" seq 1/1
         
         // -- mod="0.0011" dstVar=voice->tmp107_freq
         voice->tmp107_freq = 0.0011f;
         voice->tmp106_sin_speed = voice->note_speed_cur * voice->tmp107_freq;
         voice->tmp108_sin_tmp = (voice->tmp105_sin_phase);
         voice->tmp108_sin_tmp = ffrac_s(voice->tmp108_sin_tmp);
         voice->tmp104_phase = cycle_sine_tbl_f[(unsigned short)(16384 * voice->tmp108_sin_tmp)&16383u];
         voice->tmp105_sin_phase = ffrac_s(voice->tmp105_sin_phase + voice->tmp106_sin_speed);
         
         // ---- mod="pul" input "vsync" seq 1/1
         
         // -- mod="$v_vs_5" dstVar=voice->tmp109_vsync
         voice->tmp109_vsync = voice->var_v_vs_5;
         
         // ---- mod="pul" input "width" seq 1/1
         
         // -- mod="$v_pw_5" dstVar=voice->tmp110_width
         voice->tmp110_width = voice->var_v_pw_5;
         voice->tmp103_pul_tmp = ((voice->tmp100_pul_phase + voice->tmp104_phase));
         voice->tmp103_pul_tmp = voice->tmp103_pul_tmp * voice->tmp109_vsync;
         voice->tmp103_pul_tmp = ffrac_s(voice->tmp103_pul_tmp);
         voice->tmp99_seq = (voice->tmp103_pul_tmp >= voice->tmp110_width) ? 1.0f : -1.0f;
         voice->tmp100_pul_phase = ffrac_s(voice->tmp100_pul_phase + voice->tmp101_pul_speed);
         
         // -- mod="$v_level_5" dstVar=voice->tmp99_seq
         voice->tmp111_seq = voice->var_v_level_5;
         voice->tmp99_seq *= voice->tmp111_seq;
         out += voice->tmp99_seq;
         
         // -- mod="clp" dstVar=out
         if(out > 0.999f) out = 0.999f;
         else if(out < -0.999f) out = -0.999f;
   
         /* end calc */

#ifdef OVERSAMPLE_FACTOR
         outOS += out;
#endif // OVERSAMPLE_FACTOR
      }
#ifdef OVERSAMPLE_FACTOR
      // Apply lowpass filter before downsampling
      //   (note) normalized Fc = F/Fs = 0.442947 / sqrt(oversample_factorČ - 1)
      out = outOS * (1.0f / OVERSAMPLE_FACTOR);
#endif // OVERSAMPLE_FACTOR
      _samplesOut[k]      = out;
      _samplesOut[k + 1u] = out;

      // Next frame
      k += 2u;
      voice->note_speed_cur += voice->note_speed_inc;
   } /* loop numFrames */
}

static st_plugin_shared_t *ST_PLUGIN_API loc_shared_new(st_plugin_info_t *_info) {
   osc_hh_v1_shared_t *ret = (osc_hh_v1_shared_t *)malloc(sizeof(osc_hh_v1_shared_t));
   if(NULL != ret)
   {
      memset((void*)ret, 0, sizeof(*ret));
      ret->base.info  = _info;
      memcpy((void*)ret->params, (void*)loc_param_resets, NUM_PARAMS * sizeof(float));
   }
   return &ret->base;
}

static void ST_PLUGIN_API loc_shared_delete(st_plugin_shared_t *_shared) {
   free((void*)_shared);
}

static st_plugin_voice_t *ST_PLUGIN_API loc_voice_new(st_plugin_info_t *_info) {
   osc_hh_v1_voice_t *voice = (osc_hh_v1_voice_t *)malloc(sizeof(osc_hh_v1_voice_t));
   if(NULL != voice)
   {
      memset((void*)voice, 0, sizeof(*voice));
      voice->base.info = _info;
   }
   return &voice->base;
}

static void ST_PLUGIN_API loc_voice_delete(st_plugin_voice_t *_voice) {
   ST_PLUGIN_VOICE_CAST(osc_hh_v1_voice_t);

   free((void*)_voice);
}

static void ST_PLUGIN_API loc_plugin_exit(st_plugin_info_t *_info) {
   free((void*)_info);
}

#ifdef USE_CYCLE_SINE_TBL
static void loc_calc_sine_tbl(void) {
#define QCOS_BITS 16
#define QCOS_ONE  (1 << QCOS_BITS)
#define QCOS_MASK (QCOS_ONE - 1)
   // (note) same as in TSR "C" implementation
   float *qcos = cycle_sine_tbl_f + 4096; // quarter cos tbl

   // calc quarter cos tbl
   int k = 0;
   for(int a = 0; a < (QCOS_ONE/4); a += (QCOS_ONE/16384)/*4*/)  // 4096 elements
   {
      int x = a - ((int)(QCOS_ONE * 0.25 + 0.5)) + ((a + ((int)(QCOS_ONE * 0.25 + 0.5)))&~QCOS_MASK);
      x = ((x * ((x<0?-x:x) - ((int)(QCOS_ONE * 0.5 + 0.5)))) >> QCOS_BITS) << 4;
      x += (((((int)(QCOS_ONE * 0.225 + 0.5)) * x) >> QCOS_BITS) * ((x<0?-x:x) - QCOS_ONE)) >> QCOS_BITS;
      qcos[k++] = x / float(QCOS_ONE);
   }

   // 0°..90° (rev qtbl)
   int j = 4096;
   k = 0;
   loop(4096)
      cycle_sine_tbl_f[k++] = qcos[--j];

   // 90..180° = cos tbl
   k += 4096;

   // 180°..360° (y-flip first half of tbl)
   j = 0;
   loop(8192)
      cycle_sine_tbl_f[k++] = -cycle_sine_tbl_f[j++];

#ifdef USE_CYCLE_SINE_TBL_I
   loop(16384)
      cycle_sine_tbl_i[i] = (short)(cycle_sine_tbl_f[i] * 2048.0f/*FX_ONE*/);
#endif // USE_CYCLE_SINE_TBL_I
}
#endif // USE_CYCLE_SINE_TBL

extern "C" {
st_plugin_info_t *osc_hh_v1_init(void) {
   osc_hh_v1_info_t *ret = (osc_hh_v1_info_t *)malloc(sizeof(osc_hh_v1_info_t));

   if(NULL != ret)
   {
      memset(ret, 0, sizeof(*ret));

      ret->base.api_version = ST_PLUGIN_API_VERSION;
      ret->base.id          = "osc_hh_v1";  // unique id. don't change this in future builds.
      ret->base.author      = "bsp";
      ret->base.name        = "osc_hh_v1";
      ret->base.short_name  = "osc_hh_v1";
      ret->base.flags       = ST_PLUGIN_FLAG_OSC;
      ret->base.category    = ST_PLUGIN_CAT_UNKNOWN;
      ret->base.num_params  = NUM_PARAMS;
      ret->base.num_mods    = NUM_MODS;

      ret->base.shared_new                        = &loc_shared_new;
      ret->base.shared_delete                     = &loc_shared_delete;
      ret->base.voice_new                         = &loc_voice_new;
      ret->base.voice_delete                      = &loc_voice_delete;
      ret->base.get_param_name                    = &loc_get_param_name;
      ret->base.get_param_group_name              = &loc_get_param_group_name;
      ret->base.get_param_group_idx               = &loc_get_param_group_idx;
      ret->base.get_param_reset                   = &loc_get_param_reset;
      ret->base.query_dynamic_param_preset_values = &loc_query_dynamic_param_preset_values;
      ret->base.query_dynamic_param_preset_name   = &loc_query_dynamic_param_preset_name;
      ret->base.get_param_value                   = &loc_get_param_value;
      ret->base.set_param_value                   = &loc_set_param_value;
      ret->base.get_mod_name                      = &loc_get_mod_name;
      ret->base.set_sample_rate                   = &loc_set_sample_rate;
      ret->base.note_on                           = &loc_note_on;
      ret->base.set_mod_value                     = &loc_set_mod_value;
      ret->base.prepare_block                     = &loc_prepare_block;
      ret->base.process_replace                   = &loc_process_replace;
      ret->base.plugin_exit                       = &loc_plugin_exit;

#ifdef USE_CYCLE_SINE_TBL
      loc_calc_sine_tbl();
#endif // USE_CYCLE_SINE_TBL
   }

   return &ret->base;
}

#ifndef STFX_SKIP_MAIN_INIT
ST_PLUGIN_APICALL st_plugin_info_t *ST_PLUGIN_API st_plugin_init(unsigned int _pluginIdx) {
   switch(_pluginIdx)
   {
      case 0u:
         return osc_hh_v1_init();
   }
   return NULL;
}
#endif // STFX_SKIP_MAIN_INIT

} // extern "C"
