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.

cmdIf.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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 "cmPrefix.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 "cmThread.h"
  18. #include "cmText.h"
  19. #include "cmFileSys.h"
  20. #include "cmJson.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 "cmTimeLine.h"
  28. #include "cmScore.h"
  29. #include "cmProcObj.h"
  30. #include "cmProc4.h"
  31. #include "cmAudioFileMgr.h"
  32. #include "cmdIf.h"
  33. #include <sstream>
  34. //-------------------------------------------------------------------------------------
  35. //-------------------------------------------------------------------------------------
  36. //-------------------------------------------------------------------------------------
  37. cmdIf::cmdIf( cmCtx_t* ctx, cmdIfRspdr* rspdr, const cmChar_t* audioPath )
  38. : _ctx(ctx),_thH(cmThreadNullHandle),
  39. _cmdQueH(cmTs1p1cNullHandle),_outQueH(cmTs1p1cNullHandle),
  40. _tlH(cmTimeLineNullHandle),_afmH(cmAfmNullHandle),_scH(cmScNullHandle),
  41. _afPath(NULL),_rspdr(rspdr),_curSeqId(cmInvalidId)
  42. {
  43. cmErrSetup(&_err,&ctx->rpt,"cmdIf");
  44. cmAfmCreate(ctx,&_afmH);
  45. cmThreadCreate( &_thH, _thFunc, this, &ctx->rpt );
  46. cmTs1p1cCreate( &_cmdQueH, 4*64536, NULL, NULL, &_ctx->rpt );
  47. cmTs1p1cCreate( &_outQueH, 4*64536, NULL, NULL, &_ctx->rpt );
  48. if( audioPath != NULL )
  49. setAudioFilePath(audioPath);
  50. }
  51. cmdIf::~cmdIf()
  52. {
  53. cmThreadDestroy( &_thH ); // stop the thread to prevent interfering with que release
  54. _releaseQue(&_cmdQueH);
  55. _releaseQue(&_outQueH);
  56. cmTimeLineFinalize(&_tlH);
  57. cmAfmDestroy(&_afmH);
  58. cmScoreFinalize(&_scH);
  59. cmMemFree(_afPath);
  60. }
  61. cmdIf::rc_t cmdIf::open( const cmChar_t* fn )
  62. { return _sendCmd(kOpenCmdId,0,fn); }
  63. cmdIf::rc_t cmdIf::close( )
  64. { return _sendCmd(kCloseCmdId); }
  65. const cmChar_t* cmdIf::tlFileName() const
  66. {
  67. if( cmTimeLineIsValid(_tlH) == false )
  68. return NULL;
  69. return cmTimeLineFileName(_tlH);
  70. }
  71. const cmTlMidiFile_t* cmdIf::tlMidiFileObjPtr( const cmTlObj_t* op ) const
  72. { return cmTimeLineMidiFileObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
  73. const cmTlAudioFile_t* cmdIf::tlAudioFileObjPtr( const cmTlObj_t* op ) const
  74. { return cmTimeLineAudioFileObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
  75. const cmTlMidiEvt_t* cmdIf::tlMidiEvtObjPtr( const cmTlObj_t* op ) const
  76. { return cmTimeLineMidiEvtObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
  77. const cmTlAudioEvt_t* cmdIf::tlAudioEvtObjPtr( const cmTlObj_t* op ) const
  78. { return cmTimeLineAudioEvtObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
  79. const cmTlMarker_t* cmdIf::tlMarkerObjPtr( const cmTlObj_t* op ) const
  80. { return cmTimeLineMarkerObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
  81. const cmChar_t* cmdIf::scoreFileName() const
  82. {
  83. if( cmScoreIsValid(_scH) == false )
  84. return NULL;
  85. return cmScoreFileName(_scH);
  86. }
  87. const cmScoreEvt_t* cmdIf::scoreEventIdToPtr( unsigned scEvtId ) const
  88. {
  89. if( cmScoreIsValid(_scH)==false )
  90. return NULL;
  91. return cmScoreEvt(_scH,scEvtId);
  92. }
  93. const cmScoreSection_t* cmdIf::scoreSectionIdToPtr( unsigned scSectId ) const
  94. {
  95. if( cmScoreIsValid(_scH)==false)
  96. return NULL;
  97. return cmScoreSection(_scH,scSectId);
  98. }
  99. const cmTlObj_t* cmdIf::tlObjIdToPtr( unsigned tlObjId ) const
  100. { return cmTlIdToObjPtr( _tlH, tlObjId ); }
  101. cmdIf::rc_t cmdIf::selectSequence( unsigned id )
  102. { return _sendCmd(kSelectSeqCmdId,id); }
  103. cmdIf::rc_t cmdIf::audioFileLoad( const cmChar_t* fn, unsigned appFileId )
  104. {
  105. const cmChar_t* afFn = fn;
  106. //cmFileSysPathPart_t* pp = NULL ;
  107. /*
  108. if( _afPath != NULL )
  109. {
  110. pp = cmFsPathParts(fn);
  111. afFn = cmFsMakeFn(_afPath,pp->fnStr,pp->extStr,NULL);
  112. }
  113. */
  114. rc_t rc = _sendCmd(kAfLoadCmdId,appFileId,afFn);
  115. /*
  116. if( _afPath != NULL )
  117. {
  118. cmFsFreeFn(afFn);
  119. cmFsFreePathParts(pp);
  120. }
  121. */
  122. return rc;
  123. }
  124. cmAfmFileH_t cmdIf::audioFileHandle( unsigned appFileId )
  125. { return cmAfmIdToHandle(_afmH,appFileId); }
  126. void cmdIf::setAudioFilePath( const cmChar_t* path )
  127. { _afPath = cmMemResizeStr(_afPath,path); }
  128. cmdIf::rc_t cmdIf::setScore( const cmChar_t* scoreFn )
  129. { return _sendCmd(kScoreCmdId,0,scoreFn); }
  130. void cmdIf::setScoreLocation( unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel )
  131. {
  132. cmScoreSetPerfEvent(_scH,locIdx,smpIdx,pitch,vel);
  133. }
  134. void cmdIf::setScoreVarValue( unsigned locIdx, unsigned varId, double value )
  135. {
  136. cmScoreSetPerfValue(_scH,locIdx,varId,value);
  137. }
  138. void cmdIf::setScoreDynLevel( unsigned evtIdx, unsigned dynLvl )
  139. {
  140. cmScoreSetPerfDynLevel(_scH,evtIdx,dynLvl);
  141. }
  142. void cmdIf::onTimeLineMarkerSelected( unsigned markerTlId )
  143. {
  144. if( _rspdr != NULL )
  145. _rspdr->cmdIfOnTimeLineMarkerSelect(markerTlId);
  146. _onTimeLineObjSelected(markerTlId);
  147. }
  148. void cmdIf::onTimeLineMidiEvtSelected( unsigned midiEvtTlId )
  149. {
  150. if( _rspdr != NULL )
  151. _rspdr->cmdIfOnTimeLineMidiEvtSelect(midiEvtTlId);
  152. _onTimeLineObjSelected(midiEvtTlId);
  153. }
  154. void cmdIf::onScoreBarSelected( unsigned scoreIdx )
  155. {
  156. if( cmScoreIsValid(_scH) )
  157. cmScoreClearPerfInfo(_scH);
  158. if( _rspdr != NULL )
  159. _rspdr->cmdIfOnScoreBarSelect(scoreIdx);
  160. }
  161. cmdIf::rc_t cmdIf::generateOnsetMarks()
  162. { return _sendCmd( kGenOnsetMarksCmdId); }
  163. cmdIf::rc_t cmdIf::deleteOnsetMarks()
  164. { return _sendCmd( kDelOnsetMarksCmdId); }
  165. bool cmdIf::isBusy() const
  166. { return cmThreadIsValid(_thH) && cmThreadState(_thH)==kRunningThId; }
  167. void cmdIf::onIdle()
  168. {
  169. if( !cmTs1p1cIsValid(_outQueH) )
  170. return;
  171. // pick up msg's sent from the worker thread
  172. while( cmTs1p1cMsgWaiting(_outQueH) )
  173. {
  174. cmd_t c;
  175. cmThRC_t thRC;
  176. if((thRC = cmTs1p1cDequeueMsg(_outQueH,&c,sizeof(c))) != kOkThRC )
  177. {
  178. _thErrorMsg("Deque response failed.");
  179. continue;
  180. }
  181. //printf("deq th->app id:%i val:%i n:%i msg:%p\n",c.id,c.value,c.byteCnt,c.u.msg);
  182. switch( c.id )
  183. {
  184. // the worker thread is busy - show a modal progress window
  185. case kShowStatusCmdId:
  186. _rspdr->cmdIfShowStatusMsg(c.u.string);
  187. break;
  188. // the worker thread is idle - remove the modal progress window
  189. case kHideStatusCmdId:
  190. _rspdr->cmdIfHideStatus();
  191. break;
  192. // report an error which occured during a worker thread operation
  193. case kErrMsgCmdId:
  194. _rspdr->cmdIfErrorMsg(c.u.string);
  195. break;
  196. // send a msg to the time-line UI
  197. case kTimeLineMsgCmdId:
  198. _rspdr->cmdIfTimeLineMsg(c.u.msg,c.byteCnt);
  199. break;
  200. case kAfLoadCmdId:
  201. _rspdr->cmdIfAudioFileLoad(c.value);
  202. break;
  203. case kScoreMsgCmdId:
  204. _rspdr->cmdIfScoreMsg(c.u.msg,c.byteCnt);
  205. break;
  206. default:
  207. break;
  208. }
  209. if( c.byteCnt )
  210. {
  211. cmMemFree(c.u.msg);
  212. }
  213. }
  214. }
  215. //----------------------------------------------------------------------------------------
  216. // App Thread Functions
  217. //----------------------------------------------------------------------------------------
  218. cmdIf::rc_t cmdIf::_sendCmd( cmdId_t id, unsigned value, const char* str )
  219. {
  220. rc_t rc;
  221. if((rc = _enqueue( _cmdQueH, id, value, str, str==NULL ? 0 : strlen(str)+1 )) == kOkRC )
  222. cmThreadPause(_thH, 0 );
  223. else
  224. {
  225. cmErrMsg(&_err,kCmdEnqueueFailRC,"Command enque failed.");
  226. }
  227. return rc;
  228. }
  229. void cmdIf::_releaseQue( cmTs1p1cH_t* queHPtr )
  230. {
  231. while( cmTs1p1cMsgWaiting(*queHPtr) )
  232. {
  233. cmd_t c;
  234. cmThRC_t thRC;
  235. if((thRC = cmTs1p1cDequeueMsg(*queHPtr,&c,sizeof(c))) != kOkThRC )
  236. {
  237. // TODO: PRINT ERROR MSG HERE USING APP THREAD ERROR HANDLER
  238. //_thErrorMsg("Deque command failed during queue draining.");
  239. continue;
  240. }
  241. if( c.byteCnt )
  242. cmMemFree(c.u.msg);
  243. }
  244. cmTs1p1cDestroy(queHPtr);
  245. }
  246. //----------------------------------------------------------------------------------------
  247. // Worker Thread Functions
  248. //----------------------------------------------------------------------------------------
  249. bool cmdIf::_thFunc( void* arg )
  250. {
  251. cmdIf* p = (cmdIf*)arg;
  252. while( cmTs1p1cMsgWaiting(p->_cmdQueH) )
  253. {
  254. cmd_t c;
  255. cmThRC_t thRC;
  256. if((thRC = cmTs1p1cDequeueMsg(p->_cmdQueH,&c,sizeof(c))) != kOkThRC )
  257. {
  258. p->_thErrorMsg("Deque command failed.");
  259. continue;
  260. }
  261. switch(c.id )
  262. {
  263. case kOpenCmdId:
  264. p->_thDoOpen(&c);
  265. break;
  266. case kCloseCmdId:
  267. p->_thDoClose(&c);
  268. break;
  269. case kSelectSeqCmdId:
  270. p->_thDoSelectSeq(&c);
  271. break;
  272. case kAfLoadCmdId:
  273. p->_thDoAfLoad(&c);
  274. break;
  275. case kScoreCmdId:
  276. p->_thDoScore(&c);
  277. break;
  278. case kGenOnsetMarksCmdId:
  279. p->_thDoGenOnsetMarks(&c);
  280. break;
  281. case kDelOnsetMarksCmdId:
  282. p->_thDoDelOnsetMarks(&c);
  283. break;
  284. default:
  285. break;
  286. }
  287. if( c.byteCnt )
  288. cmMemFree(c.u.msg);
  289. }
  290. cmThreadPause( p->_thH, kPauseThFl );
  291. return true;
  292. }
  293. //void cmdIfRptFunc( void* user, const cmChar_t* text )
  294. //{ printf("%s",text); }
  295. void cmdIf::_thDoOpen( const cmd_t* cmd )
  296. {
  297. _thStatusMsg("Loading: '%s'",cmd->u.string);
  298. if( cmTimeLineInitializeFromFile(_ctx,&_tlH,_thSendTimeLineMsg,this,cmd->u.string,_afPath) != kOkTlRC )
  299. _thErrorMsg("Load failed on '%s'.",cmd->u.string);
  300. else
  301. {
  302. _curSeqId = 0;
  303. // Make notification callbacks for all time line records to _thSendTimeLineMsg()
  304. // _thSendTimeLineMsg() then enqueues msg's into _outQueH which are picked
  305. // up by the idle handler
  306. cmTimeLineSeqNotify(_tlH,_curSeqId);
  307. }
  308. _thSendResponse(kHideStatusCmdId);
  309. }
  310. void cmdIf::_thDoClose( const cmd_t* cmd )
  311. {
  312. _thStatusMsg("Closing ... ");
  313. if( cmTimeLineFinalize(&_tlH) != kOkTlRC )
  314. {
  315. _thErrorMsg("Time line finalize failed.");
  316. }
  317. _thSendResponse(kHideStatusCmdId);
  318. }
  319. void cmdIf::_thDoSelectSeq( const cmd_t* cmd )
  320. {
  321. _thStatusMsg("Selecting Sequence:%i ",cmd->value);
  322. _curSeqId = cmInvalidId;
  323. if( cmTimeLineSeqNotify(_tlH,cmd->value) != kOkTlRC )
  324. _thErrorMsg("Sequence selection failed.");
  325. else
  326. _curSeqId = cmd->value;
  327. _thSendResponse(kHideStatusCmdId);
  328. }
  329. void cmdIf::_thDoAfLoad( const cmd_t* cmd )
  330. {
  331. _thStatusMsg("Loading Audio File: '%s'",cmd->u.string);
  332. cmAfmFileH_t afH = cmAfmFileNullHandle;
  333. if( cmAfmFileOpen(_afmH,&afH,cmd->u.string, cmd->value, NULL ) != kOkAfmRC )
  334. _thErrorMsg("Audio file load failed on '%s'.",cmd->u.string);
  335. else
  336. {
  337. double msPerSummaryPt = 50.0;
  338. unsigned samplesPerSummaryPt = (unsigned)floor(cmAfmFileInfo(afH)->srate * msPerSummaryPt / 1000.0);
  339. if( cmAfmFileSummarize(afH,samplesPerSummaryPt) != kOkAfmRC )
  340. _thErrorMsg("Audio file summarization failed on '%s'.",cmd->u.string);
  341. else
  342. _thSendResponse(kAfLoadCmdId,cmd->u.string,cmd->value);
  343. }
  344. _thSendResponse(kHideStatusCmdId);
  345. }
  346. void cmdIf::_thDoScore( const cmd_t* cmd )
  347. {
  348. _thStatusMsg("Loading Score File: '%s'",cmd->u.string);
  349. if( cmScoreInitialize(_ctx,&_scH,cmd->u.string,0,NULL,0,_thSendScoreMsg,this,cmSymTblNullHandle) != kOkScRC )
  350. _thErrorMsg("Score open failed on '%s'.",cmStringNullGuard(cmd->u.string));
  351. else
  352. {
  353. // Make notification callbacks for all score records to _thSendScoreMsg()
  354. // _thSendScoreMsg() then enqueues msg's into _outQueH which are picked
  355. // up by the idle handler
  356. cmScoreSeqNotify(_scH);
  357. }
  358. _thSendResponse(kHideStatusCmdId);
  359. }
  360. void cmdIf::_thDoGenOnsetMarks( const cmd_t* cmd )
  361. {
  362. if( !cmTimeLineIsValid(_tlH) )
  363. return;
  364. _thStatusMsg("Generating Onset Markers.");
  365. // makes notification callbacks to _thSendTimeLineMsg()
  366. if( cmTimeLineGenOnsetMarks(_tlH,_curSeqId) != kOkTlRC )
  367. _thErrorMsg("Onset marker generation failed.");
  368. else
  369. cmTimeLineSeqNotify(_tlH,_curSeqId);
  370. _thSendResponse(kHideStatusCmdId);
  371. }
  372. void cmdIf::_thDoDelOnsetMarks( const cmd_t* cmd )
  373. {
  374. if( !cmTimeLineIsValid(_tlH) )
  375. return;
  376. _thStatusMsg("Deleting Onset Markers.");
  377. // makes notification callbacks to _thSendTimeLineMsg()
  378. if( cmTimeLineDeleteOnsetMarks(_tlH,_curSeqId) != kOkTlRC )
  379. _thErrorMsg("Onset marker deletion failed.");
  380. _thSendResponse(kHideStatusCmdId);
  381. }
  382. /*
  383. void cmdIf::_thErrorMsg( const char* fmt, va_list vl )
  384. {
  385. const cmChar_t* s = cmTsVPrintf(fmt,vl);
  386. _thSendResponse(kErrMsgCmdId,s);
  387. cmTsFreeStr(s);
  388. }
  389. */
  390. void cmdIf::_thErrorMsg( const char* fmt, ... )
  391. {
  392. va_list vl,vl1;
  393. va_start(vl,fmt);
  394. va_copy(vl1,vl);
  395. int n = vsnprintf(NULL,0,fmt,vl);
  396. char b[n+1];
  397. vsnprintf(b,n+1,fmt,vl1);
  398. _thSendResponse(kErrMsgCmdId,b);
  399. va_end(vl1);
  400. va_end(vl);
  401. }
  402. /*
  403. void cmdIf::_thStatusMsg( const char* fmt, va_list vl )
  404. {
  405. const cmChar_t* s = cmTsVPrintf(fmt,vl);
  406. _thSendResponse(kShowStatusCmdId,s);
  407. cmTsFreeStr(s);
  408. }
  409. */
  410. void cmdIf::_thStatusMsg( const char* fmt, ... )
  411. {
  412. va_list vl,vl1;
  413. va_start(vl,fmt);
  414. va_copy(vl1,vl);
  415. int n = vsnprintf(NULL,0,fmt,vl);
  416. char b[n+1];
  417. vsnprintf(b,n+1,fmt,vl1);
  418. _thSendResponse(kShowStatusCmdId,b);
  419. va_end(vl1);
  420. va_end(vl);
  421. }
  422. void cmdIf::_thSendResponse( cmdId_t id, const char* str, unsigned value )
  423. {
  424. if( _enqueue( _outQueH, id, value, str, str==NULL ? 0 : strlen(str)+1 ) != kOkRC )
  425. {
  426. _thErrorMsg("Response send failed.");
  427. }
  428. }
  429. void cmdIf::_thSendTimeLineMsg( void* arg, const void* msg, unsigned byteCnt )
  430. {
  431. cmdIf* p = (cmdIf*)arg;
  432. if( cmTs1p1cIsValid( p->_outQueH ) )
  433. if( p->_enqueue( p->_outQueH, kTimeLineMsgCmdId, 0, msg, byteCnt ) != kOkRC )
  434. p->_thErrorMsg("Time Line enqueue failed on response queue.");
  435. }
  436. void cmdIf::_thSendScoreMsg( void* arg, const void* msg, unsigned byteCnt )
  437. {
  438. cmdIf* p = (cmdIf*)arg;
  439. if( cmTs1p1cIsValid( p->_outQueH ) )
  440. if( p->_enqueue( p->_outQueH, kScoreMsgCmdId, 0, msg, byteCnt ) != kOkRC )
  441. p->_thErrorMsg("Score msg enqueue failed on response queue.");
  442. }
  443. //----------------------------------------------------------------------------------------
  444. // Thread Independent Functions
  445. //----------------------------------------------------------------------------------------
  446. cmdIf::rc_t cmdIf::_enqueue( cmTs1p1cH_t qH, cmdId_t id, unsigned value, const void* data, unsigned byteCnt )
  447. {
  448. cmThRC_t thRC;
  449. rc_t rc = kOkRC;
  450. cmd_t c;
  451. assert( (byteCnt==0 && data==NULL) || (byteCnt!=0 && data!=NULL) );
  452. c.id = id;
  453. c.byteCnt = byteCnt;
  454. c.value = value;
  455. c.u.msg = NULL;
  456. if( byteCnt )
  457. {
  458. // memory allocated here must be deleted after the record is dequeued
  459. c.u.string = cmMemAlloc(char,byteCnt);
  460. memcpy(c.u.msg,data,byteCnt);
  461. }
  462. //printf("enq %s id:%i n:%i msg:%p\n", cmHandlesAreEqual(qH,_outQueH) ? "thr->app" : "app->thr", c.id,c.byteCnt,c.u.string);
  463. if((thRC = cmTs1p1cEnqueueMsg(qH,&c,sizeof(c))) != kOkThRC )
  464. {
  465. if( byteCnt )
  466. cmMemFree(c.u.string);
  467. rc = kCmdFailRC;
  468. }
  469. return rc;
  470. }
  471. //----------------------------------------------------------------------------------------
  472. void cmdIf::_onTimeLineObjSelected( unsigned tlObjId )
  473. {
  474. const cmTlObj_t* mop;
  475. if((mop = cmTimeLineIdToObj(_tlH,cmInvalidId,tlObjId)) == NULL )
  476. {
  477. cmErrMsg(&_err,kCmdFailRC,"Unexpected invalid time line marker id '%i'.",tlObjId);
  478. return;
  479. }
  480. const cmTlAudioFile_t* afp = cmTimeLineAudioFileAtTime(_tlH, mop->seqId, mop->seqSmpIdx );
  481. const cmTlMidiFile_t* mfp = cmTimeLineMidiFileAtTime( _tlH, mop->seqId, mop->seqSmpIdx );
  482. const cmTlMidiEvt_t* mep = cmTimeLineMidiEvtAtTime( _tlH, mop->seqId, mop->seqSmpIdx );
  483. if( afp != NULL )
  484. printf("%s\n",afp->fn);
  485. if( mfp != NULL )
  486. printf("%s : %i\n",mfp->fn,mop->seqSmpIdx);
  487. if( mep != NULL )
  488. {
  489. if( mep->msg->status == kNoteOnMdId )
  490. printf("%s : %i\n",cmMidiToSciPitch(mep->msg->u.chMsgPtr->d0,NULL,0),mep->obj.seqSmpIdx);
  491. else
  492. printf("midi:%i\n",mep->msg->status);
  493. }
  494. }
  495. //----------------------------------------------------------------------------------------
  496. void cmdIf::testStub()
  497. {
  498. //ed_main();
  499. //cmScAlignScanMarkers(_err.rpt, _tlH, _scH );
  500. //sc_main(_scH,_tlH);
  501. cmScorePrintLoc(_scH);
  502. }