diff --git a/app/cmTimeLine.c b/app/cmTimeLine.c index 52ebaab..350985a 100644 --- a/app/cmTimeLine.c +++ b/app/cmTimeLine.c @@ -635,9 +635,9 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p, _cmTlObj_t* op, cmMidiFileH_t mfH ) unsigned mn = cmMidiFileMsgCount(mfH); const cmMidiTrackMsg_t** mapp = cmMidiFileMsgArray(mfH); unsigned mi = 0; - double accum = 0; + //double accum = 0; _cmTlObj_t* refOp = op; - bool fl = false; + //bool fl = false; unsigned dtick = 0; mfp->noteOnCnt = 0; @@ -649,16 +649,16 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p, _cmTlObj_t* op, cmMidiFileH_t mfH ) dtick = mp->dtick; - if( fl ) - { - dtick = 0; - fl = mp->dtick == 0; - } + //if( fl ) + //{ + // dtick = 0; + // fl = mp->dtick == 0; + //} - accum += dtick * p->srate / 1000000; + //accum += dtick * p->srate / 1000000; //int begSmpIdx = floor(accum_micros * p->srate / 1000000); - int begSmpIdx = floor( dtick * p->srate / 1000000 ); + int begSmpIdx = dtick; //floor( dtick * p->srate / 1000000.0 ); int durSmpCnt = 0; unsigned midiTrkMsgByteCnt = cmMidiFilePackTrackMsgBufByteCount( mp ); unsigned recdByteCnt = sizeof(cmTlMidiEvt_t) + midiTrkMsgByteCnt; @@ -669,7 +669,8 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p, _cmTlObj_t* op, cmMidiFileH_t mfH ) // count the note-on messages if( mp->status == kNoteOnMdId ) { - durSmpCnt = floor(mp->u.chMsgPtr->durTicks * p->srate / 1000000 ); + //durSmpCnt = floor(mp->u.chMsgPtr->durTicks * p->srate / 1000000.0 ); + durSmpCnt = mp->u.chMsgPtr->durTicks; ++mfp->noteOnCnt; } @@ -727,7 +728,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh unsigned durSmpCnt = floor(cmMidiFileDurSecs(mfH)*p->srate); // convert the midi file from ticks to microseconds - cmMidiFileTickToMicros(mfH); + cmMidiFileTickToSamples(mfH,p->srate,false); // assign note durations to all note-on msg's cmMidiFileCalcNoteDurations(mfH); @@ -957,6 +958,11 @@ double cmTimeLineSampleRate( cmTlH_t h ) return p->srate; } +int cmTimeLineSeqToLocalSampleIndex( int seqSmpIdx, cmTlObj_t* localObjPtr ) +{ + return seqSmpIdx - localObjPtr->seqSmpIdx; +} + cmTlObj_t* _cmTimeLineIdToObj( _cmTl_t* p, unsigned seqId, unsigned id ) { assert( seqId < p->seqCnt ); diff --git a/app/cmTimeLine.h b/app/cmTimeLine.h index e318a2c..5cdf8d6 100644 --- a/app/cmTimeLine.h +++ b/app/cmTimeLine.h @@ -111,6 +111,9 @@ extern "C" { bool cmTimeLineIsValid( cmTlH_t h ); double cmTimeLineSampleRate( cmTlH_t h ); + // Convert global (sequence) time to a time relative to an object. + int cmTimeLineSeqToLocalSampleIndex( int seqSmpIdx, cmTlObj_t* localObjPtr ); + // Given cmTlObj_t.uid return a pointer to the associated record. // seqId is optional (dflt:cmInvalidId) cmTlObj_t* cmTimeLineIdToObj( cmTlH_t h, unsigned seqId, unsigned uid ); @@ -152,6 +155,12 @@ extern "C" { cmTlMidiFile_t* cmTimeLineFindMidiFile( cmTlH_t h, const cmChar_t* fn ); + cmTlAudioFile_t* cmTimeLineAudioFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); + cmTlMidiFile_t* cmTimeLineMidiFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); + cmTlMidiEvt_t* cmTimeLineMidiEvtAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); + cmTlMarker_t* cmTimeLineMarkerAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); + + cmTlAudioFile_t* cmTimeLineAudioFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); cmTlMidiFile_t* cmTimeLineMidiFileAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); cmTlMidiEvt_t* cmTimeLineMidiEvtAtTime( cmTlH_t h, unsigned seqId, unsigned seqSmpIdx ); diff --git a/cmGrPlot.c b/cmGrPlot.c index 6b74955..c66b130 100644 --- a/cmGrPlot.c +++ b/cmGrPlot.c @@ -217,22 +217,32 @@ void _cmGrPlotObjSetFocus( cmGrPlotObj_t* op ) if( cmIsNotFlag(op->cfgFlags,kNoFocusGrPlFl) && cmIsNotFlag(op->cfgFlags,kNoDrawGrPlFl) ) break; - if( op != NULL ) + // if the focus is changing to a new object + if( op != NULL && op->p->fop != op ) { if( op->p->fop != NULL ) { // if the application callback returns false then do no release focus from the current object - if(_cmGrPlotObjCb(op->p->fop, kStateChangeGrPlId, kFocusGrPlFl ) == false ) + if(_cmGrPlotObjCb(op->p->fop, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false ) return; + cmGrPlotObj_t* fop = op->p->fop; + op->p->fop = NULL; + + // notify focus loser + _cmGrPlotObjCb(fop, kStateChangeGrPlId, kFocusGrPlFl ); } // if the application callback returns false then do not give focus to the selected object - if(_cmGrPlotObjCb(op, kStateChangeGrPlId, kFocusGrPlFl ) == false ) + if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kFocusGrPlFl ) == false ) return; op->p->fop = op; + + // notify focus winner + _cmGrPlotObjCb(op, kStateChangeGrPlId, kFocusGrPlFl ); + } } @@ -246,7 +256,7 @@ void _cmGrPlotObjSetSelect( cmGrPlotObj_t* op, bool clearFl ) unsigned stateFlags = op->stateFlags; // if the application callback returns false then do change the select state of the object - if(_cmGrPlotObjCb(op, kStateChangeGrPlId, kSelectGrPlFl ) == false ) + if(_cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kSelectGrPlFl ) == false ) return; if( clearFl ) @@ -262,6 +272,8 @@ void _cmGrPlotObjSetSelect( cmGrPlotObj_t* op, bool clearFl ) op->stateFlags = cmTogFlag(stateFlags,kSelectGrPlFl); + // notify state change + _cmGrPlotObjCb(op, kStateChangeGrPlId, kSelectGrPlFl ); } @@ -914,18 +926,22 @@ void cmGrPlotObjSetStateFlags( cmGrPlObjH_t oh, unsigned flags ) if( cmIsFlag(flags,kVisibleGrPlFl) != _cmGrPlotObjIsVisible(op) ) { - if( _cmGrPlotObjCb(op, kStateChangeGrPlId, kVisibleGrPlFl ) == false ) + if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kVisibleGrPlFl ) == false ) return; op->cfgFlags = cmTogFlag(op->cfgFlags,kNoDrawGrPlFl); + + _cmGrPlotObjCb(op, kStateChangeGrPlId, kVisibleGrPlFl ); } if( cmIsFlag(flags,kEnabledGrPlFl) != _cmGrPlotObjIsEnabled(op) ) { - if( _cmGrPlotObjCb(op, kStateChangeGrPlId, kEnabledGrPlFl ) == false ) + if( _cmGrPlotObjCb(op, kPreEventCbSelGrPlId, kEnabledGrPlFl ) == false ) return; op->stateFlags = cmTogFlag(op->cfgFlags,kEnabledGrPlFl); + + _cmGrPlotObjCb(op, kStateChangeGrPlId, kEnabledGrPlFl ); } bool fl; diff --git a/cmMidiFile.c b/cmMidiFile.c index f99a267..cf998a7 100644 --- a/cmMidiFile.c +++ b/cmMidiFile.c @@ -796,6 +796,30 @@ void cmMidiFileTickToMicros( cmMidiFileH_t h ) } +void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl ) +{ + _cmMidiFile_t* p; + unsigned mi; + //bool fl = true; + + if((p = _cmMidiFileHandleToPtr(h)) == NULL ) + return; + + cmMidiFileTickToMicros(h); + + unsigned absSmp = 0; + + for(mi=0; mimsgN; ++mi) + { + cmMidiTrackMsg_t* mp = p->msgV[mi]; + unsigned delta = floor((mp->dtick*srate)/1000000.0); + + mp->dtick = absFl ? absSmp : delta; + + absSmp += delta; + } +} + typedef struct _cmMidiVoice_str { const cmMidiTrackMsg_t* mp; diff --git a/cmMidiFile.h b/cmMidiFile.h index 40c1693..2a6e2d8 100644 --- a/cmMidiFile.h +++ b/cmMidiFile.h @@ -5,168 +5,172 @@ extern "C" { #endif -// MIDI file timing: -// Messages in the MIDI file are time tagged with a delta offset in 'ticks' -// from the previous message in the same track. -// -// A 'tick' can be converted to microsends as follows: -// -// microsecond per tick = micros per quarter note / ticks per quarter note -// -// MpT = MpQN / TpQN -// -// TpQN is given as a constant in the MIDI file header. -// MpQN is given as the value of the MIDI file tempo message. -// -// See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds. -// -// As part of the file reading process, the status byte of note-on messages -// with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg(). + // MIDI file timing: + // Messages in the MIDI file are time tagged with a delta offset in 'ticks' + // from the previous message in the same track. + // + // A 'tick' can be converted to microsends as follows: + // + // microsecond per tick = micros per quarter note / ticks per quarter note + // + // MpT = MpQN / TpQN + // + // TpQN is given as a constant in the MIDI file header. + // MpQN is given as the value of the MIDI file tempo message. + // + // See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds. + // + // As part of the file reading process, the status byte of note-on messages + // with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg(). -typedef cmHandle_t cmMidiFileH_t; -typedef unsigned cmMfRC_t; + typedef cmHandle_t cmMidiFileH_t; + typedef unsigned cmMfRC_t; -typedef struct -{ - cmMidiByte_t hr; - cmMidiByte_t min; - cmMidiByte_t sec; - cmMidiByte_t frm; - cmMidiByte_t sfr; -} cmMidiSmpte_t; - -typedef struct -{ - cmMidiByte_t num; - cmMidiByte_t den; - cmMidiByte_t metro; - cmMidiByte_t th2s; -} cmMidiTimeSig_t; - -typedef struct -{ - cmMidiByte_t key; - cmMidiByte_t scale; -} cmMidiKeySig_t; - -typedef struct -{ - cmMidiByte_t ch; - cmMidiByte_t d0; - cmMidiByte_t d1; - unsigned durTicks; // note duration calc'd by -} cmMidiChMsg_t; - - -typedef struct cmMidiTrackMsg_str -{ - unsigned dtick; // delta ticks - cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch) - cmMidiByte_t metaId; // - unsigned short trkIdx; // - unsigned byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union) - struct cmMidiTrackMsg_str* link; // link to next record in this track - - union + typedef struct { - cmMidiByte_t bVal; - unsigned iVal; - unsigned short sVal; - const char* text; - const void* voidPtr; - const cmMidiSmpte_t* smptePtr; - const cmMidiTimeSig_t* timeSigPtr; - const cmMidiKeySig_t* keySigPtr; - const cmMidiChMsg_t* chMsgPtr; - const cmMidiByte_t* sysExPtr; - } u; -} cmMidiTrackMsg_t; + cmMidiByte_t hr; + cmMidiByte_t min; + cmMidiByte_t sec; + cmMidiByte_t frm; + cmMidiByte_t sfr; + } cmMidiSmpte_t; -enum -{ - kOkMfRC = cmOkRC, // 0 - kSysFopenFailMfRC, // 1 - kSysFreadFailMfRC, // 2 - kSysFseekFailMfRC, // 3 - kSysFtellFailMfRC, // 4 - kSysFcloseFailMfRC, // 5 - kNotAMidiFileMfRC, // 6 - kMemAllocFailMfRC, // 7 - kFileCorruptMfRC, // 8 - kMissingEoxMfRC, // 9 - kUnknownMetaIdMfRC, // 10 - kInvalidHandleMfRC, // 11 - kMissingNoteOffMfRC, // 12 - kInvalidStatusMfRC // 13 -}; + typedef struct + { + cmMidiByte_t num; + cmMidiByte_t den; + cmMidiByte_t metro; + cmMidiByte_t th2s; + } cmMidiTimeSig_t; -extern cmMidiFileH_t cmMidiFileNullHandle; + typedef struct + { + cmMidiByte_t key; + cmMidiByte_t scale; + } cmMidiKeySig_t; -cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx ); -cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp ); + typedef struct + { + cmMidiByte_t ch; + cmMidiByte_t d0; + cmMidiByte_t d1; + unsigned durTicks; // note duration calc'd by + } cmMidiChMsg_t; -// Returns track count or kInvalidCnt if 'h' is invalid. -unsigned cmMidiFileTrackCount( cmMidiFileH_t h ); -// Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid. -unsigned cmMidiFileType( cmMidiFileH_t h ); + typedef struct cmMidiTrackMsg_str + { + unsigned dtick; // delta ticks + cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch) + cmMidiByte_t metaId; // + unsigned short trkIdx; // + unsigned byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union) + struct cmMidiTrackMsg_str* link; // link to next record in this track -// Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base. -unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h ); + union + { + cmMidiByte_t bVal; + unsigned iVal; + unsigned short sVal; + const char* text; + const void* voidPtr; + const cmMidiSmpte_t* smptePtr; + const cmMidiTimeSig_t* timeSigPtr; + const cmMidiKeySig_t* keySigPtr; + const cmMidiChMsg_t* chMsgPtr; + const cmMidiByte_t* sysExPtr; + } u; + } cmMidiTrackMsg_t; -// The file name used in an earlier call to midiFileOpen() or NULL if this -// midi file did not originate from an actual file. -const char* cmMidiFileName( cmMidiFileH_t h ); + enum + { + kOkMfRC = cmOkRC, // 0 + kSysFopenFailMfRC, // 1 + kSysFreadFailMfRC, // 2 + kSysFseekFailMfRC, // 3 + kSysFtellFailMfRC, // 4 + kSysFcloseFailMfRC, // 5 + kNotAMidiFileMfRC, // 6 + kMemAllocFailMfRC, // 7 + kFileCorruptMfRC, // 8 + kMissingEoxMfRC, // 9 + kUnknownMetaIdMfRC, // 10 + kInvalidHandleMfRC, // 11 + kMissingNoteOffMfRC, // 12 + kInvalidStatusMfRC // 13 + }; -// Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base. -cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h ); + extern cmMidiFileH_t cmMidiFileNullHandle; -// Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base. -cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h ); + cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx ); + cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp ); -// Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid. -unsigned cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx ); + // Returns track count or kInvalidCnt if 'h' is invalid. + unsigned cmMidiFileTrackCount( cmMidiFileH_t h ); -// Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid. -const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx ); + // Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid. + unsigned cmMidiFileType( cmMidiFileH_t h ); -// Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray(). -// Return kInvalidCnt if 'h' is invalid. -unsigned cmMidiFileMsgCount( cmMidiFileH_t h ); + // Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base. + unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h ); -// Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order. -// Returns NULL if 'h' is invalid. -const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h ); + // The file name used in an earlier call to midiFileOpen() or NULL if this + // midi file did not originate from an actual file. + const char* cmMidiFileName( cmMidiFileH_t h ); -// Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no -// msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning -// of the file. -// On return *'msgUsecsPtr' is set to the actual time of the msg. -// (which will be equal to or greater than 'usecsOffs'). -unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr ); + // Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base. + cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h ); -double cmMidiFileDurSecs( cmMidiFileH_t h ); + // Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base. + cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h ); -// Convert the track message 'dtick' field to delta-microseconds. -void cmMidiFileTickToMicros( cmMidiFileH_t h ); + // Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid. + unsigned cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx ); -// Calculate Note Duration -void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ); + // Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid. + const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx ); -// Set the delay prior to the first non-zero msg. -void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks ); + // Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray(). + // Return kInvalidCnt if 'h' is invalid. + unsigned cmMidiFileMsgCount( cmMidiFileH_t h ); -// This function packs a track msg into a single consecutive -// block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount() -// to get the required buffer length for any given cmMidiTrackMsg_t instance. -cmMidiTrackMsg_t* cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt ); -unsigned cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m ); + // Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order. + // Returns NULL if 'h' is invalid. + const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h ); -void cmMidiFilePrint( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt ); -bool cmMidiFileIsNull( cmMidiFileH_t h ); -void cmMidiFileTest( const char* fn, cmCtx_t* ctx ); + // Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no + // msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning + // of the file. + // On return *'msgUsecsPtr' is set to the actual time of the msg. + // (which will be equal to or greater than 'usecsOffs'). + unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr ); + + double cmMidiFileDurSecs( cmMidiFileH_t h ); + + // Convert the track message 'dtick' field to delta-microseconds. + void cmMidiFileTickToMicros( cmMidiFileH_t h ); + + // Convert the track message 'dtick' field to samples. + // If the absFl is set then the delta times are converted to absolute time. + void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl ); + + // Calculate Note Duration + void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ); + + // Set the delay prior to the first non-zero msg. + void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks ); + + // This function packs a track msg into a single consecutive + // block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount() + // to get the required buffer length for any given cmMidiTrackMsg_t instance. + cmMidiTrackMsg_t* cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt ); + unsigned cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m ); + + void cmMidiFilePrint( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt ); + bool cmMidiFileIsNull( cmMidiFileH_t h ); + void cmMidiFileTest( const char* fn, cmCtx_t* ctx ); #ifdef __cplusplus } diff --git a/dsp/cmDspBuiltIn.c b/dsp/cmDspBuiltIn.c index ed98d91..b09365b 100644 --- a/dsp/cmDspBuiltIn.c +++ b/dsp/cmDspBuiltIn.c @@ -1534,8 +1534,6 @@ cmDspInst_t* _cmDspTextAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned cmDspText_t* p = cmDspInstAlloc(cmDspText_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); - - // create the UI control cmDspUiTextCreate(ctx,&p->inst,kValTxId,kLblTxId); @@ -4993,6 +4991,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cmSegLineClassCons, cmTimeLineClassCons, + cmMidiFilePlayClassCons, NULL, }; diff --git a/dsp/cmDspClass.h b/dsp/cmDspClass.h index 919af7f..a0f7fff 100644 --- a/dsp/cmDspClass.h +++ b/dsp/cmDspClass.h @@ -392,7 +392,7 @@ extern "C" { cmDspRC_t cmDspUiMeterCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned minVarId, unsigned maxVarId, unsigned valVarId, unsigned lblVarId ); cmDspRC_t cmDspUiButtonCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned typeDuiId, unsigned outVarId, unsigned lblVarId ); cmDspRC_t cmDspUiLabelCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned lblVarId, unsigned alignVarId ); - cmDspRC_t cmDspUiTimeLineCreate(cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned valVarId, unsigned lblVarId, unsigned tlFileId, unsigned audPathId ); + cmDspRC_t cmDspUiTimeLineCreate(cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned tlFileVarId, unsigned audPathVarId, unsigned selVarId ); cmDspRC_t cmDspUiNewColumn( cmDspCtx_t* ctx, unsigned colW ); cmDspRC_t cmDspUiInsertHorzBorder( cmDspCtx_t* ctx ); diff --git a/dsp/cmDspKr.c b/dsp/cmDspKr.c index 63d2f80..9223764 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -24,6 +24,7 @@ #include "cmOp.h" #include "cmMath.h" + #include "cmAudioFile.h" #include "cmFileSys.h" #include "cmProcObj.h" @@ -33,6 +34,12 @@ #include "cmProc2.h" #include "cmVectOpsTemplateMain.h" +#include "cmAudioFile.h" +#include "cmMidiFile.h" +#include "cmTimeLine.h" +#include "cmScore.h" +#include "cmProc4.h" + enum { kWndSmpCntKrId, @@ -227,12 +234,20 @@ struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx ) //========================================================================================================================================== +// Time Line UI Object + enum { - kValTlId, - kLblTlId, kTlFileTlId, - kAudPathTlId + kAudPathTlId, + kSelTlId, + kAudFnTlId, + kMidiFnTlId, + kBegAudSmpIdxTlId, + kEndAudSmpIdxTlId, + kBegMidiSmpIdxTlId, + kEndMidiSmpIdxTlId + }; cmDspClass_t _cmTimeLineDC; @@ -240,38 +255,113 @@ cmDspClass_t _cmTimeLineDC; typedef struct { cmDspInst_t inst; + cmTlH_t tlH; } cmDspTimeLine_t; cmDspInst_t* _cmDspTimeLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) { cmDspVarArg_t args[] = { - { "val", kValTlId, 0, 0, kInDsvFl | kOutDsvFl | kStrzDsvFl | kReqArgDsvFl | kSendDfltDsvFl, "Current string"}, - { "lbl", kLblTlId, 0, 0, kStrzDsvFl | kOptArgDsvFl, "Label"}, + { "tlfile", kTlFileTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Time line file." }, + { "path", kAudPathTlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Audio path" }, + { "sel", kSelTlId, 0, 0, kInDsvFl | kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected marker id."}, + { "afn", kAudFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected Audio file." }, + { "mfn", kMidiFnTlId, 0, 0, kOutDsvFl | kStrzDsvFl, "Selected MIDI file." }, + { "absi", kBegAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin audio sample index."}, + { "aesi", kEndAudSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End audio sample index."}, + { "mbsi", kBegMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "Begin MIDI sample index."}, + { "mesi", kEndMidiSmpIdxTlId, 0, 0, kOutDsvFl | kIntDsvFl, "End MIDI sample index."}, { NULL, 0, 0, 0, 0 } }; cmDspTimeLine_t* p = cmDspInstAlloc(cmDspTimeLine_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + + cmDspSetDefaultUInt( ctx, &p->inst, kSelTlId, 0, cmInvalidId); + cmDspSetDefaultStrcz(ctx, &p->inst, kAudFnTlId, NULL, ""); + cmDspSetDefaultStrcz(ctx, &p->inst, kMidiFnTlId, NULL, ""); + cmDspSetDefaultInt( ctx, &p->inst, kBegAudSmpIdxTlId, 0, cmInvalidIdx); + cmDspSetDefaultInt( ctx, &p->inst, kEndAudSmpIdxTlId, 0, cmInvalidIdx); + cmDspSetDefaultInt( ctx, &p->inst, kBegMidiSmpIdxTlId, 0, cmInvalidIdx); + cmDspSetDefaultInt( ctx, &p->inst, kEndMidiSmpIdxTlId, 0, cmInvalidIdx); // create the UI control - cmDspUiTimeLineCreate(ctx,&p->inst,kValTlId,kLblTlId,kTlFileTlId,kAudPathTlId); + cmDspUiTimeLineCreate(ctx,&p->inst,kTlFileTlId,kAudPathTlId,kSelTlId); + + p->tlH = cmTimeLineNullHandle; return &p->inst; } +cmDspRC_t _cmDspTimeLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst; + + if( cmTimeLineFinalize(&p->tlH) != kOkTlRC ) + return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Time-line finalize failed."); + + return rc; +} + + cmDspRC_t _cmDspTimeLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { + cmDspRC_t rc = kOkDspRC; + cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst; + cmDspApplyAllDefaults(ctx,inst); - return kOkDspRC; + + const cmChar_t* tlFn; + if((tlFn = cmDspStrcz(inst, kTlFileTlId )) != NULL ) + if( cmTimeLineInitializeFromFile(ctx->cmCtx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC ) + rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Time-line file open failed."); + + return rc; } cmDspRC_t _cmDspTimeLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { + cmDspTimeLine_t* p = (cmDspTimeLine_t*)inst; switch( evt->dstVarId ) { - case kValTlId: - cmDspSetEvent(ctx,inst,evt); + case kSelTlId: + { + unsigned markerId; + cmDspSetEvent(ctx,inst,evt); + + // get the id of the selected marker + if((markerId = cmDspUInt(inst,kSelTlId)) != cmInvalidId ) + { + // get the marker object + cmTlObj_t* op; + if((op = cmTimeLineIdToObj(p->tlH, cmInvalidId, markerId )) != NULL ) + { + assert(op->typeId == kMarkerTlId); + + cmDspSetInt(ctx, inst, kBegAudSmpIdxTlId, op->begSmpIdx ); + cmDspSetInt(ctx, inst, kEndAudSmpIdxTlId, op->begSmpIdx + op->durSmpCnt ); + + // locate the audio file assoc'd with the marker + cmTlAudioFile_t* afp; + if((afp = cmTimeLineAudioFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL) + cmDspSetStrcz(ctx, inst, kAudFnTlId, afp->fn ); + + // locate the midi file assoc'd with the marker + cmTlMidiFile_t* mfp; + if((mfp = cmTimeLineMidiFileAtTime(p->tlH,op->seqId,op->seqSmpIdx)) != NULL ) + { + cmDspSetInt(ctx, inst, kBegMidiSmpIdxTlId, op->seqSmpIdx - mfp->obj.seqSmpIdx ); + cmDspSetInt(ctx, inst, kEndMidiSmpIdxTlId, op->seqSmpIdx + op->durSmpCnt - mfp->obj.seqSmpIdx ); + + cmDspSetStrcz(ctx, inst, kMidiFnTlId, mfp->fn ); + } + } + + } + + } + break; default: @@ -286,7 +376,7 @@ struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx ) cmDspClassSetup(&_cmTimeLineDC,ctx,"TimeLine", NULL, _cmDspTimeLineAlloc, - NULL, + _cmDspTimeLineFree, _cmDspTimeLineReset, NULL, _cmDspTimeLineRecv, @@ -296,3 +386,339 @@ struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx ) return &_cmTimeLineDC; } +//========================================================================================================================================== +// MIDI File Player + +enum +{ + kFnMfId, + kSelMfId, + kBsiMfId, + kEsiMfId, + kStatusMfId, + kD0MfId, + kD1MfId +}; + +cmDspClass_t _cmMidiFilePlayDC; + +typedef struct +{ + cmDspInst_t inst; + cmMidiFileH_t mfH; + unsigned curMsgIdx; // current midi file msg index + int csi; // current sample index + int bsi; // starting sample index + int esi; // ending sample index + unsigned startSymId; + unsigned stopSymId; + unsigned contSymId; +} cmDspMidiFilePlay_t; + +/* + 'bsi' and 'esi' give the starting and ending sample for MIDI file playback. + These indexes are relative to the start of the file. + When the player recieves a 'start' msg it sets the current sample index + 'si' to 'bsi' and begins scanning for the next note to play. + On each call to the _cmDspMidiFilePlayExec() msgs that fall in the interval + si:si+sPc-1 will be transmitted. (where sPc are the number of samples per DSP cycle). + */ + +cmDspInst_t* _cmDspMidiFilePlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + cmDspVarArg_t args[] = + { + { "fn", kFnMfId, 0, 0, kInDsvFl | kStrzDsvFl, "File name"}, + { "sel", kSelMfId, 0, 0, kInDsvFl | kSymDsvFl, "start | stop | continue" }, + { "bsi", kBsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Starting sample." }, + { "esi", kEsiMfId, 0, 0, kInDsvFl | kIntDsvFl, "Ending sample."}, + { "status", kStatusMfId, 0, 0, kOutDsvFl | kIntDsvFl, "Status value output" }, + { "d0", kD0MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 0" }, + { "d1", kD1MfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Data byte 1" }, + { NULL, 0, 0, 0, 0 } + }; + + cmDspMidiFilePlay_t* p = cmDspInstAlloc(cmDspMidiFilePlay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + + p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start"); + p->stopSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"stop"); + p->contSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"continue"); + p->mfH = cmMidiFileNullHandle; + + cmDspSetDefaultStrcz( ctx, &p->inst, kFnMfId, NULL, ""); + cmDspSetDefaultSymbol(ctx, &p->inst, kSelMfId, p->stopSymId); + cmDspSetDefaultInt( ctx, &p->inst, kBsiMfId, 0, 0); + cmDspSetDefaultInt( ctx, &p->inst, kEsiMfId, 0, 0); + cmDspSetDefaultUInt( ctx, &p->inst, kStatusMfId, 0, 0); + cmDspSetDefaultUInt( ctx, &p->inst, kD0MfId, 0, 0); + cmDspSetDefaultUInt( ctx, &p->inst, kD1MfId, 0, 0); + + return &p->inst; +} + +cmDspRC_t _cmDspMidiFilePlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst; + if( cmMidiFileClose(&p->mfH) ) + return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "MIDI file close failed."); + return kOkDspRC; +} + +// return the index of the msg following smpIdx +unsigned _cmDspMidiFilePlaySeekMsgIdx( cmDspCtx_t* ctx, cmDspMidiFilePlay_t* p, unsigned smpIdx ) +{ + unsigned i; + unsigned n = cmMidiFileMsgCount(p->mfH); + const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(p->mfH); + + for(i=0; idtick > smpIdx ) + break; + + return i==n ? cmInvalidIdx : i; +} + +cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst ) +{ + cmDspRC_t rc = kOkDspRC; + const cmChar_t* fn = cmDspStrcz(inst,kFnMfId); + cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst; + + if( fn==NULL || strlen(fn)==0 ) + return rc; + + if( cmMidiFileOpen( fn, &p->mfH, ctx->cmCtx ) != kOkFileRC ) + rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "MIDI file open failed."); + else + { + p->curMsgIdx = 0; + p->bsi = cmDspInt(inst,kBsiMfId); + p->esi = cmDspInt(inst,kEsiMfId); + p->csi = 0; + + // force the first msg to occurr one quarter note into the file + cmMidiFileSetDelay(p->mfH, cmMidiFileTicksPerQN(p->mfH) ); + + // convert midi msg times to absolute time in samples + cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true); + } + return rc; +} + +cmDspRC_t _cmDspMidiFilePlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspApplyAllDefaults(ctx,inst); + + return _cmDspMidiFilePlayOpen(ctx,inst); +} + +cmDspRC_t _cmDspMidiFilePlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst; + unsigned sPc = cmDspSamplesPerCycle(ctx); + + if( cmDspSymbol(inst,kSelMfId) != p->stopSymId ) + { + const cmMidiTrackMsg_t** mpp = cmMidiFileMsgArray(p->mfH); + unsigned msgN = cmMidiFileMsgCount(p->mfH); + + for(; p->curMsgIdx < msgN && p->csi <= mpp[p->curMsgIdx]->dtick && mpp[p->curMsgIdx]->dtick < (p->csi + sPc); ++p->curMsgIdx ) + { + const cmMidiTrackMsg_t* mp = mpp[p->curMsgIdx]; + switch( mp->status ) + { + case kNoteOnMdId: + case kCtlMdId: + cmDspSetUInt(ctx,inst, kD1MfId, mp->u.chMsgPtr->d1); + cmDspSetUInt(ctx,inst, kD0MfId, mp->u.chMsgPtr->d0); + cmDspSetUInt(ctx,inst, kStatusMfId, mp->status); + break; + } + } + } + + p->csi += sPc; + + return rc; +} + +cmDspRC_t _cmDspMidiFilePlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspMidiFilePlay_t* p = (cmDspMidiFilePlay_t*)inst; + + cmDspSetEvent(ctx,inst,evt); + + switch(evt->dstVarId) + { + case kFnMfId: + _cmDspMidiFilePlayOpen(ctx, inst ); + break; + + case kSelMfId: + { + if( cmDspSymbol(inst,kSelMfId)==p->startSymId ) + { + p->csi = cmDspInt(inst,kBsiMfId); + p->curMsgIdx = _cmDspMidiFilePlaySeekMsgIdx(ctx, p, p->csi ); + } + break; + } + + } + return kOkDspRC; +} + +struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmMidiFilePlayDC,ctx,"MidiFilePlay", + NULL, + _cmDspMidiFilePlayAlloc, + _cmDspMidiFilePlayFree, + _cmDspMidiFilePlayReset, + _cmDspMidiFilePlayExec, + _cmDspMidiFilePlayRecv, + NULL,NULL, + "Time tagged text file."); + + return &_cmMidiFilePlayDC; +} + +//========================================================================================================================================== +enum +{ + kFnSfId, + kWndCntSfId, + kWndMsSfId, + kIndexSfId, + kStatusSfId, + kD0SfId, + kD1SfId, + kOutSfId +}; + +cmDspClass_t _cmScFolDC; + +typedef struct +{ + cmDspInst_t inst; + cmScFol* sfp; + cmScH_t scH; +} cmDspScFol_t; + +cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + cmDspVarArg_t args[] = + { + { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." }, + { "wndcnt",kWndCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window element count." }, + { "wndms", kWndMsSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window length milliseconds."}, + { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."}, + { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"}, + { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"}, + { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"}, + { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."}, + { NULL, 0, 0, 0, 0, NULL } + }; + + cmDspScFol_t* p; + + if((p = cmDspInstAlloc(cmDspScFol_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL ) + return NULL; + + + p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle ); + + cmDspSetDefaultUInt( ctx, &p->inst, kWndCntSfId, 0, 10); + cmDspSetDefaultUInt( ctx, &p->inst, kWndMsSfId, 0, 5000); + cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0); + cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0); + + return &p->inst; +} + +cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspScFol_t* p = (cmDspScFol_t*)inst; + cmScFolFree(&p->sfp); + cmScoreFinalize(&p->scH); + return kOkDspRC; +} + +cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst ) +{ + const cmChar_t* fn; + cmDspScFol_t* p = (cmDspScFol_t*)inst; + + if((fn = cmDspStrcz(inst,kFnSfId)) == NULL || strlen(fn)==0 ) + return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied."); + + if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, NULL ) != kOkScRC ) + return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn); + + return kOkDspRC; +} + +cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspScFol_t* p = (cmDspScFol_t*)inst; + rc = cmDspApplyAllDefaults(ctx,inst); + + if((rc = _cmDspScFolOpenScore(ctx,inst)) != kOkDspRC ) + return rc; + + if( cmScoreIsValid(p->scH) ) + if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kWndCntSfId), cmDspUInt(inst,kWndMsSfId), p->scH) != cmOkRC ) + rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed."); + + return rc; +} + + +cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspScFol_t* p = (cmDspScFol_t*)inst; + + if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && p->sfp != NULL ) + { + switch( evt->dstVarId ) + { + case kIndexSfId: + if( cmScFolReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC ) + cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed."); + break; + + case kStatusSfId: + { + unsigned idx = cmScFolExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId)); + if( idx != cmInvalidIdx ) + cmDspSetUInt(ctx,inst,kOutSfId,idx); + } + break; + + case kFnSfId: + _cmDspScFolOpenScore(ctx,inst); + break; + } + } + + return rc; +} + +struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmScFolDC,ctx,"ScFol", + NULL, + _cmDspScFolAlloc, + _cmDspScFolFree, + _cmDspScFolReset, + NULL, + _cmDspScFolRecv, + NULL,NULL, + "Score Follower"); + + return &_cmScFolDC; +} + diff --git a/dsp/cmDspKr.h b/dsp/cmDspKr.h index 9ba976f..c03fabb 100644 --- a/dsp/cmDspKr.h +++ b/dsp/cmDspKr.h @@ -7,6 +7,7 @@ extern "C" { struct cmDspClass_str* cmKrClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmTimeLineClassCons( cmDspCtx_t* ctx ); + struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx ); #ifdef __cplusplus } diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index d6efa23..e1fbe0e 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -36,16 +36,53 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) { - cmDspRC_t rc = kOkDspRC; + cmDspRC_t rc = kOkDspRC; + const cmChar_t* tlFn = "/home/kevin/src/cmgv/src/gv/data/tl7.js"; + const cmChar_t* audPath = "/home/kevin/media/audio/20110723-Kriesberg/Audio Files"; + const cmChar_t* scFn = "/home/kevin/src/cmgv/src/gv/data/mod2.csv"; + + cmDspInst_t* sci = cmDspSysAllocInst(h,"Scalar", "ScIdx", 5, kNumberDuiId, 0.0, 10000.0, 1.0, 0.0); + + cmDspInst_t* tlp = cmDspSysAllocInst(h,"TimeLine", "tl", 2, tlFn, audPath ); + cmDspInst_t* php = cmDspSysAllocInst(h,"Phasor", NULL, 0 ); + cmDspInst_t* wtp = cmDspSysAllocInst(h,"WaveTable", NULL, 2, cmDspSysSampleRate(h), 0 ); + cmDspInst_t* pts = cmDspSysAllocInst(h,"PortToSym", NULL, 1, "start" ); + cmDspInst_t* mfp = cmDspSysAllocInst(h,"MidiFilePlay",NULL, 0 ); + cmDspInst_t* sfp = cmDspSysAllocInst(h,"ScFol", NULL, 1, scFn ); + cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 ); + cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 ); + + - cmDspInst_t* tlp = cmDspSysAllocInst(h,"TimeLine", "text", 1, "Hello" ); cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL, 1, ">" ); if((rc = cmDspSysLastRC(h)) != kOkDspRC ) return rc; + cmDspSysConnectAudio(h, php, "out", wtp, "phs" ); // phs -> wt + cmDspSysConnectAudio(h, wtp, "out", ao0p, "in" ); // wt -> aout0 + cmDspSysConnectAudio(h, wtp, "out", ao1p, "in" ); // wt -> aout1 + - cmDspSysInstallCb(h, tlp, "val", prp, "in", NULL ); + cmDspSysInstallCb(h, tlp, "afn", prp, "in", NULL ); + cmDspSysInstallCb(h, tlp, "mfn", prp, "in", NULL ); + cmDspSysInstallCb(h, tlp, "sel", prp, "in", NULL ); + + cmDspSysInstallCb(h, tlp, "absi", wtp, "beg", NULL ); + cmDspSysInstallCb(h, tlp, "aesi", wtp, "end", NULL ); + cmDspSysInstallCb(h, tlp, "afn", wtp, "fn", NULL ); + + cmDspSysInstallCb(h, tlp, "mbsi", mfp, "bsi", NULL ); + cmDspSysInstallCb(h, tlp, "mesi", mfp, "esi", NULL ); + cmDspSysInstallCb(h, tlp, "mfn", mfp, "fn", NULL ); + cmDspSysInstallCb(h, tlp, "mfn", pts, "start", NULL ); + cmDspSysInstallCb(h, pts, "out", mfp, "sel", NULL ); + + cmDspSysInstallCb(h, mfp, "status", sfp, "status", NULL ); + cmDspSysInstallCb(h, mfp, "d0", sfp, "d0", NULL ); + cmDspSysInstallCb(h, mfp, "d1", sfp, "d1", NULL ); + cmDspSysInstallCb(h, sci, "val", sfp, "index", NULL ); + cmDspSysInstallCb(h, sfp, "out", prp, "in", NULL ); return rc; } diff --git a/dsp/cmDspUi.c b/dsp/cmDspUi.c index 58cdb3e..714365c 100644 --- a/dsp/cmDspUi.c +++ b/dsp/cmDspUi.c @@ -361,10 +361,10 @@ cmDspRC_t cmDspUiLabelCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned lbl return rc; } -cmDspRC_t cmDspUiTimeLineCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned valVarId, unsigned lblVarId, unsigned tlFileVarId, unsigned audPathVarId ) +cmDspRC_t cmDspUiTimeLineCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned tlFileVarId, unsigned audPathVarId, unsigned selVarId ) { cmDspRC_t rc; - unsigned arr[] = { valVarId, lblVarId, tlFileVarId, audPathVarId }; + unsigned arr[] = { tlFileVarId, audPathVarId, selVarId }; cmDspValue_t v; unsigned vn = sizeof(arr)/sizeof(arr[0]); cmDsvSetUIntMtx(&v,arr,vn,1); @@ -374,14 +374,14 @@ cmDspRC_t cmDspUiTimeLineCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned return cmDspInstErr(ctx,inst,kUiEleCreateFailDspRC,"Time Line UI element create failed."); // use instance symbol as default label - if((rc = _cmDspUiUseInstSymbolAsLabel(ctx, inst, lblVarId, "TimeLine")) != kOkDspRC ) - return rc; + //if((rc = _cmDspUiUseInstSymbolAsLabel(ctx, inst, lblVarId, "TimeLine")) != kOkDspRC ) + // return rc; // Set the kUiDsvFl on the variables used for the min/max/def/val for this scalar // Setting this flag will cause their values to be sent to the UI whenever they change. - cmDspInstVarSetFlags( ctx, inst, valVarId, kUiDsvFl ); cmDspInstVarSetFlags( ctx, inst, tlFileVarId, kUiDsvFl ); cmDspInstVarSetFlags( ctx, inst, audPathVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, selVarId, kUiDsvFl ); return rc; }