You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

524 lines
15KB

  1. #include "mscHack.hpp"
  2. //#include "mscHack_Controls.hpp"
  3. #include "dsp/digital.hpp"
  4. //#include "CLog.h"
  5. namespace rack_plugin_mscHack {
  6. #define nDELAYS 8
  7. #define nSTEPS 4
  8. #define nBUFFLEN 0x80000
  9. #define MAX_nWAVES 7
  10. typedef struct
  11. {
  12. // track in clk bpm
  13. //SLIDING_AVG_STRUCT Avg;
  14. int tickcount;
  15. float ftickspersec;
  16. float fbpm;
  17. // track sync tick
  18. float fsynclen;
  19. float fsynccount;
  20. bool bClockReset;
  21. }MAIN_SYNC_CLOCK;
  22. typedef struct
  23. {
  24. float lp1[ 2 ] = {}, bp1[ 2 ] = {};
  25. }FILTER_PARAM_STRUCT;
  26. //-----------------------------------------------------
  27. // Module Definition
  28. //
  29. //-----------------------------------------------------
  30. struct StepDelay : Module
  31. {
  32. enum ParamIds
  33. {
  34. PARAM_FILTER_MODE,
  35. PARAM_FILTERF,
  36. PARAM_FILTERQ,
  37. PARAM_LEVEL,
  38. PARAM_PAN = (PARAM_LEVEL + nSTEPS ),
  39. PARAM_FB = (PARAM_PAN + nSTEPS ),
  40. PARAM_DELAY = (PARAM_FB + nSTEPS ),
  41. PARAM_MIX = (PARAM_DELAY + nSTEPS ),
  42. nPARAMS
  43. };
  44. enum InputIds
  45. {
  46. IN_CLOCK,
  47. IN_CLK_RESET,
  48. IN_AUDIOL,
  49. IN_AUDIOR,
  50. IN_FILTER_MOD,
  51. nINPUTS
  52. };
  53. enum OutputIds
  54. {
  55. OUT_AUDIOL,
  56. OUT_AUDIOR,
  57. nOUTPUTS
  58. };
  59. enum FILTER_TYPES
  60. {
  61. FILTER_OFF,
  62. FILTER_LP,
  63. FILTER_HP,
  64. FILTER_BP,
  65. FILTER_NT
  66. };
  67. CLog lg;
  68. bool m_bInitialized = false;
  69. // Contructor
  70. StepDelay() : Module(nPARAMS, nINPUTS, nOUTPUTS, 0){}
  71. // clock
  72. SchmittTrigger m_SchTrigClk;
  73. MAIN_SYNC_CLOCK m_Clock;
  74. // global triggers
  75. SchmittTrigger m_SchTrigGlobalClkReset;
  76. bool m_GlobalClkResetPending = false;
  77. Label *m_pTextLabel[ nSTEPS ] = {};
  78. MyLEDButtonStrip *m_pButtonLenMod[ nSTEPS ] = {};
  79. int m_lenmod[ nSTEPS ] = {0};
  80. FILTER_PARAM_STRUCT m_Filter = {};
  81. float m_fCutoff;
  82. #define L 0
  83. #define R 1
  84. // buffers
  85. float m_fBuffer[ 2 ][ nBUFFLEN ] = {};
  86. int m_BufferInOffset = 0;
  87. int m_BufferOutOffset[ nSTEPS ] = {0};
  88. //-----------------------------------------------------
  89. // MyDelayKnob
  90. //-----------------------------------------------------
  91. struct MyDelayKnob : Knob_Yellow3_20_Snap
  92. {
  93. StepDelay *mymodule;
  94. void onChange( EventChange &e ) override
  95. {
  96. mymodule = (StepDelay*)module;
  97. if( mymodule )
  98. {
  99. mymodule->CalcDelays();
  100. }
  101. RoundKnob::onChange( e );
  102. }
  103. };
  104. // Overrides
  105. void step() override;
  106. void JsonParams( bool bTo, json_t *root);
  107. json_t* toJson() override;
  108. void fromJson(json_t *rootJ) override;
  109. void onRandomize() override;
  110. void onReset() override;
  111. void ChangeFilterCutoff( float cutfreq );
  112. void Filter( float *InL, float *InR );
  113. void CalcDelays( void );
  114. void BuildWaves( void );
  115. float GetWave( int type, float phase );
  116. };
  117. //-----------------------------------------------------
  118. // Procedure: LenModCallback
  119. //-----------------------------------------------------
  120. void LenModCallback( void *pClass, int id, int nbutton, bool bOn )
  121. {
  122. StepDelay *mymodule;
  123. mymodule = (StepDelay*)pClass;
  124. if( mymodule )
  125. {
  126. mymodule->m_lenmod[ id ] = nbutton;
  127. mymodule->CalcDelays();
  128. }
  129. }
  130. //-----------------------------------------------------
  131. // Procedure: Widget
  132. //
  133. //-----------------------------------------------------
  134. struct StepDelay_Widget : ModuleWidget {
  135. StepDelay_Widget( StepDelay *module );
  136. };
  137. StepDelay_Widget::StepDelay_Widget( StepDelay *module ) : ModuleWidget(module)
  138. {
  139. int steps, x, y;
  140. box.size = Vec( 15*14, 380);
  141. {
  142. SVGPanel *panel = new SVGPanel();
  143. panel->box.size = box.size;
  144. panel->setBackground(SVG::load(assetPlugin(plugin, "res/StepDelay.svg")));
  145. addChild(panel);
  146. }
  147. //module->lg.Open("StepDelay.txt");
  148. // Clock Inputs
  149. addInput(Port::create<MyPortInSmall>( Vec( 14, 23 ), Port::INPUT, module, StepDelay::IN_CLOCK ) );
  150. // Audio Inputs
  151. addInput(Port::create<MyPortInSmall>( Vec( 14, 70 ), Port::INPUT, module, StepDelay::IN_AUDIOL ) );
  152. addInput(Port::create<MyPortInSmall>( Vec( 40, 70 ), Port::INPUT, module, StepDelay::IN_AUDIOR ) );
  153. // Audio Outputs
  154. addOutput(Port::create<MyPortOutSmall>( Vec( 14, 109 ), Port::OUTPUT, module, StepDelay::OUT_AUDIOL ) );
  155. addOutput(Port::create<MyPortOutSmall>( Vec( 40, 109 ), Port::OUTPUT, module, StepDelay::OUT_AUDIOR ) );
  156. // Mix
  157. addParam(ParamWidget::create<Knob_Blue2_26>( Vec( 11, 149 ), module, StepDelay::PARAM_MIX, 0.0, 1.0, 0.5 ) );
  158. // Filter knobs
  159. addParam(ParamWidget::create<Knob_Green1_40>( Vec( 93, 58 ), module, StepDelay::PARAM_FILTERF, 0.0, 1.0, 0.0 ) );
  160. addParam(ParamWidget::create<Knob_Purp1_20>( Vec( 144, 77 ), module, StepDelay::PARAM_FILTERQ, 0.0, 1.0, 0.0 ) );
  161. addParam(ParamWidget::create<FilterSelectToggle>( Vec( 139, 57 ), module, StepDelay::PARAM_FILTER_MODE, 0.0, 4.0, 0.0 ) );
  162. addInput(Port::create<MyPortInSmall>( Vec( 104, 103 ), Port::INPUT, module, StepDelay::IN_FILTER_MOD ) );
  163. x = 93;
  164. y = 173;
  165. for( steps = 0; steps < nSTEPS; steps++ )
  166. {
  167. y = 173;
  168. // step knobs
  169. addParam(ParamWidget::create<Knob_Red1_20>( Vec( x , y ), module, StepDelay::PARAM_LEVEL + steps, 0.0, 1.0, 0.5 ) );
  170. y += 28;
  171. addParam(ParamWidget::create<Knob_Blue3_20>( Vec( x , y ), module, StepDelay::PARAM_PAN + steps, -1.0, 1.0, 0.0 ) );
  172. y += 28;
  173. addParam(ParamWidget::create<Knob_Yellow3_20>( Vec( x , y ), module, StepDelay::PARAM_FB + steps, 0.0, 1.0, 0.0 ) );
  174. y += 28;
  175. addParam(ParamWidget::create<StepDelay::MyDelayKnob>( Vec( x , y ), module, StepDelay::PARAM_DELAY + steps, 0.0, (float)(nDELAYS - 1), 0.0 ) );
  176. module->m_pTextLabel[ steps ] = new Label();
  177. module->m_pTextLabel[ steps ]->box.pos = Vec( x - 9, y + 18 );
  178. module->m_pTextLabel[ steps ]->text = "Delay";
  179. //module->m_pTextLabel[ steps ]->
  180. addChild( module->m_pTextLabel[ steps ] );
  181. y += 38;
  182. module->m_pButtonLenMod[ steps ] = new MyLEDButtonStrip( x + 4, y, 12, 12, 2, 10.0, 2, true, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButtonStrip::TYPE_EXCLUSIVE_WOFF, steps, module, LenModCallback );
  183. addChild( module->m_pButtonLenMod[ steps ] );
  184. x += 28;
  185. }
  186. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  187. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  188. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  189. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  190. module->m_Clock.fsynclen = 2.0 * 48.0; // default to 120bpm
  191. module->CalcDelays();
  192. module->m_bInitialized = true;
  193. }
  194. //-----------------------------------------------------
  195. // Procedure: JsonParams
  196. //
  197. //-----------------------------------------------------
  198. void StepDelay::JsonParams( bool bTo, json_t *root)
  199. {
  200. JsonDataInt( bTo, "m_lenmod", root, (int*)m_lenmod, nSTEPS );
  201. }
  202. //-----------------------------------------------------
  203. // Procedure: toJson
  204. //
  205. //-----------------------------------------------------
  206. json_t *StepDelay::toJson()
  207. {
  208. json_t *root = json_object();
  209. if( !root )
  210. return NULL;
  211. JsonParams( TOJSON, root );
  212. return root;
  213. }
  214. //-----------------------------------------------------
  215. // Procedure: fromJson
  216. //
  217. //-----------------------------------------------------
  218. void StepDelay::fromJson( json_t *root )
  219. {
  220. JsonParams( FROMJSON, root );
  221. for( int i = 0; i < nSTEPS; i++ )
  222. {
  223. m_pButtonLenMod[ i ]->Set( m_lenmod[ i ], true );
  224. }
  225. CalcDelays();
  226. }
  227. //-----------------------------------------------------
  228. // Procedure: reset
  229. //
  230. //-----------------------------------------------------
  231. void StepDelay::onReset()
  232. {
  233. }
  234. //-----------------------------------------------------
  235. // Procedure: randomize
  236. //
  237. //-----------------------------------------------------
  238. void StepDelay::onRandomize()
  239. {
  240. }
  241. //-----------------------------------------------------
  242. // Procedure: ChangeFilterCutoff
  243. //
  244. //-----------------------------------------------------
  245. void StepDelay::ChangeFilterCutoff( float cutfreq )
  246. {
  247. float fx, fx2, fx3, fx5, fx7;
  248. // clamp at 1.0 and 20/samplerate
  249. cutfreq = fmax(cutfreq, 20 / engineGetSampleRate());
  250. cutfreq = fmin(cutfreq, 1.0);
  251. // calculate eq rez freq
  252. fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592;
  253. fx2 = fx*fx;
  254. fx3 = fx2*fx;
  255. fx5 = fx3*fx2;
  256. fx7 = fx5*fx2;
  257. m_fCutoff = 2.0 * (fx
  258. - (fx3 * 0.16666666666666666666666666666667)
  259. + (fx5 * 0.0083333333333333333333333333333333)
  260. - (fx7 * 0.0001984126984126984126984126984127));
  261. }
  262. //-----------------------------------------------------
  263. // Procedure: Filter
  264. //
  265. //-----------------------------------------------------
  266. #define MULTI (0.33333333333333333333333333333333f)
  267. void StepDelay::Filter( float *InL, float *InR )
  268. {
  269. FILTER_PARAM_STRUCT *p;
  270. float rez, hp1;
  271. float input[ 2 ], out[ 2 ] = {0}, lowpass, bandpass, highpass;
  272. if( (int)params[ PARAM_FILTER_MODE ].value == 0 )
  273. return;
  274. ChangeFilterCutoff( clamp( params[ PARAM_FILTERF ].value + clamp( inputs[ IN_FILTER_MOD ].normalize( 0.0f ) / CV_MAX, -1.0f, 1.0f ), -1.0f, 1.0f ) );
  275. p = &m_Filter;
  276. rez = 1.0 - params[ PARAM_FILTERQ ].value;
  277. input[ 0 ] = clamp( *InL / AUDIO_MAX, -1.0f, 1.0f );
  278. input[ 1 ] = clamp( *InR / AUDIO_MAX, -1.0f, 1.0f );
  279. // do left and right channels
  280. for( int i = 0; i < 2; i++ )
  281. {
  282. input[ i ] = input[ i ] + 0.000000001;
  283. p->lp1[ i ] = p->lp1[ i ] + m_fCutoff * p->bp1[ i ];
  284. hp1 = input[ i ] - p->lp1[ i ] - rez * p->bp1[ i ];
  285. p->bp1[ i ] = m_fCutoff * hp1 + p->bp1[ i ];
  286. lowpass = p->lp1[ i ];
  287. highpass = hp1;
  288. bandpass = p->bp1[ i ];
  289. p->lp1[ i ] = p->lp1[ i ] + m_fCutoff * p->bp1[ i ];
  290. hp1 = input[ i ] - p->lp1[ i ] - rez * p->bp1[ i ];
  291. p->bp1[ i ] = m_fCutoff * hp1 + p->bp1[ i ];
  292. lowpass = lowpass + p->lp1[ i ];
  293. highpass = highpass + hp1;
  294. bandpass = bandpass + p->bp1[ i ];
  295. input[ i ] = input[ i ] - 0.000000001;
  296. p->lp1[ i ] = p->lp1[ i ] + m_fCutoff * p->bp1[ i ];
  297. hp1 = input[ i ] - p->lp1[ i ] - rez * p->bp1[ i ];
  298. p->bp1[ i ] = m_fCutoff * hp1 + p->bp1[ i ];
  299. lowpass = (lowpass + p->lp1[ i ]) * MULTI;
  300. highpass = (highpass + hp1) * MULTI;
  301. bandpass = (bandpass + p->bp1[ i ]) * MULTI;
  302. switch( (int)params[ PARAM_FILTER_MODE ].value )
  303. {
  304. case FILTER_LP:
  305. out[ i ] = lowpass;
  306. break;
  307. case FILTER_HP:
  308. out[ i ] = highpass;
  309. break;
  310. case FILTER_BP:
  311. out[ i ] = bandpass;
  312. break;
  313. case FILTER_NT:
  314. out[ i ] = lowpass + highpass;
  315. break;
  316. default:
  317. break;
  318. }
  319. }
  320. *InL = out[ 0 ] * AUDIO_MAX;
  321. *InR = out[ 1 ] * AUDIO_MAX;
  322. }
  323. //-----------------------------------------------------
  324. // Procedure: CalcDelays
  325. //
  326. //-----------------------------------------------------
  327. #define BASE_TICK 48
  328. const float fdelaylen[ nDELAYS ] = { 0.0f, 8.0f, 4.0f, 2.0f, 1.0f, 0.5f, 0.25f, 0.125f };
  329. const float delaymod[ 3 ] = { 1.0f, 1.5f, 0.3333f };
  330. const char strDelay[ nDELAYS ][ 8 ] = { {" Off"}, {"2Bar"}, {"Bar"}, {" Half"}, {" 4th"}, {" 8th"}, {" 16th"}, {" 32nd"} };
  331. void StepDelay::CalcDelays( void )
  332. {
  333. int i, delay, delaysum = 0;
  334. for( i = 0; i < nSTEPS; i++ )
  335. {
  336. delay = (int)params[ PARAM_DELAY + i ].value;
  337. if( m_pTextLabel[ i ] )
  338. m_pTextLabel[ i ]->text = strDelay[ delay ];
  339. if( delay )
  340. {
  341. delaysum += (int)( m_Clock.fsynclen * ( fdelaylen[ delay ] * delaymod[ m_lenmod[ i ] ] ) );
  342. m_BufferOutOffset[ i ] = ( m_BufferInOffset - delaysum ) & 0x7FFFF;
  343. }
  344. }
  345. }
  346. //-----------------------------------------------------
  347. // Procedure: step
  348. //
  349. //-----------------------------------------------------
  350. void StepDelay::step()
  351. {
  352. int i;
  353. bool bMono = true;
  354. float delayL, delayR, fFbL = 0.0f, fFbR = 0.0f, inLOrig = 0.0f, inROrig = 0.0f, inL = 0.0f, inR = 0.0f, outL = 0.0f, outR = 0.0f, inPan;
  355. if( !m_bInitialized )
  356. return;
  357. // get audio inputs, Mono if L only
  358. if( inputs[ IN_AUDIOR ].active )
  359. {
  360. // right channel connected, this is not mono
  361. bMono = false;
  362. inR = inputs[ IN_AUDIOR ].value;
  363. }
  364. if( inputs[ IN_AUDIOL ].active )
  365. {
  366. inL = inputs[ IN_AUDIOL ].value;
  367. // mono, make R channel equal left
  368. if( bMono )
  369. inR = inL;
  370. }
  371. inLOrig = inL;
  372. inROrig = inR;
  373. Filter( &inL, &inR );
  374. m_Clock.tickcount++;
  375. // track clock period
  376. if( m_SchTrigClk.process( inputs[ IN_CLOCK ].normalize( 0.0f ) ) )
  377. {
  378. //m_Clock.fsynclen = (float)( engineGetSampleRate() / (float)m_Clock.tickcount ) * 48.0;
  379. m_Clock.fsynclen = m_Clock.tickcount;
  380. CalcDelays();
  381. m_Clock.tickcount = 0;
  382. }
  383. // add delays
  384. for( i = 0; i < nSTEPS; i++ )
  385. {
  386. // add each activated delay
  387. if( params[ PARAM_DELAY + i ].value != 0 )
  388. {
  389. // add delay
  390. delayL = m_fBuffer[ L ][ m_BufferOutOffset[ i ] ] * params[ PARAM_LEVEL + i ].value;
  391. delayR = m_fBuffer[ R ][ m_BufferOutOffset[ i ] ] * params[ PARAM_LEVEL + i ].value;
  392. m_BufferOutOffset[ i ] = ( m_BufferOutOffset[ i ] + 1 ) & 0x7FFFF;
  393. inPan = params[ PARAM_PAN + i ].value;
  394. if( inPan <= 0.0 )
  395. delayR *= ( 1.0 + inPan );
  396. else
  397. delayL *= ( 1.0 - inPan );
  398. outL += delayL;
  399. outR += delayR;
  400. fFbL += delayL * params[ PARAM_FB + i ].value;
  401. fFbR += delayR * params[ PARAM_FB + i ].value;
  402. }
  403. }
  404. // main delay buffer
  405. m_fBuffer[ L ][ m_BufferInOffset ] = inL + fFbL;
  406. m_fBuffer[ R ][ m_BufferInOffset ] = inR + fFbR;
  407. m_BufferInOffset = ( m_BufferInOffset + 1 ) & 0x7FFFF;
  408. outputs[ OUT_AUDIOL ].value = ( outL * params[ PARAM_MIX ].value ) + ( inLOrig * ( 1.0f - params[ PARAM_MIX ].value ) );
  409. outputs[ OUT_AUDIOR ].value = ( outR * params[ PARAM_MIX ].value ) + ( inROrig * ( 1.0f - params[ PARAM_MIX ].value ) );
  410. }
  411. } // namespace rack_plugin_mscHack
  412. using namespace rack_plugin_mscHack;
  413. RACK_PLUGIN_MODEL_INIT(mscHack, StepDelay) {
  414. Model *modelStepDelay = Model::create<StepDelay, StepDelay_Widget>( "mscHack", "StepDelay", "DELAY 4 Step Delay", DELAY_TAG, PANNING_TAG );
  415. return modelStepDelay;
  416. }