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.

450 lines
10.0KB

  1. #include "mscHack.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_mscHack {
  4. #define WAVE_BUFFER_LEN ( 192000 / 20 ) // (9600) based on quality for 20Hz at max sample rate 192000
  5. typedef struct
  6. {
  7. char code[ 6 ];
  8. }MCODE_STRUCT;
  9. // 1-dot 2-dash
  10. MCODE_STRUCT alphaCode[ 26 ] =
  11. {
  12. /* A */ { '.', '-', 0, 0, 0, 0 }, /* B */ { '-', '.', '.', '.', 0, 0 }, /* C */ { '-', '.', '-', '.', 0, 0 }, /* D */ { '-', '.', '.', 0, 0, 0 },
  13. /* E */ { '.', 0, 0, 0, 0, 0 }, /* F */ { '.', '.', '-', '.', 0, 0 }, /* G */ { '-', '-', '.', 0, 0, 0 }, /* H */ { '.', '.', '.', '.', 0, 0 },
  14. /* I */ { '.', '.', 0, 0, 0, 0 }, /* J */ { '.', '-', '-', '-', 0, 0 }, /* K */ { '-', '.', '-', 0, 0, 0 }, /* L */ { '.', '-', '.', '.', 0, 0 },
  15. /* M */ { '-', '-', 0, 0, 0, 0 }, /* N */ { '-', '.', 0, 0, 0, 0 }, /* O */ { '-', '-', '-', 0, 0, 0 }, /* P */ { '.', '-', '-', '.', 0, 0 },
  16. /* Q */ { '-', '-', '.', '-', 0, 0 }, /* R */ { '.', '-', '.', 0, 0, 0 }, /* S */ { '.', '.', '.', 0, 0, 0 }, /* T */ { '-', 0, 0, 0, 0, 0 },
  17. /* U */ { '.', '.', '-', 0, 0, 0 }, /* V */ { '.', '.', '.', '-', 0, 0 }, /* W */ { '.', '-', '-', 0, 0, 0 }, /* X */ { '-', '.', '.', '-', 0, 0 },
  18. /* Y */ { '-', '.', '-', '-', 0, 0 }, /* Z */ { '-', '-', '.', '.', 0, 0 }
  19. };
  20. MCODE_STRUCT numCode[ 10 ] =
  21. {
  22. /* 0 */ { '-', '-', '-', '-', '-', 0 },
  23. /* '.' */ { '.', '-', '-', '-', '-', 0 },
  24. /* '-' */ { '.', '.', '-', '-', '-', 0 },
  25. /* 3 */ { '.', '.', '.', '-', '-', 0 },
  26. /* 4 */ { '.', '.', '.', '.', '-', 0 },
  27. /* 5 */ { '.', '.', '.', '.', '.', 0 },
  28. /* 6 */ { '-', '.', '.', '.', '.', 0 },
  29. /* 7 */ { '-', '-', '.', '.', '.', 0 },
  30. /* 8 */ { '-', '-', '-', '.', '.', 0 },
  31. /* 9 */ { '-', '-', '-', '-', '.', 0 },
  32. };
  33. //-----------------------------------------------------
  34. // Module Definition
  35. //
  36. //-----------------------------------------------------
  37. struct Morze : Module
  38. {
  39. enum ParamIds
  40. {
  41. PARAM_SPEED,
  42. nPARAMS
  43. };
  44. enum InputIds
  45. {
  46. IN_TRIG,
  47. nINPUTS
  48. };
  49. enum OutputIds
  50. {
  51. OUT_GATE,
  52. nOUTPUTS
  53. };
  54. enum LightIds
  55. {
  56. nLIGHTS
  57. };
  58. CLog lg;
  59. bool m_bInitialized = false;
  60. int m_Index = 0;
  61. char m_Code[ 1024 ] ={};
  62. int m_count = 0;
  63. bool m_bGate = false;
  64. std::string m_stdCurrent;
  65. SchmittTrigger m_SchmitTrig;
  66. bool m_bTrigWait = true;
  67. TextField *m_TextField = NULL;
  68. bool m_bOneShot = false;
  69. Label *m_pTextLabel = NULL;
  70. // Contructor
  71. Morze() : Module(nPARAMS, nINPUTS, nOUTPUTS, nLIGHTS){}
  72. void Text2Code( char *strText );
  73. bool GetGate( void );
  74. // Overrides
  75. void step() override;
  76. void JsonParams( bool bTo, json_t *root);
  77. json_t* toJson() override;
  78. void fromJson(json_t *rootJ) override;
  79. void onRandomize() override;
  80. void onReset() override;
  81. void onCreate() override;
  82. void onDelete() override;
  83. };
  84. //-----------------------------------------------------
  85. // Procedure: Widget
  86. //
  87. //-----------------------------------------------------
  88. struct Morze_Widget : ModuleWidget {
  89. Morze_Widget( Morze *module );
  90. };
  91. Morze_Widget::Morze_Widget( Morze *module ) : ModuleWidget(module)
  92. {
  93. box.size = Vec( 15*5, 380);
  94. {
  95. SVGPanel *panel = new SVGPanel();
  96. panel->box.size = box.size;
  97. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Morze.svg")));
  98. addChild(panel);
  99. }
  100. //module->lg.Open("c://users//mark//documents//rack//Morze.txt");
  101. //mm2px(Vec(3.39962, 14.8373))
  102. addInput(Port::create<MyPortInSmall>( Vec( 10, 20 ), Port::INPUT, module, Morze::IN_TRIG ) );
  103. addOutput(Port::create<MyPortOutSmall>( Vec( 48, 20 ), Port::OUTPUT, module, Morze::OUT_GATE ) );
  104. addParam(ParamWidget::create<Knob_Yellow3_20>( Vec( 10, 280 ), module, Morze::PARAM_SPEED, 0.0f, 1.0f, 0.5f ) );
  105. module->m_TextField = Widget::create<LedDisplayTextField>( Vec( 4, 100 ) );
  106. module->m_TextField->box.size = Vec( 67, 150.0 );
  107. module->m_TextField->multiline = true;
  108. addChild( module->m_TextField );
  109. module->m_TextField->text = "mscHack";
  110. module->m_pTextLabel = new Label();
  111. module->m_pTextLabel->box.pos = Vec( 30, 250 );
  112. module->m_pTextLabel->text = "";
  113. addChild( module->m_pTextLabel );
  114. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  115. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  116. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  117. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  118. module->Text2Code( (char*)module->m_TextField->text.c_str() );
  119. //module->BuildWaves();
  120. module->m_bInitialized = true;
  121. }
  122. //-----------------------------------------------------
  123. // Procedure: JsonParams
  124. //
  125. //-----------------------------------------------------
  126. void Morze::JsonParams( bool bTo, json_t *root)
  127. {
  128. JsonDataString( bTo, "MorseText", root, &m_TextField->text );
  129. }
  130. //-----------------------------------------------------
  131. // Procedure: toJson
  132. //
  133. //-----------------------------------------------------
  134. json_t *Morze::toJson()
  135. {
  136. json_t *root = json_object();
  137. if( !root )
  138. return NULL;
  139. JsonParams( TOJSON, root );
  140. return root;
  141. }
  142. //-----------------------------------------------------
  143. // Procedure: fromJson
  144. //
  145. //-----------------------------------------------------
  146. void Morze::fromJson( json_t *root )
  147. {
  148. JsonParams( FROMJSON, root );
  149. Text2Code( (char*)m_TextField->text.c_str() );
  150. }
  151. //-----------------------------------------------------
  152. // Procedure: onCreate
  153. //
  154. //-----------------------------------------------------
  155. void Morze::onCreate()
  156. {
  157. }
  158. //-----------------------------------------------------
  159. // Procedure: onDelete
  160. //
  161. //-----------------------------------------------------
  162. void Morze::onDelete()
  163. {
  164. }
  165. //-----------------------------------------------------
  166. // Procedure: onReset
  167. //
  168. //-----------------------------------------------------
  169. void Morze::onReset()
  170. {
  171. }
  172. //-----------------------------------------------------
  173. // Procedure: onRandomize
  174. //
  175. //-----------------------------------------------------
  176. void Morze::onRandomize()
  177. {
  178. }
  179. //-----------------------------------------------------
  180. // Procedure: isalphanum
  181. //
  182. //-----------------------------------------------------
  183. bool isalphanum( char c )
  184. {
  185. if( c >= 'a' && c <= 'z')
  186. return true;
  187. else if( c >= 'A' && c <= 'Z')
  188. return true;
  189. else if( c >= '0' && c <= '9')
  190. return true;
  191. return false;
  192. }
  193. //-----------------------------------------------------
  194. // Procedure: Text2Code
  195. //
  196. //-----------------------------------------------------
  197. void Morze::Text2Code( char *strText )
  198. {
  199. int i = 0;
  200. char c;
  201. bool bIgnoreWS =false;
  202. char strChar[ 2 ] = {0};
  203. memset( m_Code, 0, sizeof( m_Code ) );
  204. c = strText[ 0 ];
  205. while( c )
  206. {
  207. strChar[ 0 ] = c;
  208. if( c >= 'a' && c <= 'z' )
  209. {
  210. strcat( m_Code, strChar );
  211. strcat( m_Code, alphaCode[ c - 'a' ].code );
  212. strcat( m_Code, "*" );
  213. bIgnoreWS = false;
  214. }
  215. else if( c >= 'A' && c <= 'Z' )
  216. {
  217. strcat( m_Code, strChar );
  218. strcat( m_Code, alphaCode[ c - 'A' ].code );
  219. strcat( m_Code, "*" );
  220. bIgnoreWS = false;
  221. }
  222. else if( c >= '0' && c <= '9' )
  223. {
  224. strcat( m_Code, strChar );
  225. strcat( m_Code, alphaCode[ c - '0' ].code );
  226. strcat( m_Code, "*" );
  227. bIgnoreWS = false;
  228. }
  229. else if( c == '.' )
  230. {
  231. strcat( m_Code, strChar );
  232. strcat( m_Code, "." );
  233. bIgnoreWS = false;
  234. }
  235. else if( c == '-' )
  236. {
  237. strcat( m_Code, strChar );
  238. strcat( m_Code, "-" );
  239. bIgnoreWS = false;
  240. }
  241. else
  242. {
  243. if( !bIgnoreWS )
  244. {
  245. bIgnoreWS = true;
  246. strcat( m_Code, " " );
  247. }
  248. }
  249. c = strText[ ++i ];
  250. }
  251. if( !bIgnoreWS )
  252. {
  253. strcat( m_Code, " " );
  254. }
  255. strcat( m_Code, "\0" );
  256. /*i = 0;
  257. while( m_Code[ i ] )
  258. {
  259. lg.f("%c\n", m_Code[ i++ ] );
  260. };*/
  261. //lg.f("%s\n", m_Code);
  262. m_Index = 0;
  263. m_bGate = false;
  264. m_count = 0;
  265. m_bTrigWait = true;
  266. m_stdCurrent = m_TextField->text;
  267. }
  268. //-----------------------------------------------------
  269. // Procedure: GetGate
  270. //
  271. //-----------------------------------------------------
  272. bool Morze::GetGate( void )
  273. {
  274. char strChar[ 2 ] = {0};
  275. static int spc = 10;
  276. int ms = (int)( ( engineGetSampleRate() / 1000.0f ) * ( ( 1.0 - params[ PARAM_SPEED ].value ) + 0.5f ) );
  277. if( --m_count > 0 )
  278. return m_bGate;
  279. //break between characters
  280. if( m_bGate )
  281. {
  282. m_count = spc * ms;
  283. m_bGate = false;
  284. }
  285. else
  286. {
  287. //lg.f("%d - %c\n", m_Index, m_Code[ m_Index ] );
  288. //lg.f("%d\n", m_Index );
  289. switch( m_Code[ m_Index ] )
  290. {
  291. case 0: //end
  292. m_bGate = false;
  293. m_count = 0;
  294. m_Index = 0;
  295. m_bTrigWait = true;
  296. return false;
  297. case '*': //letter break
  298. m_bGate = false;
  299. m_count = 60 * ms;
  300. break;
  301. case '.': //dot
  302. m_count = 80 * ms;
  303. m_bGate = true;
  304. spc = 40;
  305. break;
  306. case '-': //dash
  307. m_count = 160 * ms;
  308. m_bGate = true;
  309. spc = 80;
  310. break;
  311. case ' ': //word break
  312. //strChar[ 0 ] = m_Code[ m_Index ];
  313. //m_pTextLabel->text = strChar;
  314. m_bGate = false;
  315. m_count = 400 * ms;
  316. break;
  317. default: // display character
  318. //lg.f("%d - %c\n", m_Index, m_Code[ m_Index ] );
  319. strChar[ 0 ] = m_Code[ m_Index ];
  320. m_pTextLabel->text = strChar;
  321. m_bGate = false;
  322. m_count = 0;
  323. break;
  324. }
  325. m_Index ++;
  326. }
  327. return m_bGate;
  328. }
  329. //-----------------------------------------------------
  330. // Procedure: step
  331. //
  332. //-----------------------------------------------------
  333. void Morze::step()
  334. {
  335. static int checkcount = 0;
  336. if( !m_bInitialized )
  337. return;
  338. if( --checkcount <= 0 )
  339. {
  340. if( m_stdCurrent != m_TextField->text )
  341. {
  342. Text2Code( (char*)m_TextField->text.c_str() );
  343. }
  344. checkcount = (int)( engineGetSampleRate() / 10.0f );
  345. }
  346. if( m_bTrigWait )
  347. {
  348. if( m_SchmitTrig.process( inputs[ IN_TRIG ].normalize( 0.0f ) ) )
  349. {
  350. m_bTrigWait = false;
  351. }
  352. else
  353. {
  354. outputs[ OUT_GATE ].value = 0.0f;
  355. return;
  356. }
  357. }
  358. if( GetGate() )
  359. outputs[ OUT_GATE ].value = CV_MAX;
  360. else
  361. outputs[ OUT_GATE ].value = 0.0f;
  362. }
  363. } // namespace rack_plugin_mscHack
  364. using namespace rack_plugin_mscHack;
  365. RACK_PLUGIN_MODEL_INIT(mscHack, Morze) {
  366. Model *modelMorze = Model::create<Morze, Morze_Widget>( "mscHack", "Morze", "Morze - Morse Code generator", SEQUENCER_TAG, UTILITY_TAG );
  367. return modelMorze;
  368. }