Programmable real-time audio signal processing application
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.

cmGrTksrFltk.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. //| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include <FL/Fl.H>
  4. #include <Fl/fl_draw.h>
  5. #include <FL/Fl_Widget.H>
  6. #include <FL/Fl_Double_Window.H>
  7. #include <Fl/Fl_Output.H>
  8. #include <Fl/Fl_Menu_Bar.H>
  9. #include <vector>
  10. #include "Fl_CbLinker.h"
  11. #include "cmGlobal.h"
  12. #include "cmFloatTypes.h"
  13. #include "cmRpt.h"
  14. #include "cmErr.h"
  15. #include "cmCtx.h"
  16. #include "cmMem.h"
  17. #include "cmMallocDebug.h"
  18. #include "cmLinkedHeap.h"
  19. #include "cmText.h"
  20. #include "cmThread.h"
  21. #include "cmPrefs.h"
  22. #include "cmSymTbl.h"
  23. #include "cmTime.h"
  24. #include "cmMidi.h"
  25. #include "cmMidiFile.h"
  26. #include "cmAudioFile.h"
  27. #include "cmAudioFileMgr.h"
  28. #include "cmTimeLine.h"
  29. #include "cmScore.h"
  30. #include "cmTakeSeqBldr.h"
  31. #include "cmGr.h"
  32. #include "cmGrDevCtx.h"
  33. #include "cmGrPlot.h"
  34. #include "cmGrPage.h"
  35. #include "cmGrFltk.h"
  36. #include "gvHashFunc.h"
  37. #include "cmGrTksrFltk.h"
  38. #include "cmGrPlotAudio.h"
  39. #include "cmdIf.h"
  40. cmGrTksrFltk::cmGrTksrFltk(cmCtx_t* ctx, cmdIf* cp, Fl_Menu_Bar* menu, int x, int y, int w, int h)
  41. : cmGrPlotFltk(ctx,x,y,w,h),
  42. //_cmdIf(cp),
  43. _tksbH(cmTakeSeqBldrNullHandle),
  44. _menuBar(menu),
  45. _samplesMetricId(cmInvalidId),_secondsMetricId(cmInvalidId),
  46. //_objSecs(0),
  47. _objId(0)
  48. //_togFl(true)
  49. {
  50. cmErrSetup(&_err,&ctx->rpt,"cmGrTksrFltk");
  51. _createMenu();
  52. if( cmGrPageIsValid(pageHandle()) == false )
  53. return;
  54. initViews(1,1);
  55. unsigned vwIdx = 0;
  56. cmGrPgH_t pgH = pageHandle();
  57. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx);
  58. cmGrH_t cvH = cmGrViewGrHandle( vwH );
  59. cmGrAxH_t axH = cmGrAxNullHandle;
  60. cmGrVExt_t limExt;
  61. _samplesMetricId = cmGrPageLabelFuncRegister( pgH, gvRoundHashValueFunc, this, "Round" );
  62. _secondsMetricId = cmGrPageLabelFuncRegister( pgH, gvMinSecMsHashValueFunc, this, "Min:Sec:Ms" );
  63. unsigned pitchLabelFuncId = cmGrPageLabelFuncRegister( pgH, gvMidiSciPitchValueFunc, this, "Pitch" );
  64. cmGrVExtSetD(&limExt,0,0,0,127);
  65. cmGrObjSetWorldExt( cvH, cmGrRootObjH(cvH), &limExt );
  66. cmGrObjSetWorldLimitExt(cvH, cmGrRootObjH(cvH), &limExt, kTopGrFl | kBottomGrFl );
  67. axH = cmGrViewAxisHandle(vwH, kTopGrIdx);
  68. cmGrAxisSetCfg( axH, cmClrFlag(cmGrAxisCfg( axH ), kHashMarkGrFl | kHashLabelGrFl ));
  69. axH = cmGrViewAxisHandle(vwH, kLeftGrIdx );
  70. cmGrAxisSetLabelFunc( axH, pitchLabelFuncId );
  71. cmGrViewSetLabelFunc( vwH, kLeftGrIdx, pitchLabelFuncId );
  72. axH = cmGrViewAxisHandle(vwH, kRightGrIdx);
  73. cmGrAxisSetCfg( axH, cmClrFlag(cmGrAxisCfg( axH ), kHashLabelGrFl ));
  74. cmGrViewSetCfg( vwH, cmSetFlag(cmGrViewCfg(vwH),kSelectHorzGrFl) );
  75. }
  76. cmGrTksrFltk::~cmGrTksrFltk()
  77. {}
  78. void cmGrTksrFltk::setTksbHandle( void* v )
  79. {
  80. _tksbH.h = v;
  81. }
  82. void cmGrTksrFltk::refresh()
  83. {
  84. if( cmGrPlotClear( plotHandle() ) != kOkGrPlRC )
  85. {
  86. cmErrMsg(&_err,kClearPlotFailRC,"Plot clear failed.");
  87. return;
  88. }
  89. if( cmTakeSeqBldrIsValid(_tksbH) == false )
  90. return;
  91. // insert tksb events here
  92. cmTakeSeqBldrRendReset(_tksbH);
  93. cmTksbRend_t m;
  94. unsigned absSmpIdx = 0;
  95. double srate = cmTakeSeqBldrSampleRate(_tksbH);
  96. while( cmTakeSeqBldrRendNext(_tksbH,&m) )
  97. {
  98. m.evt.smpIdx = absSmpIdx;
  99. _insertEvent(&m,srate);
  100. absSmpIdx += m.offsetSmp;
  101. }
  102. }
  103. double cmGrTksrFltk::sampleRate() const
  104. {
  105. if( cmTakeSeqBldrIsValid(_tksbH) )
  106. return cmTakeSeqBldrSampleRate(_tksbH);
  107. return 0;
  108. }
  109. bool cmGrTksrFltk::on_plot_object( cmGrPlotCbArg_t* arg )
  110. {
  111. /*
  112. if( arg->selId==kStateChangeGrPlId && cmIsFlag(arg->deltaFlags,kSelectGrPlFl) )
  113. {
  114. scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(arg->objH);
  115. unsigned state = cmGrPlotObjStateFlags(arg->objH);
  116. bool isSelectedFl = cmIsFlag( state, kSelectGrPlFl);
  117. if( sop != NULL )
  118. {
  119. //printf("SELECT:%i %i 0x%x\n",cmGrPlotObjId(arg->objH),isSelectedFl,state);
  120. if( sop->id==kTakeTksrId && sop->u.tlMarkerUid!=cmInvalidId )
  121. {
  122. if( isSelectedFl )
  123. cmTakeSeqBldrLoadTake(_tksbH,sop->u.tlMarkerUid,true);
  124. else
  125. cmTakeSeqBldrUnloadTake(_tksbH,sop->u.tlMarkerUid);
  126. setStatusText(cmTsPrintfS("%s", cmStringNullGuard(cmTakeSeqBldrScTrkTakeText(_tksbH,sop->u.tlMarkerUid))));
  127. }
  128. if( sop->id==kEventTksrId && sop->u.ep!=NULL && sop->u.ep->type==kBarEvtScId )
  129. {
  130. _lastBarPlotObjH = arg->objH;
  131. // callback to: kcApp::_ctl_cb(ctl_t* cp)
  132. callback()(this,user_data());
  133. }
  134. }
  135. }
  136. */
  137. return true;
  138. }
  139. void cmGrTksrFltk::_insertEvent( const cmTksbRend_t* m, double srate )
  140. {
  141. if( cmGrPageIsValid(pageHandle()) == false )
  142. return;
  143. cmGrPlH_t plH = plotHandle();
  144. cmGrPgH_t pgH = pageHandle();
  145. unsigned vwIdx = 0;
  146. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx );
  147. cmGrH_t cvH = cmGrViewGrHandle( vwH );
  148. cmGrPlObjH_t parentObjH = cmGrPlObjNullHandle;
  149. cmGrPlObjH_t xAnchorObjH = cmGrPlObjNullHandle;
  150. cmGrPlObjH_t yAnchorObjH = cmGrPlObjNullHandle;
  151. cmGrPlObjH_t objH = cmGrPlObjNullHandle;
  152. cmGrPlObjTypeId_t objTypeId = kRectGrPlId;
  153. cmReal_t x = m->evt.smpIdx / srate;
  154. cmReal_t y = 0;
  155. cmReal_t h = 1;
  156. cmReal_t w = m->durSmp / srate;
  157. const cmChar_t* label = NULL;
  158. unsigned flags = kNoDragGrPlFl;
  159. tksrId_t tid = kInvalidTksrId;
  160. if( cmMidiIsNoteOn(m->evt.status) )
  161. {
  162. tid = kNoteTksrId;
  163. y = m->evt.d0;
  164. label = cmMidiToSciPitch(m->evt.d0,NULL,0);
  165. }
  166. else
  167. {
  168. if( cmMidiIsPedalDown(m->evt.status,m->evt.d0,m->evt.d1) )
  169. {
  170. tid = kPedalTksrId;
  171. y = 120;
  172. label = cmMidiPedalLabel(m->evt.d0);
  173. flags |= kNoFillGrPlFl;
  174. }
  175. }
  176. if( tid == kInvalidTksrId )
  177. return;
  178. //printf("absSmpIdx:%f %f\n",x,w);
  179. // create the plot object to represent this event
  180. if( cmGrPlotObjCreate(plH, cvH, &objH, _objId++, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, NULL ) != kOkGrPlRC )
  181. {
  182. cmErrMsg(&_err,kInsertObjFailRC,"Insert failed on a score event.", cmStringNullGuard(label));
  183. return;
  184. }
  185. // store the score event reference as custom data inside the plot object
  186. scObj_t scObj(tid,m->rid);
  187. cmGrPlotObjAllocUser(objH,&scObj,sizeof(scObj));
  188. switch( tid )
  189. {
  190. case kNoteTksrId:
  191. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, cmGrPlotObjFillColor(objH,kEnablePlGrId) );
  192. cmGrPlotObjSetFontSize(objH,8);
  193. break;
  194. case kPedalTksrId:
  195. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kDeepPinkGrId );
  196. cmGrPlotObjSetFontSize(objH,8);
  197. break;
  198. default:
  199. break;
  200. }
  201. }
  202. #define cmMENU_TITLE "Rndr"
  203. void cmGrTksrFltk::_createMenu( )
  204. {
  205. int idx = _menuBar->add(cmMENU_TITLE,0,NULL,0,FL_SUBMENU);
  206. const char* titleArray[] = { "Pitch", "ScEvtIdx", "Delete", "Sustain", "Sostenuto", "Write", "Read" };
  207. bool onFl[] = { true, false, false, false, false, false, false };
  208. bool checkFl[] = { true, true, false, false, false, false, false };
  209. int i;
  210. for(i=0; i<kMenuItemCnt; ++i)
  211. {
  212. _menuArray[i].id = i;
  213. _menuArray[i].p = this;
  214. _menuBar->insert(idx+1+i,titleArray[i],0,_s_menuCallback, _menuArray + i, checkFl[i] ? FL_MENU_TOGGLE : 0 );
  215. if( onFl[i] )
  216. {
  217. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + idx + i + 1;
  218. mip->set();
  219. }
  220. }
  221. _menuBar->redraw();
  222. }
  223. bool cmGrTksrFltk::_isMenuChecked( int id )
  224. {
  225. unsigned i;
  226. // locate the menu item assoc'd with id
  227. for(i=0; i<kMenuItemCnt; ++i)
  228. if( _menuArray[i].id == id )
  229. break;
  230. assert( i < kMenuItemCnt );
  231. int menuIdx;
  232. if(( menuIdx = _menuBar->find_index(cmMENU_TITLE)) == -1 )
  233. return false;
  234. // The menu items and _menuArray[] were initialized in the same order
  235. // therefore the offset from the base of both should be the same.
  236. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + menuIdx + i + 1;
  237. assert( (item_t*)mip->user_data() == _menuArray + i );
  238. return mip->value() != 0;
  239. }
  240. void cmGrTksrFltk::_setEventLabels()
  241. {
  242. enum { kPitchFl=0x01, kScEvtFl=0x02 };
  243. if( cmTakeSeqBldrIsValid( _tksbH ) == false )
  244. return;
  245. cmGrPlH_t plH = plotHandle();
  246. unsigned flags = 0;
  247. flags |= _isMenuChecked(kPitchMId) ? kPitchFl : 0;
  248. flags |= _isMenuChecked(kScEvtMId) ? kScEvtFl : 0;
  249. unsigned n = cmGrPlotObjectCount(plH);
  250. unsigned i;
  251. for(i=0; i<n; ++i)
  252. {
  253. cmGrPlObjH_t poH = cmGrPlotObjectIndexToHandle(plH,i);
  254. if( cmGrPlotObjIsValid(poH) )
  255. {
  256. scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(poH);
  257. if( sop!=NULL && sop->id==kNoteTksrId && sop->u.rid!=cmInvalidId )
  258. {
  259. cmTksbRend_t r;
  260. if( cmTakeSeqBldrRendInfo( _tksbH, sop->u.rid, &r ) == kOkTsbRC )
  261. {
  262. int bufN = 255;
  263. cmChar_t buf[ bufN+1 ];
  264. buf[bufN] = 0;
  265. buf[0] = 0;
  266. if( cmIsFlag(flags,kPitchFl) && r.evt.status == kNoteOnMdId )
  267. snprintf(buf+strlen(buf),bufN-strlen(buf),"%s ",cmMidiToSciPitch(r.evt.d0,NULL,0));
  268. if( cmIsFlag(flags,kScEvtFl) && r.scEvtIdx != cmInvalidIdx )
  269. snprintf(buf+strlen(buf),bufN-strlen(buf),"sei:%i ",r.scEvtIdx);
  270. cmGrPlotObjSetLabel(poH, buf );
  271. }
  272. }
  273. }
  274. }
  275. }
  276. void cmGrTksrFltk::_s_deleteSelectedEle( void* arg, cmGrPlObjH_t oh )
  277. {
  278. if( cmIsFlag(cmGrPlotObjStateFlags(oh), kSelectGrPlFl) )
  279. {
  280. cmGrTksrFltk* p = (cmGrTksrFltk*)arg;
  281. scObj_t* sop = (scObj_t*)cmGrPlotObjUserPtr(oh);
  282. cmTakeSeqBldrRendDelete( p->_tksbH, sop->u.rid );
  283. }
  284. }
  285. void cmGrTksrFltk::_write()
  286. {
  287. const cmChar_t* fn = "/home/kevin/temp/kr/tksb/tksb0.js";
  288. if( cmTakeSeqBldrIsValid(_tksbH) == false )
  289. return;
  290. if( cmTakeSeqBldrWrite( _tksbH, fn ) != kOkTsbRC )
  291. cmErrMsg(&_err,kTksbFailRC,"Render write failed for '%s'.",cmStringNullGuard(fn));
  292. }
  293. void cmGrTksrFltk::_read()
  294. {
  295. const cmChar_t* fn = "/home/kevin/temp/kr/tksb/tksb0.js";
  296. if( cmTakeSeqBldrIsValid(_tksbH) == false )
  297. return;
  298. if( cmTakeSeqBldrRead( _tksbH, fn ) != kOkTsbRC )
  299. cmErrMsg(&_err,kTksbFailRC,"Render write failed for '%s'.",cmStringNullGuard(fn));
  300. }
  301. void cmGrTksrFltk::_insertPedal( unsigned long pedalMId )
  302. {
  303. if( cmTakeSeqBldrIsValid(_tksbH) == false )
  304. return;
  305. unsigned vwIdx = 0;
  306. cmGrPgH_t pgH = pageHandle();
  307. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx);
  308. cmGrH_t cvH = cmGrViewGrHandle( vwH );
  309. double srate = cmTakeSeqBldrSampleRate(_tksbH);
  310. cmGrVPt_t pt0,pt1;
  311. unsigned rid;
  312. cmTksbEvent_t e;
  313. memset(&e,0,sizeof(e));
  314. cmGrSelectPoints( cvH, &pt0, &pt1 );
  315. unsigned durSmp = (pt1.x - pt0.x) * srate;
  316. e.status = kCtlMdId;
  317. switch( pedalMId )
  318. {
  319. case kSustainMId:
  320. e.d0 = kSustainCtlMdId;
  321. break;
  322. case kSostenutoMId:
  323. e.d0 = kSostenutoCtlMdId;
  324. break;
  325. }
  326. //printf("x0:%f x1:%f %i\n",pt0.x,pt1.x,durSmp);
  327. e.smpIdx = pt0.x * srate;
  328. e.d1 = 127;
  329. cmTakeSeqBldrRendInsert( _tksbH, &e, durSmp, &rid );
  330. e.smpIdx = pt1.x * srate;
  331. e.d1 = 0;
  332. cmTakeSeqBldrRendInsert( _tksbH, &e, 0, &rid );
  333. refresh();
  334. }
  335. void cmGrTksrFltk::_s_menuCallback(Fl_Widget* w, void* arg )
  336. {
  337. item_t* ip = (item_t*)arg;
  338. cmGrTksrFltk* p = ip->p;
  339. unsigned long id = ip->id;
  340. switch( id )
  341. {
  342. case kPitchMId:
  343. case kScEvtMId:
  344. p->_setEventLabels();
  345. p->redraw();
  346. break;
  347. case kDeleteMId:
  348. cmGrPlotObjCb(p->plotHandle(),_s_deleteSelectedEle,p);
  349. p->refresh();
  350. p->redraw();
  351. break;
  352. case kSustainMId:
  353. case kSostenutoMId:
  354. p->_insertPedal(id);
  355. p->refresh();
  356. p->redraw();
  357. break;
  358. case kWriteMId:
  359. p->_write();
  360. break;
  361. case kReadMId:
  362. p->_read();
  363. break;
  364. }
  365. }