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.

674 lines
21KB

  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 nCHANNELS 4
  7. #define MID_INDEX 12
  8. #define CLOCK_DIVS 25
  9. const int multdisplayval[ CLOCK_DIVS ] = { 32, 24, 16, 12, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 16, 24, 32 };
  10. //-----------------------------------------------------
  11. // Module Definition
  12. //
  13. //-----------------------------------------------------
  14. struct MasterClockx4 : Module
  15. {
  16. enum ParamIds
  17. {
  18. PARAM_BPM,
  19. PARAM_MULT,
  20. PARAM_HUMANIZE = PARAM_MULT + nCHANNELS,
  21. nPARAMS
  22. };
  23. enum InputIds
  24. {
  25. INPUT_EXT_SYNC,
  26. INPUT_CHAIN = INPUT_EXT_SYNC + nCHANNELS,
  27. nINPUTS
  28. };
  29. enum OutputIds
  30. {
  31. OUTPUT_CLK,
  32. OUTPUT_TRIG = OUTPUT_CLK + ( nCHANNELS * 4 ),
  33. OUTPUT_CHAIN = OUTPUT_TRIG + ( nCHANNELS * 4 ),
  34. nOUTPUTS
  35. };
  36. bool m_bInitialized = false;
  37. CLog lg;
  38. float m_fBPM = 120;
  39. MyLED7DigitDisplay *m_pDigitDisplayMult[ nCHANNELS ] = {};
  40. MyLED7DigitDisplay *m_pDigitDisplayBPM = NULL;
  41. MyLEDButton *m_pButtonGlobalStop = NULL;
  42. MyLEDButton *m_pButtonGlobalTrig = NULL;
  43. MyLEDButton *m_pButtonStop[ nCHANNELS ] = {};
  44. MyLEDButton *m_pButtonTrig[ nCHANNELS ] = {};
  45. MyLEDButton *m_pButtonTimeX2[ nCHANNELS ] = {};
  46. bool m_bGlobalSync = false;
  47. bool m_bStopState[ nCHANNELS ] = {};
  48. bool m_bGlobalStopState = false;
  49. bool m_bChannelSyncPending[ nCHANNELS ] = {};
  50. bool m_bTimeX2[ nCHANNELS ] = {};
  51. int m_ChannelDivBeatCount[ nCHANNELS ] = {};
  52. float m_fChannelBeatsPers[ nCHANNELS ] = {};
  53. float m_fChannelClockCount[ nCHANNELS ] = {};
  54. int m_ChannelMultSelect[ nCHANNELS ] = {};
  55. float m_fHumanize = 0;
  56. float m_bWasChained = false;
  57. float m_fBeatsPers;
  58. float m_fMainClockCount;
  59. PulseGenerator m_PulseClock[ nCHANNELS ];
  60. PulseGenerator m_PulseSync[ nCHANNELS ];
  61. SchmittTrigger m_SchmittSyncIn[ nCHANNELS ];
  62. ParamWidget *m_pBpmKnob = NULL;
  63. ParamWidget *m_pHumanKnob = NULL;
  64. // Contructor
  65. MasterClockx4() : Module(nPARAMS, nINPUTS, nOUTPUTS){}
  66. //-----------------------------------------------------
  67. // MyHumanize_Knob
  68. //-----------------------------------------------------
  69. struct MyHumanize_Knob : Knob_Yellow2_26
  70. {
  71. MasterClockx4 *mymodule;
  72. void onChange( EventChange &e ) override
  73. {
  74. mymodule = (MasterClockx4*)module;
  75. if( mymodule && !mymodule->inputs[ INPUT_CHAIN ].active )
  76. mymodule->GetNewHumanizeVal();
  77. RoundKnob::onChange( e );
  78. }
  79. };
  80. //-----------------------------------------------------
  81. // MyBPM_Knob
  82. //-----------------------------------------------------
  83. struct MyBPM_Knob : Knob_Yellow2_56
  84. {
  85. MasterClockx4 *mymodule;
  86. void onChange( EventChange &e ) override
  87. {
  88. mymodule = (MasterClockx4*)module;
  89. if( mymodule && !mymodule->inputs[ INPUT_CHAIN ].active )
  90. mymodule->BPMChange( value, false );
  91. RoundKnob::onChange( e );
  92. }
  93. };
  94. //-----------------------------------------------------
  95. // MyMult_Knob
  96. //-----------------------------------------------------
  97. struct MyMult_Knob : Knob_Yellow2_26_Snap
  98. {
  99. MasterClockx4 *mymodule;
  100. int ch, col;
  101. void onChange( EventChange &e ) override
  102. {
  103. mymodule = (MasterClockx4*)module;
  104. if( mymodule )
  105. {
  106. //if( !mymodule->m_bInitialized )
  107. //return;
  108. ch = paramId - MasterClockx4::PARAM_MULT;
  109. //if( ch >= 0 && ch <= 3 )
  110. //{
  111. mymodule->SetDisplayLED( ch, (int)value );
  112. //}
  113. }
  114. RoundKnob::onChange( e );
  115. }
  116. };
  117. // Overrides
  118. void step() override;
  119. void JsonParams( bool bTo, json_t *root);
  120. json_t* toJson() override;
  121. void fromJson(json_t *rootJ) override;
  122. void onReset() override;
  123. void GetNewHumanizeVal( void );
  124. void BPMChange( float fbmp, bool bforce );
  125. void CalcChannelClockRate( int ch );
  126. void SetDisplayLED( int ch, int val );
  127. };
  128. //-----------------------------------------------------
  129. // MyLEDButton_GlobalStop
  130. //-----------------------------------------------------
  131. void MyLEDButton_GlobalStop( void *pClass, int id, bool bOn )
  132. {
  133. MasterClockx4 *mymodule;
  134. mymodule = (MasterClockx4*)pClass;
  135. mymodule->m_bGlobalStopState = bOn;
  136. }
  137. //-----------------------------------------------------
  138. // MyLEDButton_TimeX2
  139. //-----------------------------------------------------
  140. void MyLEDButton_TimeX2( void *pClass, int id, bool bOn )
  141. {
  142. MasterClockx4 *mymodule;
  143. mymodule = (MasterClockx4*)pClass;
  144. mymodule->m_bTimeX2[ id ] = bOn;
  145. mymodule->SetDisplayLED( id, (int)mymodule->params[ MasterClockx4::PARAM_MULT + id ].value );
  146. }
  147. //-----------------------------------------------------
  148. // MyLEDButton_GlobalTrig
  149. //-----------------------------------------------------
  150. void MyLEDButton_GlobalTrig( void *pClass, int id, bool bOn )
  151. {
  152. MasterClockx4 *mymodule;
  153. mymodule = (MasterClockx4*)pClass;
  154. mymodule->m_bGlobalSync = true;
  155. }
  156. //-----------------------------------------------------
  157. // MyLEDButton_ChannelStop
  158. //-----------------------------------------------------
  159. void MyLEDButton_ChannelStop ( void *pClass, int id, bool bOn )
  160. {
  161. MasterClockx4 *mymodule;
  162. mymodule = (MasterClockx4*)pClass;
  163. mymodule->m_bStopState[ id ] = bOn;
  164. }
  165. //-----------------------------------------------------
  166. // MyLEDButton_ChannelSync
  167. //-----------------------------------------------------
  168. void MyLEDButton_ChannelSync( void *pClass, int id, bool bOn )
  169. {
  170. MasterClockx4 *mymodule;
  171. mymodule = (MasterClockx4*)pClass;
  172. mymodule->m_bChannelSyncPending[ id ] = true;
  173. if( mymodule->m_pButtonTrig[ id ] )
  174. mymodule->m_pButtonTrig[ id ]->Set( true );
  175. }
  176. //-----------------------------------------------------
  177. // Procedure: Widget
  178. //
  179. //-----------------------------------------------------
  180. struct MasterClockx4_Widget : ModuleWidget {
  181. MasterClockx4_Widget( MasterClockx4 *module );
  182. };
  183. MasterClockx4_Widget::MasterClockx4_Widget( MasterClockx4 *module ) : ModuleWidget(module)
  184. {
  185. int ch, x, y;
  186. box.size = Vec( 15*18, 380);
  187. {
  188. SVGPanel *panel = new SVGPanel();
  189. panel->box.size = box.size;
  190. panel->setBackground(SVG::load(assetPlugin( plugin, "res/MasterClockx4.svg")));
  191. addChild(panel);
  192. }
  193. //module->lg.Open("MasterClockx4.txt");
  194. // bpm knob
  195. module->m_pBpmKnob = ParamWidget::create<MasterClockx4::MyBPM_Knob>( Vec( 9, 50 ), module, MasterClockx4::PARAM_BPM, 60.0, 220.0, 120.0 );
  196. addParam( module->m_pBpmKnob );
  197. // bpm display
  198. module->m_pDigitDisplayBPM = new MyLED7DigitDisplay( 5, 115, 0.055, DWRGB( 0, 0, 0 ), DWRGB( 0xFF, 0xFF, 0xFF ), MyLED7DigitDisplay::TYPE_FLOAT, 5 );
  199. addChild( module->m_pDigitDisplayBPM );
  200. // global stop switch
  201. module->m_pButtonGlobalStop = new MyLEDButton( 22, 144, 25, 25, 20.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, MyLEDButton_GlobalStop );
  202. addChild( module->m_pButtonGlobalStop );
  203. // global sync button
  204. module->m_pButtonGlobalTrig = new MyLEDButton( 22, 202, 25, 25, 20.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, MyLEDButton_GlobalTrig );
  205. addChild( module->m_pButtonGlobalTrig );
  206. // humanize knob
  207. module->m_pHumanKnob = ParamWidget::create<MasterClockx4::MyHumanize_Knob>( Vec( 22, 235 ), module, MasterClockx4::PARAM_HUMANIZE, 0.0, 1.0, 0.0 );
  208. addParam( module->m_pHumanKnob );
  209. // add chain out
  210. addOutput(Port::create<MyPortOutSmall>( Vec( 30, 345 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_CHAIN ) );
  211. // chain in
  212. addInput(Port::create<MyPortInSmall>( Vec( 30, 13 ), Port::INPUT, module, MasterClockx4::INPUT_CHAIN ) );
  213. x = 91;
  214. y = 39;
  215. for( ch = 0; ch < nCHANNELS; ch++ )
  216. {
  217. // x2
  218. module->m_pButtonTimeX2[ ch ] = new MyLEDButton( x + 2, y + 2, 11, 11, 9.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_SWITCH, ch, module, MyLEDButton_TimeX2 );
  219. addChild( module->m_pButtonTimeX2[ ch ] );
  220. // clock mult knob
  221. addParam(ParamWidget::create<MasterClockx4::MyMult_Knob>( Vec( x + 13, y + 13 ), module, MasterClockx4::PARAM_MULT + ch, 0.0f, (float)(CLOCK_DIVS - 1), (float)(MID_INDEX) ) );
  222. // mult display
  223. module->m_pDigitDisplayMult[ ch ] = new MyLED7DigitDisplay( x + 10, y + 48, 0.07, DWRGB( 0, 0, 0 ), DWRGB( 0xFF, 0xFF, 0xFF ), MyLED7DigitDisplay::TYPE_INT, 2 );
  224. addChild( module->m_pDigitDisplayMult[ ch ] );
  225. // sync triggers
  226. module->m_pButtonTrig[ ch ] = new MyLEDButton( x + 76, y + 4, 19, 19, 15.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, ch, module, MyLEDButton_ChannelSync );
  227. addChild( module->m_pButtonTrig[ ch ] );
  228. addInput(Port::create<MyPortInSmall>( Vec( x + 54, y + 5 ), Port::INPUT, module, MasterClockx4::INPUT_EXT_SYNC + ch ) );
  229. addOutput(Port::create<MyPortOutSmall>( Vec( x + 54, y + 31 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_TRIG + (ch * 4) + 0 ) );
  230. addOutput(Port::create<MyPortOutSmall>( Vec( x + 54, y + 53 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_TRIG + (ch * 4) + 1 ) );
  231. addOutput(Port::create<MyPortOutSmall>( Vec( x + 77, y + 31 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_TRIG + (ch * 4) + 2 ) );
  232. addOutput(Port::create<MyPortOutSmall>( Vec( x + 77, y + 53 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_TRIG + (ch * 4) + 3 ) );
  233. // clock out
  234. module->m_pButtonStop[ ch ] = new MyLEDButton( x + 132, y + 4, 19, 19, 15.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, MyLEDButton_ChannelStop );
  235. addChild( module->m_pButtonStop[ ch ] );
  236. addOutput(Port::create<MyPortOutSmall>( Vec( x + 107, y + 31 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_CLK + (ch * 4) + 0 ) );
  237. addOutput(Port::create<MyPortOutSmall>( Vec( x + 107, y + 53 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_CLK + (ch * 4) + 1 ) );
  238. addOutput(Port::create<MyPortOutSmall>( Vec( x + 130, y + 31 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_CLK + (ch * 4) + 2 ) );
  239. addOutput(Port::create<MyPortOutSmall>( Vec( x + 130, y + 53 ), Port::OUTPUT, module, MasterClockx4::OUTPUT_CLK + (ch * 4) + 3 ) );
  240. y += 80;
  241. }
  242. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  243. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  244. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  245. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  246. module->m_bInitialized = true;
  247. module->onReset();
  248. }
  249. //-----------------------------------------------------
  250. // Procedure: JsonParams
  251. //
  252. //-----------------------------------------------------
  253. void MasterClockx4::JsonParams( bool bTo, json_t *root)
  254. {
  255. JsonDataBool( bTo, "m_bGlobalStopState", root, &m_bGlobalStopState, 1 );
  256. JsonDataBool( bTo, "m_bStopState", root, m_bStopState, nCHANNELS );
  257. JsonDataBool( bTo, "m_bTimeX2", root, m_bTimeX2, nCHANNELS );
  258. JsonDataInt ( bTo, "m_ChannelMultSelect", root, m_ChannelMultSelect, nCHANNELS );
  259. }
  260. //-----------------------------------------------------
  261. // Procedure:
  262. //
  263. //-----------------------------------------------------
  264. json_t *MasterClockx4::toJson()
  265. {
  266. json_t *root = json_object();
  267. if( !root )
  268. return NULL;
  269. JsonParams( TOJSON, root );
  270. return root;
  271. }
  272. //-----------------------------------------------------
  273. // Procedure: fromJson
  274. //
  275. //-----------------------------------------------------
  276. void MasterClockx4::fromJson(json_t *root)
  277. {
  278. JsonParams( FROMJSON, root );
  279. m_pButtonGlobalStop->Set( m_bGlobalStopState );
  280. for( int ch = 0; ch < nCHANNELS; ch++ )
  281. {
  282. m_pButtonStop[ ch ]->Set( m_bStopState[ ch ] );
  283. m_pButtonTimeX2[ ch ]->Set( m_bTimeX2[ ch ] );
  284. //lg.f( "value = %d\n", (int)params[ PARAM_MULT + ch ].value );
  285. SetDisplayLED( ch, m_ChannelMultSelect[ ch ] );
  286. }
  287. m_fMainClockCount = 0;
  288. BPMChange( params[ PARAM_BPM ].value, true );
  289. if( m_pDigitDisplayBPM )
  290. m_pDigitDisplayBPM->SetFloat( m_fBPM );
  291. }
  292. //-----------------------------------------------------
  293. // Procedure: reset
  294. //
  295. //-----------------------------------------------------
  296. void MasterClockx4::onReset()
  297. {
  298. if( !m_bInitialized )
  299. return;
  300. m_fBPM = 120;
  301. if( m_pDigitDisplayBPM )
  302. m_pDigitDisplayBPM->SetFloat( m_fBPM );
  303. m_bGlobalStopState = false;
  304. m_pButtonGlobalStop->Set( m_bGlobalStopState );
  305. for( int ch = 0; ch < nCHANNELS; ch++ )
  306. {
  307. m_bTimeX2[ ch ] = false;
  308. m_bStopState[ ch ] = false;
  309. m_pButtonStop[ ch ]->Set( false );
  310. m_pButtonTimeX2[ ch ]->Set( false );
  311. SetDisplayLED( ch, MID_INDEX );
  312. }
  313. BPMChange( m_fBPM, true );
  314. }
  315. //-----------------------------------------------------
  316. // Procedure: SetDisplayLED
  317. //
  318. //-----------------------------------------------------
  319. void MasterClockx4::SetDisplayLED( int ch, int val )
  320. {
  321. int col, mult = 1;
  322. if( !m_bInitialized )
  323. return;
  324. if( m_bTimeX2[ ch ] )
  325. mult = 2;
  326. if( val < MID_INDEX )
  327. {
  328. col = DWRGB( 0xFF, 0, 0 );
  329. }
  330. else if( val > MID_INDEX )
  331. {
  332. col = DWRGB( 0, 0xFF, 0xFF );
  333. }
  334. else
  335. {
  336. mult = 1;
  337. col = DWRGB( 0xFF, 0xFF, 0xFF );
  338. }
  339. if( m_pDigitDisplayMult[ ch ] )
  340. {
  341. m_ChannelMultSelect[ ch ] = val;
  342. m_pDigitDisplayMult[ ch ]->SetLEDCol( col );
  343. m_pDigitDisplayMult[ ch ]->SetInt( multdisplayval[ val ] * mult );
  344. }
  345. CalcChannelClockRate( ch );
  346. }
  347. //-----------------------------------------------------
  348. // Procedure: GetNewHumanizeVal
  349. //
  350. //-----------------------------------------------------
  351. void MasterClockx4::GetNewHumanizeVal( void )
  352. {
  353. m_fHumanize = randomUniform() * engineGetSampleRate() * 0.1 * params[ PARAM_HUMANIZE ].value;
  354. if( randomUniform() > 0.5 )
  355. m_fHumanize *= -1;
  356. }
  357. //-----------------------------------------------------
  358. // Procedure: BMPChange
  359. //
  360. //-----------------------------------------------------
  361. void MasterClockx4::BPMChange( float fbpm, bool bforce )
  362. {
  363. // don't change if it is already the same
  364. if( !bforce && ( (int)(fbpm * 1000.0f ) == (int)(m_fBPM * 1000.0f ) ) )
  365. return;
  366. m_fBPM = fbpm;
  367. m_fBeatsPers = fbpm / 60.0;
  368. if( m_pDigitDisplayBPM )
  369. m_pDigitDisplayBPM->SetFloat( m_fBPM );
  370. for( int i = 0; i < nCHANNELS; i++ )
  371. CalcChannelClockRate( i );
  372. }
  373. //-----------------------------------------------------
  374. // Procedure: CalcChannelClockRate
  375. //
  376. //-----------------------------------------------------
  377. void MasterClockx4::CalcChannelClockRate( int ch )
  378. {
  379. int mult = 1;
  380. if( m_bTimeX2[ ch ] )
  381. mult = 2;
  382. // for beat division just keep a count of beats
  383. if( m_ChannelMultSelect[ ch ] == MID_INDEX )
  384. m_ChannelDivBeatCount[ ch ] = 1;
  385. else if( m_ChannelMultSelect[ ch ] < MID_INDEX )
  386. m_ChannelDivBeatCount[ ch ] = multdisplayval[ m_ChannelMultSelect[ ch ] ] * mult;
  387. else
  388. m_fChannelBeatsPers[ ch ] = m_fBeatsPers * (float)( multdisplayval[ m_ChannelMultSelect[ ch ] ] * mult );
  389. }
  390. //-----------------------------------------------------
  391. // Procedure: step
  392. //
  393. //-----------------------------------------------------
  394. void MasterClockx4::step()
  395. {
  396. int ch, mult = 1;
  397. unsigned int ival;
  398. float fSyncPulseOut, fClkPulseOut;
  399. bool bMainClockTrig = false, bChannelClockTrig;
  400. if( !m_bInitialized )
  401. return;
  402. // use the input chain trigger for our clock
  403. if( inputs[ INPUT_CHAIN ].active )
  404. {
  405. if( !m_bWasChained )
  406. {
  407. m_pHumanKnob->visible = false;
  408. m_pBpmKnob->visible = false;
  409. }
  410. m_bWasChained = true;
  411. // value of less than zero is a trig
  412. if( inputs[ INPUT_CHAIN ].value < 8.0 )
  413. {
  414. ival = (unsigned int)inputs[ INPUT_CHAIN ].value;
  415. bMainClockTrig = ( ival & 1 );
  416. m_bGlobalSync = ( ival & 2 );
  417. m_bGlobalStopState = ( ival & 4 );
  418. m_pButtonGlobalStop->Set( m_bGlobalStopState );
  419. }
  420. // values greater than zero are the bpm
  421. else
  422. {
  423. BPMChange( inputs[ INPUT_CHAIN ].value, false );
  424. }
  425. }
  426. else
  427. {
  428. // go back to our bpm if chain removed
  429. if( m_bWasChained )
  430. {
  431. m_pHumanKnob->visible = true;
  432. m_pBpmKnob->visible = true;
  433. m_bWasChained = false;
  434. BPMChange( params[ PARAM_BPM ].value, false );
  435. m_pButtonGlobalStop->Set( m_bGlobalStopState );
  436. }
  437. // keep track of main bpm
  438. m_fMainClockCount += m_fBeatsPers;
  439. //if( ( m_fMainClockCount + m_fHumanize ) >= engineGetSampleRate() )
  440. if( m_fMainClockCount >= (engineGetSampleRate()-1) )
  441. {
  442. //m_fMainClockCount = ( m_fMainClockCount + m_fHumanize ) - engineGetSampleRate();
  443. m_fMainClockCount = m_fMainClockCount - (engineGetSampleRate()-1);
  444. GetNewHumanizeVal();
  445. bMainClockTrig = true;
  446. }
  447. }
  448. // send chain
  449. if( outputs[ OUTPUT_CHAIN ].active )
  450. {
  451. ival = 0;
  452. if( bMainClockTrig )
  453. ival |= 1;
  454. if( m_bGlobalSync )
  455. ival |= 2;
  456. if( m_bGlobalStopState )
  457. ival |= 4;
  458. if( ival )
  459. outputs[ OUTPUT_CHAIN ].value = (float)ival;
  460. else
  461. outputs[ OUTPUT_CHAIN ].value = m_fBPM;
  462. }
  463. for( ch = 0; ch < nCHANNELS; ch++ )
  464. {
  465. bChannelClockTrig = false;
  466. // sync triggers
  467. if( m_bGlobalSync || m_SchmittSyncIn[ ch ].process( inputs[ INPUT_EXT_SYNC + ch ].value ) )
  468. {
  469. if( m_pButtonTrig[ ch ] )
  470. m_pButtonTrig[ ch ]->Set( true );
  471. m_bChannelSyncPending[ ch ] = true;
  472. }
  473. // sync all triggers to main clock pulse
  474. if( bMainClockTrig )
  475. {
  476. if( m_bChannelSyncPending[ ch ] )
  477. {
  478. if( m_pButtonTrig[ ch ] )
  479. m_pButtonTrig[ ch ]->Set( true );
  480. m_bChannelSyncPending[ ch ] = false;
  481. m_PulseSync[ ch ].trigger(1e-3);
  482. m_ChannelDivBeatCount[ ch ] = 0;
  483. m_fChannelClockCount[ ch ] = 0;
  484. bChannelClockTrig = true;
  485. }
  486. else
  487. {
  488. // divisions of clock will count beats
  489. if( m_ChannelMultSelect[ ch ] < MID_INDEX )
  490. {
  491. if( m_bTimeX2[ ch ] )
  492. mult = 2;
  493. if( ++m_ChannelDivBeatCount[ ch ] >= ( multdisplayval[ m_ChannelMultSelect[ ch ] ] * mult ) )
  494. {
  495. m_ChannelDivBeatCount[ ch ] = 0;
  496. bChannelClockTrig = true;
  497. }
  498. }
  499. // multiples of clock will sync with every beat
  500. else
  501. {
  502. m_fChannelClockCount[ ch ] = 0;
  503. bChannelClockTrig = true;
  504. }
  505. }
  506. }
  507. // do multiple clocks
  508. else if( m_ChannelMultSelect[ ch ] > MID_INDEX )
  509. {
  510. m_fChannelClockCount[ ch ] += m_fChannelBeatsPers[ ch ];
  511. if( m_fChannelClockCount[ ch ] >= engineGetSampleRate() )
  512. {
  513. m_fChannelClockCount[ ch ] = m_fChannelClockCount[ ch ] - engineGetSampleRate();
  514. bChannelClockTrig = true;
  515. }
  516. }
  517. if( bChannelClockTrig )
  518. m_PulseClock[ ch ].trigger( 0.050f );
  519. // syncs
  520. fSyncPulseOut = m_PulseSync[ ch ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0;
  521. outputs[ OUTPUT_TRIG + (ch * 4) + 0 ].value = fSyncPulseOut;
  522. outputs[ OUTPUT_TRIG + (ch * 4) + 1 ].value = fSyncPulseOut;
  523. outputs[ OUTPUT_TRIG + (ch * 4) + 2 ].value = fSyncPulseOut;
  524. outputs[ OUTPUT_TRIG + (ch * 4) + 3 ].value = fSyncPulseOut;
  525. // clocks
  526. fClkPulseOut = m_PulseClock[ ch ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0;
  527. if( !m_bGlobalStopState && !m_bStopState[ ch ] )
  528. {
  529. outputs[ OUTPUT_CLK + (ch * 4) + 0 ].value = fClkPulseOut;
  530. outputs[ OUTPUT_CLK + (ch * 4) + 1 ].value = fClkPulseOut;
  531. outputs[ OUTPUT_CLK + (ch * 4) + 2 ].value = fClkPulseOut;
  532. outputs[ OUTPUT_CLK + (ch * 4) + 3 ].value = fClkPulseOut;
  533. }
  534. }
  535. m_bGlobalSync = false;
  536. }
  537. } // namespace rack_plugin_mscHack
  538. using namespace rack_plugin_mscHack;
  539. RACK_PLUGIN_MODEL_INIT(mscHack, MasterClockx4) {
  540. Model *modelMasterClockx4 = Model::create<MasterClockx4, MasterClockx4_Widget>( "mscHack", "MasterClockx4", "Master CLOCK x 4", CLOCK_TAG, QUAD_TAG );
  541. return modelMasterClockx4;
  542. }