//| Copyright: (C) 2019-2020 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #ifndef cmdIf_h #define cmdIf_h class Fl_Output; // This class allows the 'model' to run independently // from the user interface. This eliminates problems with // application unresponsiveness which would arise from // executing compute intensive operations from UI control or // menu callback functions. It also allows a progress // or status bar to be shown while the model operation // is in progress. // The class works by enqueueing all incoming commands // into a thread-safe queue. An internal worker thread // executes the commands in the order they are received // and thereby changes the state of the model. // The results of model changes are posted to a second // thread-safe queue. These responses are picked // up by the onIdle() member and dispatched to an // object with a cmIfRspdr interface. Note that because // the onIdle() function is called from the applications // idle handler the callbacks to the cmIfRspdr are // always in the application thread and can therefore // safely interact with any application data constructs. // All calls to this object and all callbacks from it, // therefore occur in the application thread. class cmdIfRspdr { public: virtual ~cmdIfRspdr(){} virtual void cmdIfShowStatusMsg( const char* msg ) = 0; virtual void cmdIfHideStatus() = 0; virtual void cmdIfErrorMsg( const char* msg ) = 0; virtual void cmdIfTimeLineMsg( const void* msg, unsigned msgByteCnt ) = 0; virtual void cmdIfAudioFileLoad( unsigned fileId ) = 0; virtual void cmdIfScoreMsg( const void* msg, unsigned msgByteCnt ) = 0; virtual void cmdIfOnTimeLineMarkerSelect( unsigned markerId ) = 0; virtual void cmdIfOnTimeLineMidiEvtSelect(unsigned midiEvtId ) = 0; virtual void cmdIfOnScoreBarSelect( unsigned scoreIndex ) = 0; }; class cmdIf { public: typedef enum { kOkRC, kCmdFailRC, kCmdEnqueueFailRC } rc_t; cmdIf( cmCtx_t* ctx, cmdIfRspdr* rspdr, const cmChar_t* audioPath=NULL ); virtual ~cmdIf(); // Open a time line. rc_t open( const cmChar_t* fn ); // Close the time line. rc_t close(); // Time line interface const cmChar_t* tlFileName() const; const cmTlObj_t* tlObjIdToPtr( unsigned tlObjId ) const; const cmTlMidiFile_t* tlMidiFileObjPtr( const cmTlObj_t* op ) const; const cmTlAudioFile_t* tlAudioFileObjPtr( const cmTlObj_t* op ) const; const cmTlMidiEvt_t* tlMidiEvtObjPtr( const cmTlObj_t* op ) const; const cmTlAudioEvt_t* tlAudioEvtObjPtr( const cmTlObj_t* op ) const; const cmTlMarker_t* tlMarkerObjPtr( const cmTlObj_t* op ) const; const cmChar_t* scoreFileName() const; const cmScoreEvt_t* scoreEventIdToPtr( unsigned scEvtId ) const; const cmScoreSection_t* scoreSectionIdToPtr( unsigned scSectId ) const; // Make a time line sequence active. rc_t selectSequence( unsigned id ); // Load an audio file into the audio file mgr. // If an audio file path was set via setAudioFilePath() then // the directories referenced by 'fn' will be replaced by // the previously set audio file path. rc_t audioFileLoad( const cmChar_t* fn, unsigned appFileId ); // Return the audio file handle assigned to appFileId. cmAfmFileH_t audioFileHandle( unsigned appFileId ); // Set the audio file location. void setAudioFilePath( const cmChar_t* path ); // Assign a score file rc_t setScore( const cmChar_t* scoreFn ); // Set the current score location void setScoreLocation( unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ); // Set the value of a score variable void setScoreVarValue( unsigned locIdx, unsigned varId, double value ); // Set the performed dynamic level of a score event. void setScoreDynLevel( unsigned evtIdx, unsigned dynLvl ); void onTimeLineMarkerSelected( unsigned markerTlId ); void onTimeLineMidiEvtSelected( unsigned midiEvtTlId ); void onScoreBarSelected( unsigned scoreIndex ); // Generate or delete Audio/MIDI onset markers. rc_t generateOnsetMarks(); rc_t deleteOnsetMarks(); // True if the worker thread is running. bool isBusy() const; // Called by the application to dequeue messages via callbacks to // the cmdIfRspdr. void onIdle(); void testStub(); private: // Id's used by cmd_t typedef enum { kInvalidCmdId, // 0 kOpenCmdId, // 1 app->thread kCloseCmdId, // 2 app->thread kSelectSeqCmdId, // 3 app->thread kAfLoadCmdId, // 4 app->thread and thread->app kScoreCmdId, // 5 app->thread kShowStatusCmdId, // 6 thread->app kHideStatusCmdId, // 7 thread->app kErrMsgCmdId, // 8 thread->app kTimeLineMsgCmdId, // 9 thread->app kScoreMsgCmdId, //10 thread->app kGenOnsetMarksCmdId, kDelOnsetMarksCmdId } cmdId_t; // Messages are passed between the app and the worker thread // and v.v. using this record format. Note that the u.msg // field is always dynamically allocated by _enqueue() // and must be released following the dequeue operation. typedef struct cmd_str { cmdId_t id; // cmdId unsigned byteCnt; // length of msg unsigned value; // msg value union { void* msg; // msg[byteCnt] char* string; // string[byteCnt] } u; } cmd_t; cmCtx_t* _ctx; // cmErr_t _err; // cmThreadH_t _thH; // worker thread cmTs1p1cH_t _cmdQueH; // app->model cmTs1p1cH_t _outQueH; // model->appl cmTlH_t _tlH; // time line handle cmAfmH_t _afmH; // audio file manager cmScH_t _scH; // score handle cmChar_t* _afPath; // cmdIfRspdr* _rspdr; // unsigned _curSeqId; // seqId of last selected sequence // Functions called from the app thread. rc_t _sendCmd( cmdId_t id, unsigned value=0, const char* str=NULL ); void _releaseQue( cmTs1p1cH_t* queHPtr ); // Functions called from the worker thread static bool _thFunc( void* arg ); void _thDoOpen( const cmd_t* cmd ); void _thDoClose( const cmd_t* cmd ); void _thDoSelectSeq( const cmd_t* cmd ); void _thDoAfLoad( const cmd_t* cmd ); void _thDoScore( const cmd_t* cmd ); void _thDoGenOnsetMarks( const cmd_t* cmd ); void _thDoDelOnsetMarks( const cmd_t* cmd ); //void _thErrorMsg( const char* fmt, va_list vl ); void _thErrorMsg( const char* fmt, ... ); //void _thStatusMsg( const char* fmt, va_list vl ); void _thStatusMsg( const char* fmt, ... ); void _thSendResponse( cmdId_t id, const char* str = NULL, unsigned value=0 ); static void _thSendTimeLineMsg( void* arg, const void* msg, unsigned byteCnt ); static void _thSendScoreMsg( void* arg, const void* msg, unsigned byteCnt ); // Thread independent functions rc_t _enqueue( cmTs1p1cH_t qH, cmdId_t id, unsigned value, const void* msg, unsigned msgByteCnt ); // Print context information for selected time line objects void _onTimeLineObjSelected( unsigned tlObjId ); }; #endif