123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652 |
- //| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
- //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
- #include <FL/Fl.H>
- #include <FL/fl_draw.h>
- #include <FL/Fl_Widget.H>
- #include <FL/Fl_Double_Window.H>
- #include <Fl/Fl_Output.H>
-
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmFloatTypes.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmMallocDebug.h"
- #include "cmLinkedHeap.h"
- #include "cmThread.h"
- #include "cmText.h"
- #include "cmFileSys.h"
- #include "cmJson.h"
- #include "cmPrefs.h"
- #include "cmSymTbl.h"
- #include "cmTime.h"
- #include "cmMidi.h"
- #include "cmMidiFile.h"
- #include "cmAudioFile.h"
- #include "cmTimeLine.h"
-
- #include "cmScore.h"
-
- #include "cmProcObj.h"
- #include "cmProc4.h"
-
- #include "cmAudioFileMgr.h"
- #include "cmdIf.h"
-
- #include <sstream>
-
-
- //-------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------
-
- cmdIf::cmdIf( cmCtx_t* ctx, cmdIfRspdr* rspdr, const cmChar_t* audioPath )
- : _ctx(ctx),_thH(cmThreadNullHandle),
- _cmdQueH(cmTs1p1cNullHandle),_outQueH(cmTs1p1cNullHandle),
- _tlH(cmTimeLineNullHandle),_afmH(cmAfmNullHandle),_scH(cmScNullHandle),
- _afPath(NULL),_rspdr(rspdr),_curSeqId(cmInvalidId)
- {
- cmErrSetup(&_err,&ctx->rpt,"cmdIf");
-
- cmAfmCreate(ctx,&_afmH);
-
- cmThreadCreate( &_thH, _thFunc, this, &ctx->rpt );
- cmTs1p1cCreate( &_cmdQueH, 4*64536, NULL, NULL, &_ctx->rpt );
- cmTs1p1cCreate( &_outQueH, 4*64536, NULL, NULL, &_ctx->rpt );
-
- if( audioPath != NULL )
- setAudioFilePath(audioPath);
- }
-
- cmdIf::~cmdIf()
- {
- cmThreadDestroy( &_thH ); // stop the thread to prevent interfering with que release
- _releaseQue(&_cmdQueH);
- _releaseQue(&_outQueH);
- cmTimeLineFinalize(&_tlH);
- cmAfmDestroy(&_afmH);
- cmScoreFinalize(&_scH);
- cmMemFree(_afPath);
- }
-
- cmdIf::rc_t cmdIf::open( const cmChar_t* fn )
- { return _sendCmd(kOpenCmdId,0,fn); }
-
- cmdIf::rc_t cmdIf::close( )
- { return _sendCmd(kCloseCmdId); }
-
- const cmChar_t* cmdIf::tlFileName() const
- {
- if( cmTimeLineIsValid(_tlH) == false )
- return NULL;
-
- return cmTimeLineFileName(_tlH);
- }
-
- const cmTlMidiFile_t* cmdIf::tlMidiFileObjPtr( const cmTlObj_t* op ) const
- { return cmTimeLineMidiFileObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
-
- const cmTlAudioFile_t* cmdIf::tlAudioFileObjPtr( const cmTlObj_t* op ) const
- { return cmTimeLineAudioFileObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
-
- const cmTlMidiEvt_t* cmdIf::tlMidiEvtObjPtr( const cmTlObj_t* op ) const
-
- { return cmTimeLineMidiEvtObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
-
- const cmTlAudioEvt_t* cmdIf::tlAudioEvtObjPtr( const cmTlObj_t* op ) const
- { return cmTimeLineAudioEvtObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
-
- const cmTlMarker_t* cmdIf::tlMarkerObjPtr( const cmTlObj_t* op ) const
- { return cmTimeLineMarkerObjPtr(_tlH,const_cast<cmTlObj_t*>(op)); }
-
-
- const cmChar_t* cmdIf::scoreFileName() const
- {
- if( cmScoreIsValid(_scH) == false )
- return NULL;
- return cmScoreFileName(_scH);
- }
-
- const cmScoreEvt_t* cmdIf::scoreEventIdToPtr( unsigned scEvtId ) const
- {
- if( cmScoreIsValid(_scH)==false )
- return NULL;
- return cmScoreEvt(_scH,scEvtId);
- }
-
- const cmScoreSection_t* cmdIf::scoreSectionIdToPtr( unsigned scSectId ) const
- {
- if( cmScoreIsValid(_scH)==false)
- return NULL;
- return cmScoreSection(_scH,scSectId);
- }
-
-
-
- const cmTlObj_t* cmdIf::tlObjIdToPtr( unsigned tlObjId ) const
- { return cmTlIdToObjPtr( _tlH, tlObjId ); }
-
-
- cmdIf::rc_t cmdIf::selectSequence( unsigned id )
- { return _sendCmd(kSelectSeqCmdId,id); }
-
-
- cmdIf::rc_t cmdIf::audioFileLoad( const cmChar_t* fn, unsigned appFileId )
- {
- const cmChar_t* afFn = fn;
- //cmFileSysPathPart_t* pp = NULL ;
-
- /*
- if( _afPath != NULL )
- {
- pp = cmFsPathParts(fn);
- afFn = cmFsMakeFn(_afPath,pp->fnStr,pp->extStr,NULL);
- }
- */
-
- rc_t rc = _sendCmd(kAfLoadCmdId,appFileId,afFn);
-
- /*
- if( _afPath != NULL )
- {
- cmFsFreeFn(afFn);
- cmFsFreePathParts(pp);
- }
- */
-
- return rc;
- }
-
- cmAfmFileH_t cmdIf::audioFileHandle( unsigned appFileId )
- { return cmAfmIdToHandle(_afmH,appFileId); }
-
- void cmdIf::setAudioFilePath( const cmChar_t* path )
- { _afPath = cmMemResizeStr(_afPath,path); }
-
- cmdIf::rc_t cmdIf::setScore( const cmChar_t* scoreFn )
- { return _sendCmd(kScoreCmdId,0,scoreFn); }
-
- void cmdIf::setScoreLocation( unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel )
- {
- cmScoreSetPerfEvent(_scH,locIdx,smpIdx,pitch,vel);
- }
-
- void cmdIf::setScoreVarValue( unsigned locIdx, unsigned varId, double value )
- {
- cmScoreSetPerfValue(_scH,locIdx,varId,value);
- }
-
- void cmdIf::setScoreDynLevel( unsigned evtIdx, unsigned dynLvl )
- {
- cmScoreSetPerfDynLevel(_scH,evtIdx,dynLvl);
- }
-
-
- void cmdIf::onTimeLineMarkerSelected( unsigned markerTlId )
- {
- if( _rspdr != NULL )
- _rspdr->cmdIfOnTimeLineMarkerSelect(markerTlId);
-
- _onTimeLineObjSelected(markerTlId);
-
- }
-
- void cmdIf::onTimeLineMidiEvtSelected( unsigned midiEvtTlId )
- {
- if( _rspdr != NULL )
- _rspdr->cmdIfOnTimeLineMidiEvtSelect(midiEvtTlId);
-
- _onTimeLineObjSelected(midiEvtTlId);
- }
-
- void cmdIf::onScoreBarSelected( unsigned scoreIdx )
- {
- if( cmScoreIsValid(_scH) )
- cmScoreClearPerfInfo(_scH);
-
- if( _rspdr != NULL )
- _rspdr->cmdIfOnScoreBarSelect(scoreIdx);
-
- }
-
- cmdIf::rc_t cmdIf::generateOnsetMarks()
- { return _sendCmd( kGenOnsetMarksCmdId); }
-
- cmdIf::rc_t cmdIf::deleteOnsetMarks()
- { return _sendCmd( kDelOnsetMarksCmdId); }
-
-
- bool cmdIf::isBusy() const
- { return cmThreadIsValid(_thH) && cmThreadState(_thH)==kRunningThId; }
-
- void cmdIf::onIdle()
- {
- if( !cmTs1p1cIsValid(_outQueH) )
- return;
-
- // pick up msg's sent from the worker thread
- while( cmTs1p1cMsgWaiting(_outQueH) )
- {
- cmd_t c;
- cmThRC_t thRC;
-
- if((thRC = cmTs1p1cDequeueMsg(_outQueH,&c,sizeof(c))) != kOkThRC )
- {
- _thErrorMsg("Deque response failed.");
- continue;
- }
-
- //printf("deq th->app id:%i val:%i n:%i msg:%p\n",c.id,c.value,c.byteCnt,c.u.msg);
-
- switch( c.id )
- {
- // the worker thread is busy - show a modal progress window
- case kShowStatusCmdId:
- _rspdr->cmdIfShowStatusMsg(c.u.string);
- break;
-
- // the worker thread is idle - remove the modal progress window
- case kHideStatusCmdId:
- _rspdr->cmdIfHideStatus();
- break;
-
- // report an error which occured during a worker thread operation
- case kErrMsgCmdId:
- _rspdr->cmdIfErrorMsg(c.u.string);
- break;
-
- // send a msg to the time-line UI
- case kTimeLineMsgCmdId:
- _rspdr->cmdIfTimeLineMsg(c.u.msg,c.byteCnt);
- break;
-
- case kAfLoadCmdId:
- _rspdr->cmdIfAudioFileLoad(c.value);
- break;
-
- case kScoreMsgCmdId:
- _rspdr->cmdIfScoreMsg(c.u.msg,c.byteCnt);
- break;
-
- default:
- break;
- }
-
- if( c.byteCnt )
- {
- cmMemFree(c.u.msg);
- }
- }
- }
-
- //----------------------------------------------------------------------------------------
- // App Thread Functions
- //----------------------------------------------------------------------------------------
-
- cmdIf::rc_t cmdIf::_sendCmd( cmdId_t id, unsigned value, const char* str )
- {
- rc_t rc;
- if((rc = _enqueue( _cmdQueH, id, value, str, str==NULL ? 0 : strlen(str)+1 )) == kOkRC )
- cmThreadPause(_thH, 0 );
- else
- {
- cmErrMsg(&_err,kCmdEnqueueFailRC,"Command enque failed.");
- }
-
- return rc;
- }
-
- void cmdIf::_releaseQue( cmTs1p1cH_t* queHPtr )
- {
-
- while( cmTs1p1cMsgWaiting(*queHPtr) )
- {
- cmd_t c;
- cmThRC_t thRC;
-
- if((thRC = cmTs1p1cDequeueMsg(*queHPtr,&c,sizeof(c))) != kOkThRC )
- {
- // TODO: PRINT ERROR MSG HERE USING APP THREAD ERROR HANDLER
- //_thErrorMsg("Deque command failed during queue draining.");
- continue;
- }
-
-
- if( c.byteCnt )
- cmMemFree(c.u.msg);
-
- }
-
- cmTs1p1cDestroy(queHPtr);
-
- }
-
- //----------------------------------------------------------------------------------------
- // Worker Thread Functions
- //----------------------------------------------------------------------------------------
- bool cmdIf::_thFunc( void* arg )
- {
- cmdIf* p = (cmdIf*)arg;
-
- while( cmTs1p1cMsgWaiting(p->_cmdQueH) )
- {
- cmd_t c;
- cmThRC_t thRC;
-
- if((thRC = cmTs1p1cDequeueMsg(p->_cmdQueH,&c,sizeof(c))) != kOkThRC )
- {
- p->_thErrorMsg("Deque command failed.");
- continue;
- }
-
- switch(c.id )
- {
- case kOpenCmdId:
- p->_thDoOpen(&c);
- break;
-
- case kCloseCmdId:
- p->_thDoClose(&c);
- break;
-
- case kSelectSeqCmdId:
- p->_thDoSelectSeq(&c);
- break;
-
- case kAfLoadCmdId:
- p->_thDoAfLoad(&c);
- break;
-
- case kScoreCmdId:
- p->_thDoScore(&c);
- break;
-
- case kGenOnsetMarksCmdId:
- p->_thDoGenOnsetMarks(&c);
- break;
-
- case kDelOnsetMarksCmdId:
- p->_thDoDelOnsetMarks(&c);
- break;
-
- default:
- break;
- }
-
- if( c.byteCnt )
- cmMemFree(c.u.msg);
-
- }
-
-
- cmThreadPause( p->_thH, kPauseThFl );
-
- return true;
- }
-
- //void cmdIfRptFunc( void* user, const cmChar_t* text )
- //{ printf("%s",text); }
-
- void cmdIf::_thDoOpen( const cmd_t* cmd )
- {
- _thStatusMsg("Loading: '%s'",cmd->u.string);
-
- if( cmTimeLineInitializeFromFile(_ctx,&_tlH,_thSendTimeLineMsg,this,cmd->u.string,_afPath) != kOkTlRC )
- _thErrorMsg("Load failed on '%s'.",cmd->u.string);
- else
- {
- _curSeqId = 0;
-
- // Make notification callbacks for all time line records to _thSendTimeLineMsg()
- // _thSendTimeLineMsg() then enqueues msg's into _outQueH which are picked
- // up by the idle handler
- cmTimeLineSeqNotify(_tlH,_curSeqId);
- }
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoClose( const cmd_t* cmd )
- {
- _thStatusMsg("Closing ... ");
-
- if( cmTimeLineFinalize(&_tlH) != kOkTlRC )
- {
- _thErrorMsg("Time line finalize failed.");
- }
-
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoSelectSeq( const cmd_t* cmd )
- {
- _thStatusMsg("Selecting Sequence:%i ",cmd->value);
-
- _curSeqId = cmInvalidId;
- if( cmTimeLineSeqNotify(_tlH,cmd->value) != kOkTlRC )
- _thErrorMsg("Sequence selection failed.");
- else
- _curSeqId = cmd->value;
-
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoAfLoad( const cmd_t* cmd )
- {
- _thStatusMsg("Loading Audio File: '%s'",cmd->u.string);
-
- cmAfmFileH_t afH = cmAfmFileNullHandle;
-
- if( cmAfmFileOpen(_afmH,&afH,cmd->u.string, cmd->value, NULL ) != kOkAfmRC )
- _thErrorMsg("Audio file load failed on '%s'.",cmd->u.string);
- else
- {
- double msPerSummaryPt = 50.0;
- unsigned samplesPerSummaryPt = (unsigned)floor(cmAfmFileInfo(afH)->srate * msPerSummaryPt / 1000.0);
-
- if( cmAfmFileSummarize(afH,samplesPerSummaryPt) != kOkAfmRC )
- _thErrorMsg("Audio file summarization failed on '%s'.",cmd->u.string);
- else
- _thSendResponse(kAfLoadCmdId,cmd->u.string,cmd->value);
- }
-
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoScore( const cmd_t* cmd )
- {
- _thStatusMsg("Loading Score File: '%s'",cmd->u.string);
-
- if( cmScoreInitialize(_ctx,&_scH,cmd->u.string,0,NULL,0,_thSendScoreMsg,this,cmSymTblNullHandle) != kOkScRC )
- _thErrorMsg("Score open failed on '%s'.",cmStringNullGuard(cmd->u.string));
- else
- {
- // Make notification callbacks for all score records to _thSendScoreMsg()
- // _thSendScoreMsg() then enqueues msg's into _outQueH which are picked
- // up by the idle handler
- cmScoreSeqNotify(_scH);
- }
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoGenOnsetMarks( const cmd_t* cmd )
- {
- if( !cmTimeLineIsValid(_tlH) )
- return;
-
- _thStatusMsg("Generating Onset Markers.");
-
- // makes notification callbacks to _thSendTimeLineMsg()
- if( cmTimeLineGenOnsetMarks(_tlH,_curSeqId) != kOkTlRC )
- _thErrorMsg("Onset marker generation failed.");
- else
- cmTimeLineSeqNotify(_tlH,_curSeqId);
-
- _thSendResponse(kHideStatusCmdId);
- }
-
- void cmdIf::_thDoDelOnsetMarks( const cmd_t* cmd )
- {
- if( !cmTimeLineIsValid(_tlH) )
- return;
-
- _thStatusMsg("Deleting Onset Markers.");
-
- // makes notification callbacks to _thSendTimeLineMsg()
- if( cmTimeLineDeleteOnsetMarks(_tlH,_curSeqId) != kOkTlRC )
- _thErrorMsg("Onset marker deletion failed.");
-
- _thSendResponse(kHideStatusCmdId);
- }
-
- /*
- void cmdIf::_thErrorMsg( const char* fmt, va_list vl )
- {
- const cmChar_t* s = cmTsVPrintf(fmt,vl);
- _thSendResponse(kErrMsgCmdId,s);
- cmTsFreeStr(s);
- }
- */
- void cmdIf::_thErrorMsg( const char* fmt, ... )
- {
- va_list vl,vl1;
- va_start(vl,fmt);
- va_copy(vl1,vl);
-
- int n = vsnprintf(NULL,0,fmt,vl);
- char b[n+1];
- vsnprintf(b,n+1,fmt,vl1);
- _thSendResponse(kErrMsgCmdId,b);
-
- va_end(vl1);
- va_end(vl);
- }
-
- /*
- void cmdIf::_thStatusMsg( const char* fmt, va_list vl )
- {
- const cmChar_t* s = cmTsVPrintf(fmt,vl);
- _thSendResponse(kShowStatusCmdId,s);
- cmTsFreeStr(s);
- }
- */
-
- void cmdIf::_thStatusMsg( const char* fmt, ... )
- {
- va_list vl,vl1;
- va_start(vl,fmt);
- va_copy(vl1,vl);
-
- int n = vsnprintf(NULL,0,fmt,vl);
- char b[n+1];
- vsnprintf(b,n+1,fmt,vl1);
- _thSendResponse(kShowStatusCmdId,b);
- va_end(vl1);
- va_end(vl);
- }
-
-
- void cmdIf::_thSendResponse( cmdId_t id, const char* str, unsigned value )
- {
- if( _enqueue( _outQueH, id, value, str, str==NULL ? 0 : strlen(str)+1 ) != kOkRC )
- {
- _thErrorMsg("Response send failed.");
- }
- }
-
- void cmdIf::_thSendTimeLineMsg( void* arg, const void* msg, unsigned byteCnt )
- {
- cmdIf* p = (cmdIf*)arg;
- if( cmTs1p1cIsValid( p->_outQueH ) )
- if( p->_enqueue( p->_outQueH, kTimeLineMsgCmdId, 0, msg, byteCnt ) != kOkRC )
- p->_thErrorMsg("Time Line enqueue failed on response queue.");
- }
-
- void cmdIf::_thSendScoreMsg( void* arg, const void* msg, unsigned byteCnt )
- {
- cmdIf* p = (cmdIf*)arg;
- if( cmTs1p1cIsValid( p->_outQueH ) )
- if( p->_enqueue( p->_outQueH, kScoreMsgCmdId, 0, msg, byteCnt ) != kOkRC )
- p->_thErrorMsg("Score msg enqueue failed on response queue.");
- }
-
-
- //----------------------------------------------------------------------------------------
- // Thread Independent Functions
- //----------------------------------------------------------------------------------------
-
-
- cmdIf::rc_t cmdIf::_enqueue( cmTs1p1cH_t qH, cmdId_t id, unsigned value, const void* data, unsigned byteCnt )
- {
- cmThRC_t thRC;
- rc_t rc = kOkRC;
- cmd_t c;
-
- assert( (byteCnt==0 && data==NULL) || (byteCnt!=0 && data!=NULL) );
-
- c.id = id;
- c.byteCnt = byteCnt;
- c.value = value;
- c.u.msg = NULL;
-
- if( byteCnt )
- {
- // memory allocated here must be deleted after the record is dequeued
- c.u.string = cmMemAlloc(char,byteCnt);
- memcpy(c.u.msg,data,byteCnt);
- }
-
- //printf("enq %s id:%i n:%i msg:%p\n", cmHandlesAreEqual(qH,_outQueH) ? "thr->app" : "app->thr", c.id,c.byteCnt,c.u.string);
-
- if((thRC = cmTs1p1cEnqueueMsg(qH,&c,sizeof(c))) != kOkThRC )
- {
- if( byteCnt )
- cmMemFree(c.u.string);
-
- rc = kCmdFailRC;
- }
-
- return rc;
- }
-
-
- //----------------------------------------------------------------------------------------
- void cmdIf::_onTimeLineObjSelected( unsigned tlObjId )
- {
- const cmTlObj_t* mop;
- if((mop = cmTimeLineIdToObj(_tlH,cmInvalidId,tlObjId)) == NULL )
- {
- cmErrMsg(&_err,kCmdFailRC,"Unexpected invalid time line marker id '%i'.",tlObjId);
- return;
- }
-
- const cmTlAudioFile_t* afp = cmTimeLineAudioFileAtTime(_tlH, mop->seqId, mop->seqSmpIdx );
- const cmTlMidiFile_t* mfp = cmTimeLineMidiFileAtTime( _tlH, mop->seqId, mop->seqSmpIdx );
- const cmTlMidiEvt_t* mep = cmTimeLineMidiEvtAtTime( _tlH, mop->seqId, mop->seqSmpIdx );
-
- if( afp != NULL )
- printf("%s\n",afp->fn);
-
- if( mfp != NULL )
- printf("%s : %i\n",mfp->fn,mop->seqSmpIdx);
-
- if( mep != NULL )
- {
- if( mep->msg->status == kNoteOnMdId )
- printf("%s : %i\n",cmMidiToSciPitch(mep->msg->u.chMsgPtr->d0,NULL,0),mep->obj.seqSmpIdx);
- else
- printf("midi:%i\n",mep->msg->status);
- }
- }
-
- //----------------------------------------------------------------------------------------
- void cmdIf::testStub()
- {
- //ed_main();
- //cmScAlignScanMarkers(_err.rpt, _tlH, _scH );
- //sc_main(_scH,_tlH);
- cmScorePrintLoc(_scH);
- }
-
|