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.

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