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.

599 lines
18KB

  1. #include "mscHack.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_mscHack {
  4. //-----------------------------------------------------
  5. // Module Definition
  6. //
  7. //-----------------------------------------------------
  8. struct OSC_WaveMorph_3 : Module
  9. {
  10. #define nCHANNELS 3
  11. enum ParamIds
  12. {
  13. PARAM_BAND,
  14. PARAM_LEVEL,
  15. PARAM_CUTOFF,
  16. PARAM_RES,
  17. PARAM_FILTER_MODE,
  18. nPARAMS
  19. };
  20. enum InputIds
  21. {
  22. INPUT_VOCT,
  23. INPUT_MORPHCV,
  24. IN_FILTER,
  25. IN_REZ,
  26. IN_LEVEL,
  27. IN_WAVE_CHANGE,
  28. nINPUTS
  29. };
  30. enum OutputIds
  31. {
  32. OUTPUT_AUDIO,
  33. nOUTPUTS
  34. };
  35. enum LightIds
  36. {
  37. nLIGHTS
  38. };
  39. bool m_bInitialized = false;
  40. CLog lg;
  41. // Contructor
  42. OSC_WaveMorph_3() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){}
  43. int m_CurrentChannel = 0;
  44. int m_GraphData[ MAX_ENVELOPE_CHANNELS ][ ENVELOPE_HANDLES ] = {};
  45. int m_waveSet = 0;
  46. bool m_bCpy = false;
  47. bool m_bSolo = false;
  48. SchmittTrigger m_SchmittChangeWave;
  49. Widget_EnvelopeEdit *m_pEnvelope = NULL;
  50. MyLEDButtonStrip *m_pButtonChSelect = NULL;
  51. MyLEDButton *m_pButtonWaveSetBck = NULL;
  52. MyLEDButton *m_pButtonWaveSetFwd = NULL;
  53. MyLEDButton *m_pButtonDraw = NULL;
  54. MyLEDButton *m_pButtonCopy = NULL;
  55. MyLEDButton *m_pButtonRand = NULL;
  56. MyLEDButton *m_pButtonInvert = NULL;
  57. MyLEDButton *m_pButtonSolo = NULL;
  58. Label *m_pTextLabel = NULL;
  59. // filter
  60. enum FILTER_TYPES
  61. {
  62. FILTER_OFF,
  63. FILTER_LP,
  64. FILTER_HP,
  65. FILTER_BP,
  66. FILTER_NT
  67. };
  68. int filtertype;
  69. float q, f;
  70. float lp1 = 0, bp1 = 0;
  71. //-----------------------------------------------------
  72. // Band_Knob
  73. //-----------------------------------------------------
  74. struct Band_Knob : Knob_Yellow2_26
  75. {
  76. OSC_WaveMorph_3 *mymodule;
  77. int param;
  78. void onChange( EventChange &e ) override
  79. {
  80. mymodule = (OSC_WaveMorph_3*)module;
  81. if( mymodule )
  82. mymodule->m_pEnvelope->m_fband = value;
  83. RoundKnob::onChange( e );
  84. }
  85. };
  86. void ChangeChannel( int ch );
  87. void ChangeFilterCutoff( float cutfreq );
  88. void Filter( float *In );
  89. // Overrides
  90. void step() override;
  91. void JsonParams( bool bTo, json_t *root);
  92. json_t* toJson() override;
  93. void fromJson(json_t *rootJ) override;
  94. void onRandomize() override;
  95. void onReset() override;
  96. void onCreate() override;
  97. void onDelete() override;
  98. };
  99. //-----------------------------------------------------
  100. // Seq_Triad2_Pause
  101. //-----------------------------------------------------
  102. void OSC_WaveMorph_3_EnvelopeEditCALLBACK ( void *pClass, float val )
  103. {
  104. char strVal[ 10 ] = {};
  105. OSC_WaveMorph_3 *mymodule;
  106. mymodule = (OSC_WaveMorph_3*)pClass;
  107. sprintf( strVal, "[%.3fV]", val );
  108. mymodule->m_pTextLabel->text = strVal;
  109. }
  110. //-----------------------------------------------------
  111. // OSC_WaveMorph_3_DrawMode
  112. //-----------------------------------------------------
  113. void OSC_WaveMorph_3_DrawMode( void *pClass, int id, bool bOn )
  114. {
  115. OSC_WaveMorph_3 *mymodule;
  116. mymodule = (OSC_WaveMorph_3*)pClass;
  117. mymodule->m_pEnvelope->m_bDraw = bOn;
  118. }
  119. //-----------------------------------------------------
  120. // OSC_WaveMorph_3_Solo
  121. //-----------------------------------------------------
  122. void OSC_WaveMorph_3_Solo( void *pClass, int id, bool bOn )
  123. {
  124. OSC_WaveMorph_3 *mymodule;
  125. mymodule = (OSC_WaveMorph_3*)pClass;
  126. mymodule->m_bSolo = bOn;
  127. }
  128. //-----------------------------------------------------
  129. // Procedure: OSC_WaveMorph_3_ChSelect
  130. //-----------------------------------------------------
  131. void OSC_WaveMorph_3_ChSelect( void *pClass, int id, int nbutton, bool bOn )
  132. {
  133. OSC_WaveMorph_3 *mymodule;
  134. mymodule = (OSC_WaveMorph_3*)pClass;
  135. mymodule->ChangeChannel( nbutton );
  136. }
  137. //-----------------------------------------------------
  138. // Procedure: OSC_WaveMorph_3_WaveSet
  139. //-----------------------------------------------------
  140. void OSC_WaveMorph_3_WaveSet( void *pClass, int id, bool bOn )
  141. {
  142. OSC_WaveMorph_3 *mymodule;
  143. mymodule = (OSC_WaveMorph_3*)pClass;
  144. if( id == 0 )
  145. {
  146. if( ++mymodule->m_waveSet >= EnvelopeData::nPRESETS )
  147. mymodule->m_waveSet = 0;
  148. }
  149. else
  150. {
  151. if( --mymodule->m_waveSet < 0 )
  152. mymodule->m_waveSet = EnvelopeData::nPRESETS - 1;
  153. }
  154. mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].Preset( mymodule->m_waveSet );
  155. }
  156. //-----------------------------------------------------
  157. // Procedure: OSC_WaveMorph_3_WaveInvert
  158. //-----------------------------------------------------
  159. void OSC_WaveMorph_3_WaveInvert( void *pClass, int id, bool bOn )
  160. {
  161. int i;
  162. OSC_WaveMorph_3 *mymodule;
  163. mymodule = (OSC_WaveMorph_3*)pClass;
  164. for( i = 0; i < ENVELOPE_HANDLES; i++ )
  165. mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, 1.0f - mymodule->m_pEnvelope->m_EnvData[ mymodule->m_CurrentChannel ].m_HandleVal[ i ] );
  166. }
  167. //-----------------------------------------------------
  168. // Procedure: OSC_WaveMorph_3_WaveRand
  169. //-----------------------------------------------------
  170. void OSC_WaveMorph_3_WaveRand( void *pClass, int id, bool bOn )
  171. {
  172. int i;
  173. OSC_WaveMorph_3 *mymodule;
  174. mymodule = (OSC_WaveMorph_3*)pClass;
  175. for( i = 0; i < ENVELOPE_HANDLES; i++ )
  176. mymodule->m_pEnvelope->setVal( mymodule->m_CurrentChannel, i, randomUniform() );
  177. }
  178. //-----------------------------------------------------
  179. // Procedure: OSC_WaveMorph_3_WaveCopy
  180. //-----------------------------------------------------
  181. void OSC_WaveMorph_3_WaveCopy( void *pClass, int id, bool bOn )
  182. {
  183. OSC_WaveMorph_3 *mymodule;
  184. mymodule = (OSC_WaveMorph_3*)pClass;
  185. mymodule->m_bCpy = bOn;
  186. }
  187. //-----------------------------------------------------
  188. // Procedure: Widget
  189. //
  190. //-----------------------------------------------------
  191. struct OSC_WaveMorph_3_Widget : ModuleWidget {
  192. OSC_WaveMorph_3_Widget( OSC_WaveMorph_3 *module );
  193. };
  194. OSC_WaveMorph_3_Widget::OSC_WaveMorph_3_Widget( OSC_WaveMorph_3 *module ) : ModuleWidget(module)
  195. {
  196. box.size = Vec( 15*16, 380);
  197. {
  198. SVGPanel *panel = new SVGPanel();
  199. panel->box.size = box.size;
  200. panel->setBackground(SVG::load(assetPlugin(plugin, "res/OSC_WaveMorph_3.svg")));
  201. addChild(panel);
  202. }
  203. //module->lg.Open("OSC_WaveMorph_3.txt");
  204. // input V/OCT
  205. addInput(Port::create<MyPortInSmall>( Vec( 14, 20 ), Port::INPUT, module, OSC_WaveMorph_3::INPUT_VOCT ) );
  206. // input morph cv
  207. addInput(Port::create<MyPortInSmall>( Vec( 14, 311 ), Port::INPUT, module, OSC_WaveMorph_3::INPUT_MORPHCV ) );
  208. // invert
  209. module->m_pButtonInvert = new MyLEDButton( 88, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveInvert );
  210. addChild( module->m_pButtonInvert );
  211. // envelope editor
  212. module->m_pEnvelope = new Widget_EnvelopeEdit( 16, 47, 208, 96, 5, module, OSC_WaveMorph_3_EnvelopeEditCALLBACK, nCHANNELS );
  213. addChild( module->m_pEnvelope );
  214. module->m_pEnvelope->m_EnvData[ 0 ].m_Range = EnvelopeData::RANGE_Audio;
  215. module->m_pEnvelope->m_EnvData[ 1 ].m_Range = EnvelopeData::RANGE_Audio;
  216. module->m_pEnvelope->m_EnvData[ 2 ].m_Range = EnvelopeData::RANGE_Audio;
  217. // solo button
  218. module->m_pButtonSolo = new MyLEDButton( 158, 146, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_Solo );
  219. addChild( module->m_pButtonSolo );
  220. // wave change (when soloing) cv input
  221. addInput(Port::create<MyPortInSmall>( Vec( 131, 144 ), Port::INPUT, module, OSC_WaveMorph_3::IN_WAVE_CHANGE ) );
  222. // envelope select buttons
  223. module->m_pButtonChSelect = new MyLEDButtonStrip( 183, 146, 11, 11, 3, 8.0, nCHANNELS, false, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, 0, module, OSC_WaveMorph_3_ChSelect );
  224. addChild( module->m_pButtonChSelect );
  225. module->m_pTextLabel = new Label();
  226. module->m_pTextLabel->box.pos = Vec( 150, 4 );
  227. module->m_pTextLabel->text = "----";
  228. addChild( module->m_pTextLabel );
  229. // wave set buttons
  230. module->m_pButtonWaveSetBck = new MyLEDButton( 122, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveSet );
  231. addChild( module->m_pButtonWaveSetBck );
  232. module->m_pButtonWaveSetFwd = new MyLEDButton( 134, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 1, module, OSC_WaveMorph_3_WaveSet );
  233. addChild( module->m_pButtonWaveSetFwd );
  234. // random
  235. module->m_pButtonRand = new MyLEDButton( 163, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_MOMENTARY, 0, module, OSC_WaveMorph_3_WaveRand );
  236. addChild( module->m_pButtonRand );
  237. // copy
  238. module->m_pButtonCopy = new MyLEDButton( 188, 31, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_WaveCopy );
  239. addChild( module->m_pButtonCopy );
  240. // draw mode
  241. module->m_pButtonDraw = new MyLEDButton( 17, 145, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 128, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, OSC_WaveMorph_3_DrawMode );
  242. addChild( module->m_pButtonDraw );
  243. // band knob
  244. addParam(ParamWidget::create<OSC_WaveMorph_3::Band_Knob>( Vec( 60 , 145 ), module, OSC_WaveMorph_3::PARAM_BAND, 0.0, 0.8, 0.333 ) );
  245. // filter
  246. addParam(ParamWidget::create<Knob_Green1_40>( Vec( 30, 200 ), module, OSC_WaveMorph_3::PARAM_CUTOFF, 0.0, 0.1, 0.0 ) );
  247. addParam(ParamWidget::create<FilterSelectToggle>( Vec( 73, 200 ), module, OSC_WaveMorph_3::PARAM_FILTER_MODE, 0.0, 4.0, 0.0 ) );
  248. addParam(ParamWidget::create<Knob_Purp1_20>( Vec( 76, 219 ), module, OSC_WaveMorph_3::PARAM_RES, 0.0, 1.0, 0.0 ) );
  249. // in cvs
  250. addInput(Port::create<MyPortInSmall>( Vec( 41, 244 ), Port::INPUT, module, OSC_WaveMorph_3::IN_FILTER ) );
  251. addInput(Port::create<MyPortInSmall>( Vec( 77, 244 ), Port::INPUT, module, OSC_WaveMorph_3::IN_REZ ) );
  252. addInput(Port::create<MyPortInSmall>( Vec( 162, 265 ), Port::INPUT, module, OSC_WaveMorph_3::IN_LEVEL ) );
  253. // level knob
  254. addParam(ParamWidget::create<Knob_Blue2_56>( Vec( 143 , 200 ), module, OSC_WaveMorph_3::PARAM_LEVEL, 0.0, 1.0, 0.0 ) );
  255. // audio out
  256. addOutput(Port::create<MyPortOutSmall>( Vec( 203, 218 ), Port::OUTPUT, module, OSC_WaveMorph_3::OUTPUT_AUDIO ) );
  257. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  258. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  259. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  260. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  261. module->m_bInitialized = true;
  262. }
  263. //-----------------------------------------------------
  264. // Procedure: JsonParams
  265. //
  266. //-----------------------------------------------------
  267. void OSC_WaveMorph_3::JsonParams( bool bTo, json_t *root)
  268. {
  269. JsonDataInt( bTo, "m_GraphData", root, (int*)m_GraphData, nCHANNELS * ENVELOPE_HANDLES );
  270. JsonDataBool( bTo, "m_bSolo", root, &m_bSolo, 1 );
  271. }
  272. //-----------------------------------------------------
  273. // Procedure: toJson
  274. //
  275. //-----------------------------------------------------
  276. json_t *OSC_WaveMorph_3::toJson()
  277. {
  278. json_t *root = json_object();
  279. if( !root )
  280. return NULL;
  281. m_pEnvelope->getDataAll( (int*)m_GraphData );
  282. JsonParams( TOJSON, root );
  283. return root;
  284. }
  285. //-----------------------------------------------------
  286. // Procedure: fromJson
  287. //
  288. //-----------------------------------------------------
  289. void OSC_WaveMorph_3::fromJson( json_t *root )
  290. {
  291. JsonParams( FROMJSON, root );
  292. m_pEnvelope->setDataAll( (int*)m_GraphData );
  293. m_pButtonSolo->Set( m_bSolo );
  294. ChangeChannel( 0 );
  295. }
  296. //-----------------------------------------------------
  297. // Procedure: onCreate
  298. //
  299. //-----------------------------------------------------
  300. void OSC_WaveMorph_3::onCreate()
  301. {
  302. }
  303. //-----------------------------------------------------
  304. // Procedure: onDelete
  305. //
  306. //-----------------------------------------------------
  307. void OSC_WaveMorph_3::onDelete()
  308. {
  309. }
  310. //-----------------------------------------------------
  311. // Procedure: onReset
  312. //
  313. //-----------------------------------------------------
  314. void OSC_WaveMorph_3::onReset()
  315. {
  316. memset( m_GraphData, 0, sizeof( m_GraphData ) );
  317. m_pEnvelope->setDataAll( (int*)m_GraphData );
  318. ChangeChannel( 0 );
  319. }
  320. //-----------------------------------------------------
  321. // Procedure: onRandomize
  322. //
  323. //-----------------------------------------------------
  324. void OSC_WaveMorph_3::onRandomize()
  325. {
  326. int ch, i;
  327. for( ch = 0; ch < nCHANNELS; ch++ )
  328. {
  329. for( i = 0; i < ENVELOPE_HANDLES; i++ )
  330. m_pEnvelope->setVal( ch, i, randomUniform() );
  331. }
  332. }
  333. //-----------------------------------------------------
  334. // Procedure: onRandomize
  335. //
  336. //-----------------------------------------------------
  337. void OSC_WaveMorph_3::ChangeChannel( int ch )
  338. {
  339. int i;
  340. if( ch < 0 || ch >= nCHANNELS )
  341. return;
  342. if( m_bCpy )
  343. {
  344. m_bCpy = false;
  345. m_pButtonCopy->Set( false );
  346. for( i = 0; i < ENVELOPE_HANDLES; i++ )
  347. {
  348. m_pEnvelope->setVal( ch, i, m_pEnvelope->m_EnvData[ m_CurrentChannel ].m_HandleVal[ i ] );
  349. }
  350. }
  351. m_CurrentChannel = ch;
  352. m_pButtonChSelect->Set( ch, true );
  353. m_pEnvelope->setView( ch );
  354. }
  355. //-----------------------------------------------------
  356. // Procedure: ChangeFilterCutoff
  357. //
  358. //-----------------------------------------------------
  359. void OSC_WaveMorph_3::ChangeFilterCutoff( float cutfreq )
  360. {
  361. float fx, fx2, fx3, fx5, fx7;
  362. // clamp at 1.0 and 20/samplerate
  363. cutfreq = fmax(cutfreq, 20 / engineGetSampleRate());
  364. cutfreq = fmin(cutfreq, 1.0);
  365. // calculate eq rez freq
  366. fx = 3.141592 * (cutfreq * 0.026315789473684210526315789473684) * 2 * 3.141592;
  367. fx2 = fx*fx;
  368. fx3 = fx2*fx;
  369. fx5 = fx3*fx2;
  370. fx7 = fx5*fx2;
  371. f = 2.0 * (fx
  372. - (fx3 * 0.16666666666666666666666666666667)
  373. + (fx5 * 0.0083333333333333333333333333333333)
  374. - (fx7 * 0.0001984126984126984126984126984127));
  375. }
  376. //-----------------------------------------------------
  377. // Procedure: Filter
  378. //
  379. //-----------------------------------------------------
  380. #define MULTI (0.33333333333333333333333333333333f)
  381. void OSC_WaveMorph_3::Filter( float *In )
  382. {
  383. float rez, hp1;
  384. float input, out = 0.0f, lowpass, bandpass, highpass;
  385. if( (int)params[ PARAM_FILTER_MODE ].value == 0 )
  386. return;
  387. rez = 1.0 - clamp( params[ PARAM_RES ].value * ( inputs[ IN_REZ ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f );
  388. input = *In / AUDIO_MAX;
  389. input = input + 0.000000001;
  390. lp1 = lp1 + f * bp1;
  391. hp1 = input - lp1 - rez * bp1;
  392. bp1 = f * hp1 + bp1;
  393. lowpass = lp1;
  394. highpass = hp1;
  395. bandpass = bp1;
  396. lp1 = lp1 + f * bp1;
  397. hp1 = input - lp1 - rez * bp1;
  398. bp1 = f * hp1 + bp1;
  399. lowpass = lowpass + lp1;
  400. highpass = highpass + hp1;
  401. bandpass = bandpass + bp1;
  402. input = input - 0.000000001;
  403. lp1 = lp1 + f * bp1;
  404. hp1 = input - lp1 - rez * bp1;
  405. bp1 = f * hp1 + bp1;
  406. lowpass = (lowpass + lp1) * MULTI;
  407. highpass = (highpass + hp1) * MULTI;
  408. bandpass = (bandpass + bp1) * MULTI;
  409. switch( (int)params[ PARAM_FILTER_MODE ].value )
  410. {
  411. case FILTER_LP:
  412. out = lowpass;
  413. break;
  414. case FILTER_HP:
  415. out = highpass;
  416. break;
  417. case FILTER_BP:
  418. out = bandpass;
  419. break;
  420. case FILTER_NT:
  421. out = lowpass + highpass;
  422. break;
  423. default:
  424. return;
  425. }
  426. *In = out * AUDIO_MAX;
  427. }
  428. //-----------------------------------------------------
  429. // Procedure: step
  430. //
  431. //-----------------------------------------------------
  432. void OSC_WaveMorph_3::step()
  433. {
  434. int ch;
  435. float fout = 0.0f, fmorph[ nCHANNELS ] = {}, fcv, cutoff, flevel;
  436. bool bChangeWave = false;
  437. if( !m_bInitialized )
  438. return;
  439. fcv = clamp( inputs[ INPUT_MORPHCV ].normalize( 0.0f ) / CV_MAX, -1.0f, 1.0f );
  440. fmorph[ 1 ] = 1.0 - fabs( fcv );
  441. // left wave
  442. if( fcv <= 0.0f )
  443. fmorph[ 0 ] = -fcv;
  444. else if( fcv > 0.0f )
  445. fmorph[ 2 ] = fcv;
  446. bChangeWave = ( m_SchmittChangeWave.process( inputs[ IN_WAVE_CHANGE ].normalize( 0.0f ) ) );
  447. if( bChangeWave && m_bSolo )
  448. {
  449. ch = m_CurrentChannel + 1;
  450. if( ch >= nCHANNELS )
  451. ch = 0;
  452. ChangeChannel( ch );
  453. }
  454. // process each channel
  455. for( ch = 0; ch < nCHANNELS; ch++ )
  456. {
  457. m_pEnvelope->m_EnvData[ ch ].m_Clock.syncInc = 32.7032f * clamp( powf( 2.0f, clamp( inputs[ INPUT_VOCT ].normalize( 3.0f ), 0.0f, VOCT_MAX ) ), 0.0f, 4186.01f );
  458. if( m_bSolo && ch == m_CurrentChannel )
  459. fout += m_pEnvelope->procStep( ch, false, false );
  460. else if( !m_bSolo )
  461. fout += m_pEnvelope->procStep( ch, false, false ) * fmorph[ ch ];
  462. }
  463. cutoff = clamp( params[ PARAM_CUTOFF ].value * ( inputs[ IN_FILTER ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f );
  464. ChangeFilterCutoff( cutoff );
  465. flevel = clamp( params[ PARAM_LEVEL ].value * ( inputs[ IN_LEVEL ].normalize( CV_MAX ) / CV_MAX ), 0.0f, 1.0f );
  466. fout *= flevel;
  467. Filter( &fout );
  468. outputs[ OUTPUT_AUDIO ].value = clamp( fout, -AUDIO_MAX, AUDIO_MAX );
  469. }
  470. } // namespace rack_plugin_mscHack
  471. using namespace rack_plugin_mscHack;
  472. RACK_PLUGIN_MODEL_INIT(mscHack, OSC_WaveMorph_3) {
  473. Model *modelOSC_WaveMorph_3 = Model::create<OSC_WaveMorph_3, OSC_WaveMorph_3_Widget>( "mscHack", "OSC_WaveMorph_3", "OSC Wavemorph3", OSCILLATOR_TAG, MULTIPLE_TAG );
  474. return modelOSC_WaveMorph_3;
  475. }