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.

cmGrTlFltk.cpp 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. #include <FL/Fl.H>
  2. #include <Fl/fl_draw.h>
  3. #include <FL/Fl_Widget.H>
  4. #include <FL/Fl_Double_Window.H>
  5. #include <Fl/Fl_Output.H>
  6. #include <Fl/Fl_Menu_Bar.H>
  7. #include <vector>
  8. #include "Fl_CbLinker.h"
  9. #include "cmGlobal.h"
  10. #include "cmFloatTypes.h"
  11. #include "cmRpt.h"
  12. #include "cmErr.h"
  13. #include "cmCtx.h"
  14. #include "cmMem.h"
  15. #include "cmMallocDebug.h"
  16. #include "cmLinkedHeap.h"
  17. #include "cmText.h"
  18. #include "cmThread.h"
  19. #include "cmPrefs.h"
  20. #include "cmTime.h"
  21. #include "cmMidi.h"
  22. #include "cmMidiFile.h"
  23. #include "cmAudioFile.h"
  24. #include "cmAudioFileMgr.h"
  25. #include "cmSymTbl.h"
  26. #include "cmTimeLine.h"
  27. #include "cmScore.h"
  28. #include "cmGr.h"
  29. #include "cmGrDevCtx.h"
  30. #include "cmGrPlot.h"
  31. #include "cmGrPage.h"
  32. #include "cmGrFltk.h"
  33. #include "gvHashFunc.h"
  34. #include "cmGrTlFltk.h"
  35. #include "cmGrPlotAudio.h"
  36. #include "cmdIf.h"
  37. cmGrTlFltk::cmGrTlFltk(cmCtx_t* ctx, cmdIf* cp, Fl_Menu_Bar* menu, int x, int y, int w, int h)
  38. : cmGrPlotFltk(ctx,x,y,w,h),_srate(0),_cmdIf(cp),_menuBar(menu),
  39. _seqMenuIdx(cmInvalidIdx),_seqCnt(0),_seqItemArray(NULL),
  40. _markCnt(0),
  41. _samplesMetricId(cmInvalidId),_secondsMetricId(cmInvalidId),
  42. _selMarkPlotObjH(cmGrPlObjNullHandle),
  43. _curSeqId(cmInvalidId)
  44. {
  45. _createMenu();
  46. //_seqMenuIdx = _menuBar->find_index("&Seq");
  47. cmErrSetup(&_err,&ctx->rpt,"cmGrTlFltk");
  48. if( cmGrPageIsValid(pageHandle()) == false )
  49. return;
  50. // set the arrangement of 'views' on the 'page'
  51. // (2 rows, 1 column)
  52. initViews(kViewCnt,1);
  53. unsigned vwIdx = kAudioVwIdx;
  54. cmGrPgH_t grPgH = pageHandle();
  55. cmGrVwH_t grVwH = cmGrPageViewHandle( grPgH, vwIdx);
  56. cmGrH_t grH = cmGrViewGrHandle( grVwH );
  57. cmGrAxH_t grAxH = cmGrAxNullHandle;
  58. cmGrVExt_t limExt;
  59. // register plot hash mark labelling functions
  60. _samplesMetricId = cmGrPageLabelFuncRegister( grPgH, _s_roundHashValueFunc, this, "Round" );
  61. _secondsMetricId = cmGrPageLabelFuncRegister( grPgH, _s_minSecMsHashValueFunc, this, "Min:Sec:Ms" );
  62. unsigned pitchLabelFuncId = cmGrPageLabelFuncRegister( grPgH, _s_midiSciPitchValueFunc, this, "Pitch" );
  63. //unsigned timeLabelFuncId = _secondsMetricId;
  64. cmGrVExtSetD(&limExt,0,-1,0,1);
  65. cmGrObjSetWorldLimitExt(grH, cmGrRootObjH(grH), &limExt, kTopGrFl | kBottomGrFl );
  66. grAxH = cmGrViewAxisHandle(grVwH, kBottomGrIdx);
  67. cmGrAxisSetCfg( grAxH, cmClrFlag(cmGrAxisCfg( grAxH ), kHashMarkGrFl | kHashLabelGrFl ));
  68. //grAxH = cmGrViewAxisHandle(grVwH, kTopGrIdx );
  69. //cmGrAxisSetLabelFunc( grAxH, timeLabelFuncId );
  70. grAxH = cmGrViewAxisHandle(grVwH, kRightGrIdx);
  71. cmGrAxisSetCfg( grAxH, cmClrFlag(cmGrAxisCfg( grAxH ), kHashLabelGrFl ));
  72. //cmGrViewSetLabelFunc( grVwH, kTopGrIdx, timeLabelFuncId );
  73. cmGrViewSetCfg( grVwH, cmSetFlag(cmGrViewCfg(grVwH),kSelectHorzGrFl) );
  74. vwIdx = kMidiVwIdx;
  75. grVwH = cmGrPageViewHandle( grPgH, vwIdx);
  76. grH = cmGrViewGrHandle( grVwH );
  77. cmGrVExtSetD(&limExt,0,0,0,127);
  78. cmGrObjSetWorldLimitExt(grH, cmGrRootObjH(grH), &limExt, kTopGrFl | kBottomGrFl );
  79. grAxH = cmGrViewAxisHandle(grVwH, kTopGrIdx);
  80. cmGrAxisSetCfg( grAxH, cmClrFlag(cmGrAxisCfg( grAxH ), kHashMarkGrFl | kHashLabelGrFl ));
  81. //grAxH = cmGrViewAxisHandle(grVwH, kBottomGrIdx );
  82. //cmGrAxisSetLabelFunc( grAxH, timeLabelFuncId );
  83. grAxH = cmGrViewAxisHandle(grVwH, kRightGrIdx);
  84. cmGrAxisSetCfg( grAxH, cmClrFlag(cmGrAxisCfg( grAxH ), kHashLabelGrFl ));
  85. grAxH = cmGrViewAxisHandle(grVwH, kLeftGrIdx );
  86. cmGrAxisSetLabelFunc( grAxH, pitchLabelFuncId );
  87. //cmGrViewSetLabelFunc( grVwH, kTopGrIdx, timeLabelFuncId );
  88. cmGrViewSetLabelFunc( grVwH, kLeftGrIdx, pitchLabelFuncId );
  89. cmGrViewSetCfg( grVwH, cmSetFlag(cmGrViewCfg(grVwH),kSelectHorzGrFl) );
  90. cmGrSetSync( grH, cmGrViewGrHandle( cmGrPageViewHandle( grPgH, kAudioVwIdx ) ), kWorldSyncGrFl | kViewSyncGrFl | kSelectSyncGrFl | kHorzSyncGrFl );
  91. cmGrSetSync( cmGrViewGrHandle( cmGrPageViewHandle( grPgH, kAudioVwIdx ) ), grH, kWorldSyncGrFl | kViewSyncGrFl | kSelectSyncGrFl | kHorzSyncGrFl );
  92. setTimeAxisMetric(kSecondsMetricId);
  93. }
  94. cmGrTlFltk::~cmGrTlFltk()
  95. {
  96. cmMemFree(_seqItemArray);
  97. }
  98. void cmGrTlFltk::_insertTimeLineObj( const cmTlUiMsg_t* m )
  99. {
  100. cmGrPlH_t plH = plotHandle();
  101. cmGrPgH_t pgH = pageHandle();
  102. cmGrPlObjH_t parentObjH = cmGrPlObjNullHandle;
  103. cmGrPlObjH_t xAnchorObjH = cmGrPlObjNullHandle;
  104. cmGrPlObjH_t yAnchorObjH = cmGrPlObjNullHandle;
  105. cmGrPlObjH_t objH = cmGrPlObjNullHandle;
  106. const cmTlObj_t* top = _cmdIf->tlObjIdToPtr(m->objId);
  107. assert(top != NULL);
  108. if( top==NULL)
  109. return;
  110. unsigned parentObjId = (top!=NULL && top->ref!=NULL) ? top->ref->uid : cmInvalidId;
  111. const cmTlMidiEvt_t* mep = NULL;
  112. const cmTlAudioFile_t* afp = NULL;
  113. unsigned vwIdx = kAudioVwIdx;
  114. cmGrPlObjTypeId_t objTypeId = kRectGrPlId;
  115. cmReal_t x = top->begSmpIdx;
  116. cmReal_t y = -1.0;
  117. cmReal_t w = top->durSmpCnt;
  118. cmReal_t h = 2.0;
  119. const cmChar_t* label = top->name;
  120. unsigned flags = kNoDragGrPlFl;
  121. bool pedalFl = false;
  122. cmGrVExt_t wext;
  123. cmGrVExtSetNull(&wext);
  124. // convert cmTlUiMsg_t into parameters for a call to cmGrPlotObjCreate().
  125. switch( top->typeId )
  126. {
  127. case kMidiFileTlId:
  128. {
  129. vwIdx = kMidiVwIdx;
  130. y = 0;
  131. h = 127;
  132. flags |= kNoFillGrPlFl | kNoSelectGrPlFl;
  133. cmGrVExtSet(&wext,0,0,top->durSmpCnt,h);
  134. if( parentObjId != cmInvalidId )
  135. xAnchorObjH = cmGrPlotObjectIdToHandle( plH, parentObjId );
  136. //printf("midi file id:%i x:%f y:%f w:%f h:%f %s\n",m->objId,x,y,w,h,cmStringNullGuard(label));
  137. }
  138. break;
  139. case kMidiEvtTlId:
  140. {
  141. mep = _cmdIf->tlMidiEvtObjPtr(top);
  142. vwIdx = kMidiVwIdx;
  143. y = 127; // all non-note-on msg's get put to the top of the display
  144. h = 1;
  145. w = 100; // arbitrary msg duration
  146. xAnchorObjH = cmGrPlotObjectIdToHandle( plH, parentObjId );
  147. parentObjH = cmGrPlotObjectIdToHandle( plH, mep->midiFileObjId );
  148. assert( cmHandlesAreNotEqual(xAnchorObjH,cmGrPlObjNullHandle) );
  149. assert( cmHandlesAreNotEqual(parentObjH,cmGrPlObjNullHandle) );
  150. const cmMidiTrackMsg_t* mtm = mep->msg;
  151. cmMidiByte_t status = mtm->status;
  152. if( cmMidiIsNoteOn(status) )
  153. {
  154. y = mtm->u.chMsgPtr->d0;
  155. w = top->durSmpCnt;
  156. label = cmMidiToSciPitch(mtm->u.chMsgPtr->d0,NULL,0);
  157. }
  158. else
  159. {
  160. if( cmMidiIsSustainPedalDown(status,mtm->u.chMsgPtr->d0,mtm->u.chMsgPtr->d1) )
  161. {
  162. y = 64;
  163. w = top->durSmpCnt;
  164. flags += kNoFillGrPlFl;
  165. label = "Pedal";
  166. pedalFl= true;
  167. }
  168. else
  169. {
  170. if( status == kMetaStId )
  171. label = cmMidiMetaStatusToLabel(mtm->metaId);
  172. else
  173. label = cmMidiStatusToLabel(status);
  174. }
  175. }
  176. }
  177. break;
  178. case kAudioFileTlId:
  179. afp = _cmdIf->tlAudioFileObjPtr(top);
  180. if( parentObjId != cmInvalidId )
  181. xAnchorObjH = cmGrPlotObjectIdToHandle( plH, parentObjId );
  182. cmGrVExtSet(&wext,0,-1,top->durSmpCnt,h);
  183. //printf("audio file id:%i x:%f y:%f w:%f h:%f %s\n",m->objId,x,y,w,h,cmStringNullGuard(label));
  184. break;
  185. case kAudioEvtTlId:
  186. objTypeId = kVLineGrPlId;
  187. break;
  188. case kMarkerTlId:
  189. if( _cmdIf->tlMarkerObjPtr(top)->typeId == kMidiOnsetMarkTlId )
  190. vwIdx = kMidiVwIdx;
  191. objTypeId = kVLineGrPlId;
  192. xAnchorObjH = cmGrPlotObjectIdToHandle( plH, parentObjId );
  193. //flags |= kNoFillGrPlFl | kBorderSelGrPlFl | kNoFocusGrPlFl;
  194. w = 0;
  195. break;
  196. default:
  197. { assert(0); }
  198. }
  199. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, vwIdx );
  200. cmGrH_t cvH = cmGrViewGrHandle( vwH );
  201. //const cmChar_t* anchLabel = cmHandlesAreEqual(xAnchorObjH,cmGrPlObjNullHandle) ? NULL : cmGrPlotObjLabel(xAnchorObjH);
  202. //const cmChar_t* parentLabel = cmHandlesAreEqual(parentObjH,cmGrPlObjNullHandle) ? NULL : cmGrPlotObjLabel(parentObjH);
  203. //printf("type:%i id:%i x:%f y:%f w:%f h:%f %s parent:%s xachor:%s\n",m->typeId,m->objId,x,y,w,h,cmStringNullGuard(label),cmStringNullGuard(parentLabel),cmStringNullGuard(anchLabel));
  204. // Create the object
  205. if( cmGrPlotObjCreate(plH, cvH, &objH, m->objId, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags, x, y, w, h, label, cmGrVExtIsNull(&wext)?NULL:&wext ) != kOkGrPlRC )
  206. {
  207. cmErrMsg(&_err,kInsertObjFailRC,"Insert failed on the object labelled '%s'.", cmStringNullGuard(top->name));
  208. return;
  209. }
  210. // set the plot obj's user arg. to be the time line element pointer
  211. cmGrPlotObjSetUserPtr(objH,(void*)top);
  212. // if the sequence is changing then invalidate the currently selected marker object
  213. if( m->seqId != _curSeqId )
  214. {
  215. _curSeqId = m->seqId;
  216. _selMarkPlotObjH = cmGrPlObjNullHandle;
  217. }
  218. // Modify the objects attributes
  219. if( cmGrPlotObjIsValid(objH) )
  220. {
  221. switch( top->typeId )
  222. {
  223. case kMidiEvtTlId:
  224. cmGrPlotObjSetFontSize(objH,9);
  225. if( pedalFl )
  226. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, kGreenGrId );
  227. else
  228. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, cmGrPlotObjFillColor(objH,kEnablePlGrId) );
  229. _setMidiEventLabels(objH,_getMenuCheckFlags());
  230. break;
  231. case kAudioFileTlId:
  232. if( afp->fn != NULL )
  233. _cmdIf->audioFileLoad(afp->fn,m->objId);
  234. break;
  235. case kMarkerTlId:
  236. {
  237. cmGrColor_t color = kBlackGrId;
  238. const cmTlMarker_t* mop = _cmdIf->tlMarkerObjPtr(top);
  239. switch( mop->typeId)
  240. {
  241. case kAudioMarkTlId:
  242. {
  243. unsigned n = cmGrColorMapEleCount( cvH, kGrDefaultColorMapId );
  244. unsigned ci = _markCnt++ % n;
  245. color = cmGrColorMap(cvH,kGrDefaultColorMapId)[ci];
  246. }
  247. break;
  248. case kAudioOnsetMarkTlId:
  249. color = kDarkRedGrId;
  250. break;
  251. case kMidiOnsetMarkTlId:
  252. color = kDarkBlueGrId;
  253. break;
  254. default:
  255. { assert(0); }
  256. }
  257. cmGrPlotObjSetLabelAttr( objH, kNorthJsGrFl | kWestJsGrFl | kTopJsGrFl | kRightJsGrFl, 0, color );
  258. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, color );;
  259. cmGrPlotObjSetPhysExt(objH, 1, 0, 1, 0 );
  260. // create the marker end indicator
  261. objH = cmGrPlObjNullHandle;
  262. if( cmGrPlotObjCreate(plH, cvH, &objH, cmInvalidId, parentObjH, xAnchorObjH, yAnchorObjH, objTypeId, flags | kNoSelectGrPlFl, x+top->durSmpCnt, y, w, h, "", NULL ) != kOkGrPlRC )
  263. cmErrMsg(&_err,kInsertObjFailRC,"Insert failed ending marker line labelled '%s'.", cmStringNullGuard(top->name));
  264. else
  265. cmGrPlotObjSetLineColor( objH, kEnablePlGrId, color );
  266. }
  267. break;
  268. default:
  269. break;
  270. }
  271. }
  272. }
  273. cmTlUiMsgTypeId_t cmGrTlFltk::recvTimeLineMsg( const void* msg, unsigned msgByteCnt )
  274. {
  275. cmTlUiMsg_t m;
  276. cmTimeLineDecode(msg,msgByteCnt,&m);
  277. switch( m.msgId )
  278. {
  279. case kInitMsgTlId:
  280. {
  281. // remove all objects from all views
  282. cmGrPageClear(pageHandle());
  283. _srate = m.srate;
  284. _updateSeqMenu(m.seqCnt,m.seqId);
  285. }
  286. break;
  287. case kDoneMsgTlId:
  288. //size(w(),h()+1);
  289. break;
  290. case kFinalMsgTlId:
  291. break;
  292. case kInsertMsgTlId:
  293. _insertTimeLineObj(&m);
  294. break;
  295. default:
  296. { assert(0); }
  297. }
  298. return m.msgId;
  299. }
  300. void cmGrTlFltk::recvAudioFileLoad( unsigned fileId )
  301. {
  302. cmGrPlH_t plH = plotHandle();
  303. cmGrPlObjH_t grPlObjH = cmGrPlotObjectIdToHandle( plH, fileId );
  304. cmAfmFileH_t afH = _cmdIf->audioFileHandle( fileId );
  305. unsigned chIdx = 0;
  306. if( cmAfmFileIsValid(afH) == false )
  307. {
  308. cmErrMsg(&_err,kAudioObjFailRC,"Unable to locate audio file plot graphic object for id:%i.", fileId);
  309. return;
  310. }
  311. if( cmGrPlotAudioFileObjCreate( grPlObjH, afH, chIdx ) != kOkGrPlRC )
  312. {
  313. const cmChar_t* audioFn = cmAudioFileName(cmAfmFileHandle(afH));
  314. cmErrMsg(&_err,kAudioObjFailRC,"Create audio file graphic object failed for '%s'.", cmStringNullGuard(audioFn));
  315. return;
  316. }
  317. redraw();
  318. }
  319. void cmGrTlFltk::setTimeAxisMetric( timeAxisMetricId_t metricId )
  320. {
  321. unsigned timeLabelFuncId = cmInvalidId;
  322. switch( metricId )
  323. {
  324. case kSamplesMetricId: timeLabelFuncId = _samplesMetricId; break;
  325. case kSecondsMetricId: timeLabelFuncId = _secondsMetricId; break;
  326. default:
  327. { assert(0); }
  328. }
  329. cmGrPgH_t pgH = pageHandle();
  330. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, kAudioVwIdx);
  331. cmGrAxH_t axH = cmGrViewAxisHandle( vwH, kTopGrIdx);
  332. cmGrViewSetLabelFunc( vwH, kTopGrIdx, timeLabelFuncId );
  333. cmGrAxisSetLabelFunc( axH, timeLabelFuncId );
  334. vwH = cmGrPageViewHandle( pgH, kMidiVwIdx);
  335. axH = cmGrViewAxisHandle( vwH, kBottomGrIdx);
  336. cmGrViewSetLabelFunc( vwH, kBottomGrIdx, timeLabelFuncId );
  337. cmGrAxisSetLabelFunc( axH, timeLabelFuncId );
  338. }
  339. void cmGrTlFltk::toggleMarkerText()
  340. {
  341. cmGrPlH_t plH = plotHandle();
  342. unsigned n = cmGrPlotObjectCount(plH);
  343. unsigned i;
  344. for(i=0; i<n; ++i)
  345. {
  346. cmGrPlObjH_t poH = cmGrPlotObjectIndexToHandle(plH,i);
  347. if( cmGrPlotObjIsValid(poH) )
  348. cmGrPlotObjTogCfgFlags(poH,kNoLabelGrPlFl);
  349. }
  350. redraw();
  351. }
  352. unsigned cmGrTlFltk::timeLineSelectedMarkerId() const
  353. {
  354. const cmTlObj_t* top;
  355. if( cmGrPlotObjIsValid(_selMarkPlotObjH)
  356. && cmIsFlag(cmGrPlotObjStateFlags(_selMarkPlotObjH),kSelectGrPlFl)
  357. && (top = (const cmTlObj_t*)cmGrPlotObjUserPtr(_selMarkPlotObjH)) != NULL
  358. && (top->typeId==kMarkerTlId || top->typeId==kMidiEvtTlId) )
  359. {
  360. return top->uid;
  361. }
  362. return cmInvalidId;
  363. }
  364. void cmGrTlFltk::setAudioFileCursor( unsigned smpIdx )
  365. {
  366. if( cmGrPlotObjIsValid(_selMarkPlotObjH) )
  367. {
  368. cmGrPlObjH_t poh;
  369. // get the audio file plot object handle
  370. if(cmGrPlotObjIsValid(poh = cmGrPlotObjXAnchor(_selMarkPlotObjH)))
  371. {
  372. cmGrVExt_t vext;
  373. cmGrVPt_t pt0,pt1;
  374. // get the canvas handle
  375. cmGrPgH_t pgH = pageHandle();
  376. cmGrVwH_t vwH = cmGrPageViewHandle( pgH, kAudioVwIdx );
  377. cmGrH_t cvH = cmGrViewGrHandle( vwH );
  378. cmGrPlotObjVExt(poh,&vext); // get the extents of the audio file object
  379. smpIdx += vext.loc.x; // offset the current sample index to put the index in global time
  380. cmGrViewExtents(cvH, &vext ); // get the current view extents
  381. cmGrVPtSet(&pt0,smpIdx,cmGrVExtMinY(&vext)); // setup the selection points
  382. cmGrVPtSet(&pt1,smpIdx,cmGrVExtMaxY(&vext));
  383. cmGrSetSelectPoints(cvH, &pt0, &pt1 ); // apply the selection points to form a cursor line
  384. }
  385. }
  386. }
  387. void cmGrTlFltk::selectBar( unsigned barNumb )
  388. {
  389. cmGrPlH_t plH = plotHandle();
  390. unsigned n = cmGrPlotObjectCount(plH);
  391. unsigned i;
  392. for(i=0; i<n; ++i)
  393. {
  394. cmGrPlObjH_t poH = cmGrPlotObjectIndexToHandle(plH,i);
  395. const cmTlMarker_t* mkp;
  396. const cmTlObj_t* top;
  397. if( cmGrPlotObjIsValid(poH)
  398. && (top = (const cmTlObj_t*)cmGrPlotObjUserPtr(poH)) != NULL
  399. && top->typeId == kMarkerTlId
  400. && (mkp = _cmdIf->tlMarkerObjPtr(top)) != NULL
  401. && mkp->bar == barNumb ) // <-------- there is an apparent weakness in selecting a marker based
  402. { // only on the bar number - because the intention is to pick a
  403. // bar line marker but it may be (i have not actually checked)
  404. // that other objects might have a given bar number but not be
  405. // a bar line object.
  406. unsigned flags = cmGrPlotObjStateFlags(poH);
  407. cmGrPlotObjSetStateFlags(poH,cmSetFlag(flags,kFocusGrPlFl | kSelectGrPlFl));
  408. redraw();
  409. _selMarkPlotObjH = poH;
  410. _cmdIf->onTimeLineMarkerSelected(mkp->obj.uid);
  411. }
  412. }
  413. }
  414. bool cmGrTlFltk::on_plot_object( cmGrPlotCbArg_t* arg )
  415. {
  416. if( arg->selId==kStateChangeGrPlId
  417. && cmIsFlag(arg->deltaFlags,kSelectGrPlFl)
  418. && cmIsFlag(cmGrPlotObjStateFlags(arg->objH),kSelectGrPlFl) )
  419. {
  420. const cmTlObj_t* top;
  421. if((top = (const cmTlObj_t*)cmGrPlotObjUserPtr(arg->objH)) != NULL)
  422. {
  423. const cmChar_t* s = NULL;
  424. switch(top->typeId)
  425. {
  426. case kAudioFileTlId:
  427. {
  428. const cmTlAudioFile_t* afp;
  429. if((afp = _cmdIf->tlAudioFileObjPtr(top)) != NULL && afp->fn != NULL)
  430. s = afp->fn;
  431. }
  432. break;
  433. case kMidiFileTlId:
  434. {
  435. const cmTlMidiFile_t* mfp;
  436. if((mfp = _cmdIf->tlMidiFileObjPtr(top)) != NULL && mfp->fn != NULL)
  437. s = mfp->fn;
  438. }
  439. break;
  440. case kMidiEvtTlId:
  441. {
  442. const cmTlMidiEvt_t* mep;
  443. if((mep = _cmdIf->tlMidiEvtObjPtr(top)) != NULL )
  444. {
  445. _selMarkPlotObjH = arg->objH;
  446. callback()(this,user_data());
  447. _cmdIf->onTimeLineMidiEvtSelected(mep->obj.uid);
  448. }
  449. }
  450. break;
  451. case kMarkerTlId:
  452. {
  453. const cmTlMarker_t* mkp;
  454. if((mkp = _cmdIf->tlMarkerObjPtr(top)) != NULL)
  455. {
  456. if(mkp->text != NULL)
  457. s = mkp->text;
  458. _selMarkPlotObjH = arg->objH;
  459. callback()(this,user_data());
  460. _cmdIf->onTimeLineMarkerSelected(mkp->obj.uid);
  461. }
  462. }
  463. break;
  464. default:
  465. break;
  466. }
  467. if( s == NULL )
  468. s = cmGrPlotObjLabel(arg->objH);
  469. if( s == NULL )
  470. s = "";
  471. setStatusText(s);
  472. }
  473. }
  474. return true;
  475. }
  476. void cmGrTlFltk::_s_seqMenuCallback( Fl_Widget* w, void* vp )
  477. {
  478. item_t* ip = (item_t*)vp;
  479. assert( ip->id < ip->p->_seqCnt );
  480. ip->p->_cmdIf->selectSequence(ip->id);
  481. }
  482. void cmGrTlFltk::_s_roundHashValueFunc( void* arg, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value )
  483. {
  484. snprintf(label,labelCharCnt,"%i",(int)round(value));
  485. }
  486. void cmGrTlFltk::_s_minSecMsHashValueFunc( void* arg, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value )
  487. {
  488. cmGrTlFltk* p = (cmGrTlFltk*)arg;
  489. int min=0,sec=0,ms=0;
  490. double smpPerMin = p->_srate * 60.0;
  491. double smpPerMs = p->_srate / 1000.0;
  492. if( value > smpPerMin )
  493. {
  494. min = (int)floor( value / smpPerMin );
  495. value -= min * smpPerMin;
  496. }
  497. if( value > p->_srate )
  498. {
  499. sec = (int)floor( value / p->_srate );
  500. value -= sec * p->_srate;
  501. }
  502. if( value > smpPerMs )
  503. {
  504. ms = (int)floor( value / smpPerMs );
  505. value -= ms * smpPerMs;
  506. }
  507. snprintf(label,labelCharCnt,"%i:%2i:%2i",min,sec,ms);
  508. }
  509. void cmGrTlFltk::_s_midiSciPitchValueFunc( void* arg, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value )
  510. {
  511. assert( label != NULL && labelCharCnt > 0 );
  512. if( labelCharCnt > 0 )
  513. label[0] = 0;
  514. if( 0 <= value && value <= 127 )
  515. cmMidiToSciPitch((cmMidiByte_t)floor(value), label, labelCharCnt );
  516. else
  517. {
  518. if( labelCharCnt > 3 )
  519. strcpy(label,"?");
  520. }
  521. }
  522. void cmGrTlFltk::_updateSeqMenu(int newSeqCnt, unsigned seqId)
  523. {
  524. if(_seqMenuIdx == -1 )
  525. return;
  526. //const Fl_Menu_Item* seq_mip = _menuBar->menu() + _seqMenuIdx;
  527. //int sz = seq_mip->size();
  528. // if the count of time-line sequences does not match the new count of sequences
  529. if( 1 /*sz != newSeqCnt*/ )
  530. {
  531. int i;
  532. // erase the current sequence sub-menu
  533. _menuBar->clear_submenu(_seqMenuIdx);
  534. // create an array to link the menu items to the sequence control id's
  535. _seqItemArray = cmMemResizeZ(item_t,_seqItemArray,newSeqCnt);
  536. // create each menu items and item map record
  537. for(i=0; i<newSeqCnt; ++i)
  538. {
  539. _seqItemArray[i].id = i;
  540. _seqItemArray[i].p = this;
  541. _menuBar->insert(_seqMenuIdx + i + 1,cmTsPrintf("%i",i),0,_s_seqMenuCallback,_seqItemArray+i,FL_MENU_TOGGLE);
  542. }
  543. }
  544. // set the menu check boxes to indicate the selected sequence
  545. int i;
  546. for(i=0; i<newSeqCnt; ++i)
  547. {
  548. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + _seqMenuIdx + i + 1;
  549. if( i == (int)seqId )
  550. mip->set();
  551. else
  552. mip->clear();
  553. }
  554. // track the current sequence count
  555. _seqCnt = newSeqCnt;
  556. }
  557. void cmGrTlFltk::_createMenu( )
  558. {
  559. _seqMenuIdx = _menuBar->add("Seq", 0,NULL,0,FL_SUBMENU);
  560. int idx = _menuBar->add("Time Line",0,NULL,0,FL_SUBMENU);
  561. const char* titleArray[] = { "Samples", "Seconds", "Marker Text", "Pitch", "Velocity","Id", "Gen Onset","Del Onset" };
  562. bool checkFl[] = { false, false, false, true, true, true, false, false };
  563. bool onFl[] = { false, false, false, true, false, false, false, false };
  564. int i;
  565. for(i=0; i<kMenuItemCnt; ++i)
  566. {
  567. int flag = checkFl[i] ? FL_MENU_TOGGLE : 0;
  568. _menuArray[i].id = i;
  569. _menuArray[i].p = this;
  570. _menuBar->insert(idx+1+i,titleArray[i],0,_s_menuCallback, _menuArray + i, flag );
  571. if( onFl[i] )
  572. {
  573. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + idx + i + 1;
  574. mip->set();
  575. }
  576. }
  577. }
  578. bool cmGrTlFltk::_isMenuChecked( int id )
  579. {
  580. unsigned i;
  581. // locate the menu item assoc'd with id
  582. for(i=0; i<kMenuItemCnt; ++i)
  583. if( _menuArray[i].id == id )
  584. break;
  585. assert( i < kMenuItemCnt );
  586. int menuIdx;
  587. if(( menuIdx = _menuBar->find_index("Time Line")) == -1 )
  588. return false;
  589. // The menu items and _menuArray[] were initialized in the same order
  590. // therefore the offset from the base of both should be the same.
  591. Fl_Menu_Item* mip = (Fl_Menu_Item*)_menuBar->menu() + menuIdx + i + 1;
  592. assert( (item_t*)mip->user_data() == _menuArray + i );
  593. return mip->value() != 0;
  594. }
  595. unsigned cmGrTlFltk::_getMenuCheckFlags()
  596. {
  597. unsigned flags = 0;
  598. flags |= _isMenuChecked(kViewPitchMId) ? kPitchChkFl : 0;
  599. flags |= _isMenuChecked(kViewVelocityMId) ? kVelChkFl : 0;
  600. flags |= _isMenuChecked(kViewIdMId) ? kIdChkFl : 0;
  601. return flags;
  602. }
  603. void cmGrTlFltk::_setLabels()
  604. {
  605. cmGrPlH_t plH = plotHandle();
  606. unsigned flags = _getMenuCheckFlags();
  607. unsigned n = cmGrPlotObjectCount(plH);
  608. unsigned i;
  609. for(i=0; i<n; ++i)
  610. {
  611. cmGrPlObjH_t poH = cmGrPlotObjectIndexToHandle(plH,i);
  612. _setMidiEventLabels(poH,flags);
  613. }
  614. }
  615. void cmGrTlFltk::_setMidiEventLabels( cmGrPlObjH_t poH, unsigned flags)
  616. {
  617. cmTlObj_t* top;
  618. if( cmGrPlotObjIsValid(poH) && (top = (cmTlObj_t*)cmGrPlotObjUserPtr(poH))!=NULL && top->typeId==kMidiEvtTlId )
  619. {
  620. const cmMidiTrackMsg_t* mep = ((const cmTlMidiEvt_t*)top)->msg;
  621. if( mep->status == kNoteOnMdId )
  622. {
  623. int bufN = 255;
  624. cmChar_t buf[ bufN+1 ];
  625. buf[bufN] = 0;
  626. buf[0] = 0;
  627. if( cmIsFlag(flags,kPitchChkFl) )
  628. snprintf(buf+strlen(buf),bufN-strlen(buf),"%s ",cmMidiToSciPitch(mep->u.chMsgPtr->d0,NULL,0));
  629. if( cmIsFlag(flags,kVelChkFl) )
  630. snprintf(buf+strlen(buf),bufN-strlen(buf),"%i ",mep->u.chMsgPtr->d1);
  631. if( cmIsFlag(flags,kIdChkFl) )
  632. snprintf(buf+strlen(buf),bufN-strlen(buf),"%i ",mep->uid);
  633. cmGrPlotObjSetLabel(poH, buf );
  634. }
  635. }
  636. }
  637. void cmGrTlFltk::_s_menuCallback(Fl_Widget* w, void* arg )
  638. {
  639. item_t* ip = (item_t*)arg;
  640. cmGrTlFltk* p = ip->p;
  641. unsigned long id = ip->id;
  642. switch( id )
  643. {
  644. case kViewSamplesMId:
  645. case kViewSecondsMId:
  646. {
  647. cmGrTlFltk::timeAxisMetricId_t metricId = id==kViewSamplesMId ? cmGrTlFltk::kSamplesMetricId : cmGrTlFltk::kSecondsMetricId;
  648. p->setTimeAxisMetric( metricId );
  649. p->redraw();
  650. }
  651. break;
  652. case kViewMarkTextMId:
  653. p->toggleMarkerText();
  654. break;
  655. case kViewVelocityMId:
  656. case kViewPitchMId:
  657. case kViewIdMId:
  658. p->_setLabels();
  659. p->redraw();
  660. break;
  661. case kGenOnsetMarksMId:
  662. p->_cmdIf->generateOnsetMarks();
  663. break;
  664. case kDelOnsetMarksMId:
  665. p->_cmdIf->deleteOnsetMarks();
  666. break;
  667. }
  668. }