Programmable real-time audio signal processing application
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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. }