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.

419 lines
10KB

  1. #include "mscHack.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_mscHack {
  4. #define nCHANNELS 8
  5. #define nENVELOPE_SEGS 5
  6. typedef struct
  7. {
  8. float m, b;
  9. }ENV_SEG;
  10. //-----------------------------------------------------
  11. // Module Definition
  12. //
  13. //-----------------------------------------------------
  14. struct ASAF8 : Module
  15. {
  16. enum ParamIds
  17. {
  18. PARAM_SPEED_IN,
  19. PARAM_SPEED_OUT = PARAM_SPEED_IN + nCHANNELS,
  20. nPARAMS = PARAM_SPEED_OUT + nCHANNELS
  21. };
  22. enum InputIds
  23. {
  24. IN_TRIGS,
  25. IN_AUDIOL = IN_TRIGS + nCHANNELS,
  26. IN_AUDIOR = IN_AUDIOL + nCHANNELS,
  27. nINPUTS = IN_AUDIOR + nCHANNELS
  28. };
  29. enum OutputIds
  30. {
  31. OUT_AUDIOL,
  32. OUT_AUDIOR = OUT_AUDIOL + nCHANNELS,
  33. nOUTPUTS = OUT_AUDIOR + nCHANNELS,
  34. };
  35. enum LightIds
  36. {
  37. nLIGHTS
  38. };
  39. enum FadeStates
  40. {
  41. STATE_OFF,
  42. STATE_FIN,
  43. STATE_ON,
  44. STATE_FOUT
  45. };
  46. CLog lg;
  47. bool m_bInitialized = false;
  48. // triggers
  49. MyLEDButton *m_pTrigButton[ nCHANNELS ] = {};
  50. int m_State[ nCHANNELS ] = {STATE_OFF};
  51. float m_fFade[ nCHANNELS ] = {};
  52. float m_fPos[ nCHANNELS ] = {};
  53. ENV_SEG m_EnvSeg[ nENVELOPE_SEGS ] = {};
  54. Label *m_pTextLabel = NULL;
  55. // Contructor
  56. ASAF8() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){}
  57. //-----------------------------------------------------
  58. // spd_Knob
  59. //-----------------------------------------------------
  60. struct spd_Knob : Knob_Green1_15
  61. {
  62. ASAF8 *mymodule;
  63. int param;
  64. char strVal[ 10 ] = {};
  65. void onChange( EventChange &e ) override
  66. {
  67. mymodule = (ASAF8*)module;
  68. sprintf( strVal, "[%.2fs]", value );
  69. mymodule->m_pTextLabel->text = strVal;
  70. RoundKnob::onChange( e );
  71. }
  72. };
  73. void envSeg_from_points( float x1, float y1, float x2, float y2, ENV_SEG *L );
  74. bool processFade( int ch, bool bfin );
  75. // Overrides
  76. void step() override;
  77. void JsonParams( bool bTo, json_t *root);
  78. json_t* toJson() override;
  79. void fromJson(json_t *rootJ) override;
  80. void onRandomize() override;
  81. void onReset() override;
  82. void onCreate() override;
  83. void onDelete() override;
  84. };
  85. //-----------------------------------------------------
  86. // ASAF8_TrigButton
  87. //-----------------------------------------------------
  88. void ASAF8_TrigButton( void *pClass, int id, bool bOn )
  89. {
  90. //ASAF8 *mymodule;
  91. //mymodule = (ASAF8*)pClass;
  92. /*if( bOn )
  93. mymodule->m_State[ id ] = ASAF8::STATE_FIN;
  94. else
  95. mymodule->m_State[ id ] = ASAF8::STATE_FOUT;*/
  96. }
  97. //-----------------------------------------------------
  98. // Procedure: Widget
  99. //
  100. //-----------------------------------------------------
  101. struct ASAF8_Widget : ModuleWidget {
  102. ASAF8_Widget( ASAF8 *module );
  103. };
  104. ASAF8_Widget::ASAF8_Widget( ASAF8 *module ) : ModuleWidget(module)
  105. {
  106. int x, y;
  107. box.size = Vec( 15*12, 380);
  108. {
  109. SVGPanel *panel = new SVGPanel();
  110. panel->box.size = box.size;
  111. panel->setBackground(SVG::load(assetPlugin(plugin, "res/ASAF8.svg")));
  112. addChild(panel);
  113. }
  114. //module->lg.Open("ASAF8.txt");
  115. module->m_pTextLabel = new Label();
  116. module->m_pTextLabel->box.pos = Vec( 90, 28 );
  117. module->m_pTextLabel->text = "----";
  118. addChild( module->m_pTextLabel );
  119. x = 3;
  120. y = 77;
  121. for( int ch = 0; ch < nCHANNELS; ch++ )
  122. {
  123. // inputs
  124. addInput(Port::create<MyPortInSmall>( Vec( x + 1, y ), Port::INPUT, module, ASAF8::IN_AUDIOL + ch ) );
  125. addInput(Port::create<MyPortInSmall>( Vec( x + 22, y ), Port::INPUT, module, ASAF8::IN_AUDIOR + ch ) );
  126. // trigger input
  127. addInput(Port::create<MyPortInSmall>( Vec( x + 47, y ), Port::INPUT, module, ASAF8::IN_TRIGS + ch ) );
  128. // trigger button
  129. module->m_pTrigButton[ ch ] = new MyLEDButton( x + 68, y - 1, 19, 19, 15.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, ASAF8_TrigButton );
  130. addChild( module->m_pTrigButton[ ch ] );
  131. // speed knobs
  132. addParam(ParamWidget::create<ASAF8::spd_Knob>( Vec( x + 94, y ), module, ASAF8::PARAM_SPEED_IN + ch, 0.05f, 20.0f, 5.0f ) );
  133. addParam(ParamWidget::create<ASAF8::spd_Knob>( Vec( x + 115, y ), module, ASAF8::PARAM_SPEED_OUT + ch, 0.05f, 20.0f, 5.0f ) );
  134. // outputs
  135. addOutput(Port::create<MyPortOutSmall>( Vec( x + 137, y ), Port::OUTPUT, module, ASAF8::OUT_AUDIOL + ch ) );
  136. addOutput(Port::create<MyPortOutSmall>( Vec( x + 158, y ), Port::OUTPUT, module, ASAF8::OUT_AUDIOR + ch ) );
  137. y += 33;
  138. }
  139. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  140. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  141. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  142. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  143. module->envSeg_from_points( 0.0f, 1.0f, 0.2f, 0.975f, &module->m_EnvSeg[ 0 ] );
  144. module->envSeg_from_points( 0.2f, 0.975f, 0.3f, 0.9f, &module->m_EnvSeg[ 1 ] );
  145. module->envSeg_from_points( 0.3f, 0.9f, 0.7f, 0.1f, &module->m_EnvSeg[ 2 ] );
  146. module->envSeg_from_points( 0.7f, 0.1f, 0.8f, 0.075f, &module->m_EnvSeg[ 3 ] );
  147. module->envSeg_from_points( 0.8f, 0.075f, 1.0f, 0.0f, &module->m_EnvSeg[ 4 ] );
  148. module->m_bInitialized = true;
  149. }
  150. //-----------------------------------------------------
  151. // Procedure: JsonParams
  152. //
  153. //-----------------------------------------------------
  154. void ASAF8::JsonParams( bool bTo, json_t *root)
  155. {
  156. JsonDataInt( bTo, "m_State", root, m_State, nCHANNELS );
  157. }
  158. //-----------------------------------------------------
  159. // Procedure: toJson
  160. //
  161. //-----------------------------------------------------
  162. json_t *ASAF8::toJson()
  163. {
  164. json_t *root = json_object();
  165. if( !root )
  166. return NULL;
  167. JsonParams( TOJSON, root );
  168. return root;
  169. }
  170. //-----------------------------------------------------
  171. // Procedure: fromJson
  172. //
  173. //-----------------------------------------------------
  174. void ASAF8::fromJson( json_t *root )
  175. {
  176. JsonParams( FROMJSON, root );
  177. for( int ch = 0; ch < nCHANNELS; ch++ )
  178. {
  179. if( m_State[ ch ] == STATE_OFF || m_State[ ch ] == STATE_FOUT )
  180. {
  181. m_pTrigButton[ ch ]->Set( false );
  182. m_State[ ch ] = STATE_OFF;
  183. m_fFade[ ch ] = 0.0f;
  184. }
  185. else
  186. {
  187. m_pTrigButton[ ch ]->Set( true );
  188. m_State[ ch ] = STATE_ON;
  189. m_fFade[ ch ] = 1.0f;
  190. }
  191. }
  192. }
  193. //-----------------------------------------------------
  194. // Procedure: onCreate
  195. //
  196. //-----------------------------------------------------
  197. void ASAF8::onCreate()
  198. {
  199. }
  200. //-----------------------------------------------------
  201. // Procedure: onDelete
  202. //
  203. //-----------------------------------------------------
  204. void ASAF8::onDelete()
  205. {
  206. }
  207. //-----------------------------------------------------
  208. // Procedure: onReset
  209. //
  210. //-----------------------------------------------------
  211. void ASAF8::onReset()
  212. {
  213. }
  214. //-----------------------------------------------------
  215. // Procedure: onRandomize
  216. //
  217. //-----------------------------------------------------
  218. void ASAF8::onRandomize()
  219. {
  220. }
  221. //-----------------------------------------------------
  222. // Function: envSeg_from_points
  223. //
  224. //-----------------------------------------------------
  225. void ASAF8::envSeg_from_points( float x1, float y1, float x2, float y2, ENV_SEG *L )
  226. {
  227. L->m = (y2 - y1) / (x2 - x1);
  228. L->b = y1 - (L->m * x1);
  229. }
  230. //-----------------------------------------------------
  231. // Procedure: processFade
  232. //
  233. //-----------------------------------------------------
  234. bool ASAF8::processFade( int ch, bool bfin )
  235. {
  236. int i = 0;
  237. float inc;
  238. if( bfin )
  239. inc = 1.0 / ( engineGetSampleRate() * params[ PARAM_SPEED_IN + ch ].value );
  240. else
  241. inc = 1.0 / ( engineGetSampleRate() * params[ PARAM_SPEED_OUT + ch ].value );
  242. if( m_fPos[ ch ] < 0.2f )
  243. i = 0;
  244. else if( m_fPos[ ch ] < 0.3f )
  245. i = 1;
  246. else if( m_fPos[ ch ] < 0.7f )
  247. i = 2;
  248. else if( m_fPos[ ch ] < 0.8f )
  249. i = 3;
  250. else
  251. i = 4;
  252. if( bfin )
  253. m_fFade[ ch ] = 1.0 - ( ( m_fPos[ ch ] * m_EnvSeg[ i ].m ) + m_EnvSeg[ i ].b );
  254. else
  255. m_fFade[ ch ] = ( m_fPos[ ch ] * m_EnvSeg[ i ].m ) + m_EnvSeg[ i ].b;
  256. m_fPos[ ch ] += inc;
  257. // return true means we are finished fade
  258. if( m_fPos[ ch ] >= 1.0f )
  259. return true;
  260. return false;
  261. }
  262. //-----------------------------------------------------
  263. // Procedure: step
  264. //
  265. //-----------------------------------------------------
  266. #define FADE_GATE_LVL (0.01f)
  267. void ASAF8::step()
  268. {
  269. if( !m_bInitialized )
  270. return;
  271. for( int ch = 0; ch < nCHANNELS; ch++ )
  272. {
  273. switch( m_State[ ch ] )
  274. {
  275. case STATE_FOUT:
  276. if( inputs[ IN_TRIGS + ch ].normalize( 0.0f ) >= FADE_GATE_LVL || m_pTrigButton[ ch ]->m_bOn )
  277. {
  278. m_pTrigButton[ ch ]->Set( true );
  279. m_fPos[ ch ] = 1.0f - m_fPos[ ch ];
  280. m_State[ ch ] = STATE_FIN;
  281. break;
  282. }
  283. if( processFade( ch, false ) )
  284. {
  285. m_fFade[ ch ] = 0.0f;
  286. m_State[ ch ] = STATE_OFF;
  287. }
  288. break;
  289. case STATE_OFF:
  290. if( inputs[ IN_TRIGS + ch ].normalize( 0.0f ) >= FADE_GATE_LVL || m_pTrigButton[ ch ]->m_bOn )
  291. {
  292. m_pTrigButton[ ch ]->Set( true );
  293. m_State[ ch ] = STATE_FIN;
  294. m_fPos[ ch ] = 0.0f;
  295. break;
  296. }
  297. m_fFade[ ch ] = 0.0f;
  298. break;
  299. case STATE_FIN:
  300. if( inputs[ IN_TRIGS + ch ].normalize( 1.0f ) < FADE_GATE_LVL || !m_pTrigButton[ ch ]->m_bOn )
  301. {
  302. m_pTrigButton[ ch ]->Set( false );
  303. m_fPos[ ch ] = 1.0f - m_fPos[ ch ];
  304. m_State[ ch ] = STATE_FOUT;
  305. break;
  306. }
  307. if( processFade( ch, true ) )
  308. {
  309. m_fFade[ ch ] = 1.0f;
  310. m_State[ ch ] = STATE_ON;
  311. }
  312. break;
  313. case STATE_ON:
  314. if( inputs[ IN_TRIGS + ch ].normalize( 1.0f ) < FADE_GATE_LVL || !m_pTrigButton[ ch ]->m_bOn )
  315. {
  316. m_pTrigButton[ ch ]->Set( false );
  317. m_State[ ch ] = STATE_FOUT;
  318. m_fPos[ ch ] = 0.0f;
  319. break;
  320. }
  321. m_fFade[ ch ] = 1.0f;
  322. break;
  323. }
  324. if( inputs[ IN_AUDIOL + ch ].active )
  325. outputs[ OUT_AUDIOL + ch ].value = inputs[ IN_AUDIOL + ch ].value * m_fFade[ ch ];
  326. else
  327. outputs[ OUT_AUDIOL + ch ].value = CV_MAX * m_fFade[ ch ];
  328. if( inputs[ IN_AUDIOR + ch ].active )
  329. outputs[ OUT_AUDIOR + ch ].value = inputs[ IN_AUDIOR + ch ].value * m_fFade[ ch ];
  330. else
  331. outputs[ OUT_AUDIOR + ch ].value = CV_MAX * m_fFade[ ch ];
  332. }
  333. }
  334. } // namespace rack_plugin_mscHack
  335. using namespace rack_plugin_mscHack;
  336. RACK_PLUGIN_MODEL_INIT(mscHack, ASAF8) {
  337. Model *modelASAF8 = Model::create<ASAF8, ASAF8_Widget>( "mscHack", "ASAF8", "ASAF-8 Channel Auto Stereo Audio Fader", ATTENUATOR_TAG, CONTROLLER_TAG, UTILITY_TAG, MULTIPLE_TAG );
  338. return modelASAF8;
  339. }