diff --git a/app/cmScore.c b/app/cmScore.c index cf8a835..b1533b9 100644 --- a/app/cmScore.c +++ b/app/cmScore.c @@ -41,9 +41,11 @@ enum kRemarkColScIdx = 19 }; + typedef struct { unsigned id; + unsigned flag; cmChar_t label[ kLabelCharCnt + 1 ]; } cmScEvtRef_t; @@ -64,18 +66,12 @@ typedef struct cmScSetEle_str typedef struct cmScSet_str { unsigned typeFl; // type of this set - cmScSetEle_t* eles; // indexes of set elements - cmScSetEle_t* sects; // application section labels - bool inFl; // true if currently accepting elements - struct cmScSet_str* link; // + cmScSetEle_t* eles; // indexes of set elements + cmScSetEle_t* sects; // application section labels + bool inFl; // true if currently accepting elements + struct cmScSet_str* link; // } cmScSet_t; -typedef struct cmScPerf_str -{ - cmScoreSet_t* set; - struct cmScPerf_str* link; -} cmScPerf_t; - typedef struct { cmErr_t err; @@ -102,40 +98,53 @@ typedef struct cmScoreSet_t* sets; unsigned setCnt; - cmScPerf_t perf; + unsigned* dynRefArray; + unsigned dynRefCnt; + + unsigned nxtLocIdx; + unsigned minSetLocIdx; + unsigned maxSetLocIdx; } cmSc_t; cmScEvtRef_t _cmScEvtRefArray[] = { - { kTimeSigEvtScId, "tsg" }, - { kKeySigEvtScId, "ksg" }, - { kTempoEvtScId, "tmp" }, - { kTrackEvtScId, "trk" }, - { kTextEvtScId, "txt" }, - { kEOTrackEvtScId, "eot" }, - { kCopyEvtScId, "cpy"}, - { kBlankEvtScId, "blk"}, - { kBarEvtScId, "bar"}, - { kPgmEvtScId, "pgm" }, - { kCtlEvtScId, "ctl" }, - { kNonEvtScId, "non" }, - { kInvalidEvtScId, "***" } + { kTimeSigEvtScId, 0, "tsg" }, + { kKeySigEvtScId, 0, "ksg" }, + { kTempoEvtScId, 0, "tmp" }, + { kTrackEvtScId, 0, "trk" }, + { kTextEvtScId, 0, "txt" }, + { kEOTrackEvtScId, 0, "eot" }, + { kCopyEvtScId, 0, "cpy" }, + { kBlankEvtScId, 0, "blk" }, + { kBarEvtScId, 0, "bar" }, + { kPgmEvtScId, 0, "pgm" }, + { kCtlEvtScId, 0, "ctl" }, + { kNonEvtScId, 0, "non" }, + { kInvalidEvtScId, 0, "***" } }; cmScEvtRef_t _cmScDynRefArray[] = { - { 1, "pppp" }, - { 2, "ppp" }, - { 3, "pp" }, - { 4, "p" }, - { 5, "mp" }, - { 6, "m" }, - { 7, "mf" }, - { 8, "f" }, - { 9, "ff" }, - { 10, "fff" }, - { 11, "ffff"}, - { kInvalidDynScId, "***" }, + { 1, 0, "pppp" }, + { 2, 0, "ppp" }, + { 3, 0, "pp" }, + { 4, 0, "p" }, + { 5, 0, "mp" }, + { 6, 0, "m" }, + { 7, 0, "mf" }, + { 8, 0, "f" }, + { 9, 0, "ff" }, + { 10,0, "fff" }, + { 11,0, "ffff"}, + { kInvalidDynScId,0, "***" }, +}; + +cmScEvtRef_t _cmScVarRefArray[] = +{ + { kEvenVarScId, kEvenScFl, "e"}, + { kDynVarScId, kDynScFl, "d"}, + { kTempoVarScId,kTempoScFl,"t"}, + { cmInvalidId, 0, "@"} }; cmSc_t* _cmScHandleToPtr( cmScH_t h ) @@ -172,6 +181,15 @@ unsigned _cmScDynLabelToId( const cmChar_t* label ) return kInvalidDynScId; } +// return the count of dynamic label/id pairs +unsigned _cmScDynLabelCount( ) +{ + unsigned n = 0; + cmScEvtRef_t* r = _cmScDynRefArray; + for(; r->id != kInvalidEvtScId; ++r ) + ++n; + return n; +} const cmChar_t* cmScDynIdToLabel( unsigned id ) { cmScEvtRef_t* r = _cmScDynRefArray; @@ -181,6 +199,66 @@ const cmChar_t* cmScDynIdToLabel( unsigned id ) return NULL; } +char _cmScVarFlagToChar( unsigned flags ) +{ + unsigned i; + for(i=0; _cmScVarRefArray[i].id!=cmInvalidId; ++i) + if( _cmScVarRefArray[i].flag == flags ) + return _cmScVarRefArray[i].label[0]; + assert(0); + return ' '; +} + +char _cmScVarIdToChar( unsigned id ) +{ + unsigned i; + for(i=0; _cmScVarRefArray[i].id!=cmInvalidId; ++i) + if( _cmScVarRefArray[i].id == id ) + return _cmScVarRefArray[i].label[0]; + assert(0); + return ' '; +} + +unsigned _cmScVarFlagToId( unsigned flags ) +{ + unsigned i; + for(i=0; _cmScVarRefArray[i].id!=cmInvalidId; ++i) + if( _cmScVarRefArray[i].flag == flags ) + return _cmScVarRefArray[i].id; + assert(0); + return cmInvalidId; +} + +const char* _cmScFlagsToStr( unsigned flags, char* buf, int bufCharCnt ) +{ + + unsigned i=0; + if( cmIsFlag(flags,kEvenScFl) ) + { + assert(isetCnt; ++i) { cmMemFree(p->sets[i].eleArray); - cmMemFree(p->sets[i].sectArray); + //cmMemFree(p->sets[i].sectArray); } cmMemFree(p->sets); } @@ -285,10 +363,15 @@ cmScRC_t _cmScFinalize( cmSc_t* p ) if( p->loc != NULL ) { for(i=0; ilocCnt; ++i) + { cmMemFree(p->loc[i].evtArray); + if( p->loc[i].begSectPtr != NULL ) + cmMemFree(p->loc[i].begSectPtr->setArray); + } cmMemFree(p->loc); } + cmMemFree(p->sect); cmMemFree(p->fn); cmMemFree(p->array); @@ -660,17 +743,26 @@ cmScRC_t _cmScProcSets( cmSc_t* p ) ++en; // allocate the section array - p->sets[i].typeFl = sp->typeFl; - p->sets[i].sectCnt = en; - p->sets[i].sectArray = cmMemAllocZ(cmScoreSection_t*,en); + p->sets[i].varId = _cmScVarFlagToId(sp->typeFl); + //p->sets[i].sectCnt = en; + //p->sets[i].sectArray = cmMemAllocZ(cmScoreSection_t*,en); - // fill in the section array + // fill in the section array with sections which this set will be applied to ep = sp->sects; for(j=0; ep!=NULL; ep=ep->link,++j) { + cmScoreSection_t* sp; assert(ep->label != NULL); - if((p->sets[i].sectArray[j] = _cmScLabelToSection(p, ep->label )) == NULL ) - rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The section labelled '%s' could not be found for the set which includes row number %i.",ep->label,rowNumb); + if((sp = _cmScLabelToSection(p, ep->label )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The section labelled '%s' could not be found for the set which includes row number %i.",ep->label,rowNumb); + else + { + //= p->sets[i].sectArray[j]; + + sp->setArray = cmMemResizeP(cmScoreSet_t*,sp->setArray,++sp->setCnt); + sp->setArray[sp->setCnt-1] = p->sets + i; + } + } ++i; @@ -703,7 +795,7 @@ cmScRC_t _cmScProcSets( cmSc_t* p ) assert( jlocCnt ); // assign the ith set to the location which contains it's last element - p->sets[i].link = p->loc[j].setList; + p->sets[i].llink = p->loc[j].setList; p->loc[j].setList = p->sets + i; } @@ -732,16 +824,17 @@ cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList ) if( sp->label != NULL ) { p->sect[i].label = sp->label; - p->sect[i].begIndex = sp->startIdx; + p->sect[i].index = i; + p->sect[i].begEvtIndex = sp->startIdx; ++i; } // assign the begSectPtr to each section for(i=0; isectCnt; ++i) { - assert( p->sect[i].begIndex < p->cnt ); + assert( p->sect[i].begEvtIndex < p->cnt ); unsigned j,k; - const cmScoreEvt_t* ep = p->array + p->sect[i].begIndex; + const cmScoreEvt_t* ep = p->array + p->sect[i].begEvtIndex; for(j=0; jlocCnt; ++j) { for(k=0; kloc[j].evtCnt; ++k) @@ -767,10 +860,7 @@ cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList ) sp = np; } - _cmScPrintSets("Sets",p->setList ); - //_cmScPrintSets("even",p->evenSetList); - //_cmScPrintSets("dyn",p->evenSetList); - //_cmScPrintSets("tempo",p->evenSetList); + //_cmScPrintSets("Sets",p->setList ); _cmScProcSets(p); @@ -914,10 +1004,7 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) return rc; } -// This function does not currently work because there is no -// guarantee that all the time values (secs field) have been filled in -/// with valid times and that all event records have a valid 'type' id. -cmScRC_t _cmScoreInitLocArray( cmSc_t* p ) +cmScRC_t _cmScInitLocArray( cmSc_t* p ) { cmScRC_t rc = kOkScRC; double maxDSecs = 0; // max time between events that are considered simultaneous @@ -957,6 +1044,7 @@ cmScRC_t _cmScoreInitLocArray( cmSc_t* p ) assert(klocCnt); + p->loc[k].index = k; p->loc[k].evtCnt = j-i; p->loc[k].evtArray = cmMemAllocZ(cmScoreEvt_t*,p->loc[k].evtCnt); @@ -965,6 +1053,8 @@ cmScRC_t _cmScoreInitLocArray( cmSc_t* p ) { p->loc[k].evtArray[j] = p->array + (i + j); + p->loc[k].evtArray[j]->locIdx = k; + if( p->array[i+j].type == kBarEvtScId ) barNumb = p->array[i+j].barNumb; } @@ -982,7 +1072,8 @@ cmScRC_t _cmScoreInitLocArray( cmSc_t* p ) return rc; } -cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg ) + +cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, const unsigned* dynRefArray, unsigned dynRefCnt, cmScCb_t cbFunc, void* cbArg ) { cmScRC_t rc = kOkScRC; if((rc = cmScoreFinalize(hp)) != kOkScRC ) @@ -995,17 +1086,33 @@ cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScC if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC ) goto errLabel; - // See note at function - if((rc = _cmScoreInitLocArray(p)) != kOkScRC ) + if((rc = _cmScInitLocArray(p)) != kOkScRC ) goto errLabel; if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC ) goto errLabel; + // load the dynamic reference array + if( dynRefArray != NULL && dynRefCnt > 0) + { + unsigned n = _cmScDynLabelCount(); + if( dynRefCnt != n ) + { + rc = cmErrMsg(&p->err,kInvalidDynRefCntScRC,"The count of dynamics labels must be %i not %i.",n,dynRefCnt); + goto errLabel; + } - p->cbFunc = cbFunc; - p->cbArg = cbArg; - p->fn = cmMemAllocStr(fn); + p->dynRefArray = cmMemAllocZ(unsigned,dynRefCnt); + memcpy(p->dynRefArray,dynRefArray,sizeof(unsigned)*dynRefCnt); + p->dynRefCnt = dynRefCnt; + } + + p->cbFunc = cbFunc; + p->cbArg = cbArg; + p->fn = cmMemAllocStr(fn); + p->nxtLocIdx = 0; + p->minSetLocIdx = cmInvalidIdx; + p->maxSetLocIdx = cmInvalidIdx; hp->h = p; @@ -1062,6 +1169,20 @@ cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx ) return p->array + idx; } +unsigned cmScoreSectionCount( cmScH_t h ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + return p->sectCnt; +} + +cmScoreSection_t* cmScoreSection( cmScH_t h, unsigned idx ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + assert( idx < p->sectCnt); + return p->sect + idx; +} + + unsigned cmScoreLocCount( cmScH_t h ) { cmSc_t* p = _cmScHandleToPtr(h); @@ -1079,48 +1200,6 @@ cmScoreLoc_t* cmScoreLoc( cmScH_t h, unsigned idx ) return p->loc + idx; } -char _cmScFlagsToChar( unsigned flags ) -{ - switch(flags) - { - case kEvenScFl: return 'e'; - case kDynScFl: return 'd'; - case kTempoScFl:return 't'; - default: - { assert(0); } - } - return ' '; -} - -const char* _cmScFlagsToStr( unsigned flags, char* buf, int bufCharCnt ) -{ - - unsigned i=0; - if( cmIsFlag(flags,kEvenScFl) ) - { - assert(ilocCnt; i+=colCnt ) { + // print the location 'index' line unsigned c,j,k; printf("index: "); for(c=0,j=i; jlocCnt && clocCnt && cloc[j].begSectPtr==NULL ) @@ -1147,11 +1229,14 @@ void cmScorePrintLoc( cmScH_t h ) printf("%7s ",p->loc[j].begSectPtr->label); printf("\n"); + // calculate the max number of simultan. events at any one location + // for this set of 'colCnt' columns. unsigned n=0; for(c=0,j=i; jlocCnt && cloc[j].evtCnt > n ) n = p->loc[j].evtCnt; + // for each 'sco' line for(k=0; klocCnt && cloc[j].setList; - for(; sp!=NULL; sp=sp->link) - m += sp->sectCnt; - - if( m>n) - n = m; - } + if(p->loc[j].begSectPtr != NULL && p->loc[j].begSectPtr->setCnt > n ) + n = p->loc[j].begSectPtr->setCnt; for(k=0; klocCnt && cloc[j].setList; - for(; sp!=NULL && fl; sp=sp->link) - { - unsigned z; - for(z=0; zsectCnt; ++y,++z) - if( y == k ) - { - printf(" %3s%c ",sp->sectArray[z]->label,_cmScFlagsToChar(sp->typeFl) ); - fl = false; - break; - } + if( p->loc[j].begSectPtr != NULL && kloc[j].begSectPtr->setCnt ) + { + const cmScoreSet_t* sp = p->loc[j].begSectPtr->setArray[k]; + printf(" %3s-%c ",p->loc[j].begSectPtr->label,_cmScVarIdToChar(sp->varId) ); } - if( fl ) + else + { printf("%s",emptyStr); + } } printf("\n"); } + printf("\n"); } } @@ -1231,18 +1305,25 @@ cmScRC_t cmScoreSeqNotify( cmScH_t h ) if( p->cbFunc != NULL ) { - memset(&m.evt,0,sizeof(m.evt)); + memset(&m.u.evt,0,sizeof(m.u.evt)); m.typeId = kBeginMsgScId; p->cbFunc(p->cbArg,&m,sizeof(m)); m.typeId = kEventMsgScId; for(i=0; icnt; ++i) { - m.evt = p->array[i]; + m.u.evt = p->array[i]; p->cbFunc(p->cbArg,&m,sizeof(m)); } - memset(&m.evt,0,sizeof(m.evt)); + m.typeId = kSectionMsgScId; + for(i=0; isectCnt; ++i) + { + m.u.sect = p->sect[i]; + p->cbFunc(p->cbArg,&m,sizeof(m)); + } + + memset(&m.u.evt,0,sizeof(m.u.evt)); m.typeId = kEndMsgScId; p->cbFunc(p->cbArg,&m,sizeof(m)); @@ -1258,8 +1339,27 @@ void cmScoreClearPerfInfo( cmScH_t h ) { p->array[i].perfSmpIdx = cmInvalidIdx; p->array[i].perfVel = 0; + p->array[i].perfDynLvl = 0; } + for(i=0; ilocCnt; ++i) + { + cmScoreSet_t* sp = p->loc[i].setList; + for(; sp!=NULL; sp=sp->llink) + sp->doneFl = false; + } + + for(i=0; isectCnt; ++i) + { + unsigned j; + for(j=0; jsect[i].vars[j] = DBL_MAX; + } + + p->nxtLocIdx = 0; + p->minSetLocIdx = cmInvalidIdx; + p->maxSetLocIdx = cmInvalidIdx; + } bool _cmScIsSetPerfDone( cmScoreSet_t* sp ) @@ -1272,29 +1372,351 @@ bool _cmScIsSetPerfDone( cmScoreSet_t* sp ) } - -void cmScoreSetPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ) +void _cmScPerfSortTimes( unsigned *v, unsigned n ) +{ + unsigned i; + bool fl = true; + while(fl && n) + { + fl = false; + for(i=1; i v[i] ) + { + unsigned t = v[i-1]; + v[i-1] = v[i]; + v[i] = t; + fl = true; + } + } + --n; + } +} + +bool _cmScPerfEven(cmSc_t* p, cmScoreSet_t* stp, bool printMissFl) +{ + unsigned i = 0; + double u = 0; + double x = 0; + bool sortFl = false; + bool printFl = true; + + unsigned v[ stp->eleCnt ]; + unsigned d[ stp->eleCnt - 1]; + assert( stp->eleCnt > 1 ); + + // calculate the sum of the time between events + for(i=0; ieleCnt; ++i) + { + // if this event was not received - then the set is not valid + if( stp->eleArray[i]->perfSmpIdx == cmInvalidIdx ) + { + if( printFl && printMissFl) + printf("EVENESS: missing loc:%i %s\n",stp->eleArray[i]->locIdx,cmMidiToSciPitch(stp->eleArray[i]->pitch,NULL,0)); + return false; + } + + // load v[i] + v[i] = stp->eleArray[i]->perfSmpIdx; + + // check for out of order elements + if( i> 0 ) + if( v[i] < v[i-1] ) + sortFl = true; + } + + // sort the times in ascending order + if( sortFl ) + _cmScPerfSortTimes(v,stp->eleCnt); + + + // calc the sum of time differences + for(i=1; ieleCnt; ++i) + u += d[i-1] = v[i] - v[i-1]; + + // calculate the average time between events + u /= stp->eleCnt-1; + + // calculate the std-dev of the time between events + for(i=0; ieleCnt-1; ++i) + x += (d[i]-u)*(d[i]-u); + + double sd = sqrt(x/(stp->eleCnt-1)); + + // compute the average z-score + double c = 0; + for(i=0; ieleCnt-1; ++i) + c += fabs(d[i]-u)/sd; + + + stp->value = c/(stp->eleCnt-1); + stp->doneFl = true; + + if(printFl) + { + /* + for(i=0; ieleCnt; ++i) + { + printf("%i %i ",i,v[i]); + if( i > 0 ) + printf("%i ", d[i-1]); + printf("\n"); + } + */ + printf("%s EVENESS:%f\n",sortFl?"SORTED ":"",stp->value); + } + + return true; +} + +bool _cmScPerfDyn( cmSc_t* p, cmScoreSet_t* stp, bool printMissFl) +{ + double a = 0; + unsigned i = 0; + bool printFl = true; + + for(i=0; ieleCnt; ++i) + { + unsigned j; + + // if this event was not received - then the set is not valid + if( stp->eleArray[i]->perfSmpIdx == cmInvalidIdx ) + { + if( printFl && printMissFl ) + printf("DYNAMICS: missing loc:%i %s\n",stp->eleArray[i]->locIdx,cmMidiToSciPitch(stp->eleArray[i]->pitch,NULL,0)); + return false; + } + + unsigned m = 0; // lower bound for the first dyn. category + + // determine the dynamic category for the performed velocity of each event + for(j=0; jdynRefCnt; ++j) + { + // if the vel fall's into the jth dyn. category + if( m <= stp->eleArray[i]->perfVel && stp->eleArray[i]->perfVel < p->dynRefArray[j] ) + break; + + // store the min vel for the next dyn category + m = p->dynRefArray[j]; + } + + assert( j < p->dynRefCnt ); + + stp->eleArray[i]->perfDynLvl = j+1; + + a += abs((j+1) - stp->eleArray[i]->dynVal); + + if( p->cbFunc != NULL ) + { + cmScMsg_t m; + m.typeId = kDynMsgScId; + m.u.dyn.evtIdx = stp->eleArray[i]->index; + m.u.dyn.dynLvl = stp->eleArray[i]->perfDynLvl; + p->cbFunc(p->cbArg,&m,sizeof(m)); + } + + } + + stp->value = a / stp->eleCnt; + stp->doneFl = true; + + if( printFl ) + printf("DYNAMICS:%f\n",stp->value); + + return true; +} + +bool _cmScPerfTempo(cmSc_t* p, cmScoreSet_t* stp, bool printFl) +{ + return false; +} + +void _cmScPerfExec( cmSc_t* p, cmScoreSet_t* sp, bool printMissFl ) +{ + if( sp->doneFl == false ) + { + switch( sp->varId ) + { + case kEvenVarScId: + _cmScPerfEven(p,sp,printMissFl); + break; + + case kDynVarScId: + _cmScPerfDyn(p,sp,printMissFl); + break; + + case kTempoVarScId: + _cmScPerfTempo(p,sp,printMissFl); + break; + + default: + { assert(0); } + } + } + +} + +void _cmScPerfExecRange( cmSc_t* p ) +{ + if( p->minSetLocIdx == cmInvalidIdx || p->maxSetLocIdx==cmInvalidIdx ) + return; + + unsigned i = p->minSetLocIdx; + for(; i<=p->maxSetLocIdx; ++i) + { + cmScoreSet_t* sp = p->loc[i].setList; + for(; sp!=NULL; sp=sp->llink) + _cmScPerfExec(p,sp,false); + + } +} + +bool _cmScSetPerfEvent( cmSc_t* p, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ) { - cmSc_t* p = _cmScHandleToPtr(h); assert(locIdx < p->locCnt ); - cmScoreLoc_t* lp = p->loc + locIdx; + cmScoreLoc_t* lp = p->loc + locIdx; + bool foundFl = false; + bool doneFl = true; unsigned i; + // locate the event at the loc[locIdx] for(i=0; ievtCnt; ++i) { cmScoreEvt_t* ep = lp->evtArray[i]; - if( ep->type == kNonEvtScId && ep->pitch == pitch ) + if( ep->type == kNonEvtScId ) { - assert( ep->perfSmpIdx == cmInvalidIdx ); + if( ep->pitch == pitch ) + { + assert( ep->perfSmpIdx == cmInvalidIdx ); - ep->perfSmpIdx = smpIdx; - ep->perfVel = vel; - break; + ep->perfSmpIdx = smpIdx; + ep->perfVel = vel; + foundFl = true; + } + + // check if all notes have arrived for this location + if( ep->perfSmpIdx == cmInvalidIdx ) + doneFl = false; } } + // the event must always be found + assert( foundFl ); + + return doneFl; } +bool cmScoreSetPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + return _cmScSetPerfEvent(p,locIdx,smpIdx,pitch,vel); +} + +void cmScoreExecPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ) +{ + unsigned i; + cmSc_t* p = _cmScHandleToPtr(h); + bool doneFl = _cmScSetPerfEvent(p,locIdx,smpIdx,pitch,vel); + unsigned printLvl = 1; + cmScoreLoc_t* lp = p->loc + locIdx; + + + // all events for a location must be complete to trigger attached events + if( doneFl == false ) + return; + + if( p->loc[locIdx].setList != NULL ) + { + // set idx of most recent loc w/ a set end event + p->maxSetLocIdx = locIdx; + + if( p->minSetLocIdx == cmInvalidIdx ) + p->minSetLocIdx = locIdx; + } + + // attempt to calculate all sets between loc[p->minSetLocIdx] and loc[p->maxSetLocIdx] + _cmScPerfExecRange(p); + + // prevent event retriggering or going backwards + if( printLvl && locIdx < p->nxtLocIdx ) + { + printf("----- BACK ----- \n"); + return; + } + + if( printLvl && locIdx > p->nxtLocIdx ) + { + printf("----- SKIP ----- \n"); + } + + // for each location between the current and previous location + for(; p->nxtLocIdx<=locIdx; ++p->nxtLocIdx) + { + + lp = p->loc + p->nxtLocIdx; + + // if this location is the start of a new section - then apply + // sets that are assigned to this section + if( lp->begSectPtr != NULL && lp->begSectPtr->setCnt > 0 ) + { + // notice the location of the oldest section start - once we cross this point + // it is too late to notice set completions - so incr p->inSetLocIdx + if( lp->begSectPtr->setCnt ) + p->minSetLocIdx = p->nxtLocIdx+1; + + for(i=0; ibegSectPtr->setCnt; ++i) + { + cmScoreSet_t* stp = lp->begSectPtr->setArray[i]; + + if( stp->doneFl == false ) + _cmScPerfExec(p, stp, printLvl>0 ); + + if( stp->doneFl ) + { + assert( stp->varId < kScVarCnt ); + + lp->begSectPtr->vars[ stp->varId ] = stp->value; + + if( p->cbFunc != NULL ) + { + cmScMsg_t m; + m.typeId = kVarMsgScId; + m.u.meas.varId = stp->varId; + m.u.meas.value = stp->value; + p->cbFunc(p->cbArg,&m,sizeof(m)); + + } + } + } + } + } +} + +void cmScoreSetPerfValue( cmScH_t h, unsigned locIdx, unsigned varId, double value ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + + int li = locIdx; + for(; li>=0; --li) + if( p->loc[li].begSectPtr != NULL ) + { + assert( varId < kScVarCnt ); + p->loc[li].begSectPtr->vars[varId] = value; + break; + } + + assert( li>=0); +} + +void cmScoreSetPerfDynLevel( cmScH_t h, unsigned evtIdx, unsigned dynLvl ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + + assert(evtIdx < p->cnt ); + p->array[ evtIdx ].perfDynLvl = dynLvl; +} + + cmScRC_t cmScoreDecode( const void* msg, unsigned msgByteCnt, cmScMsg_t* m) { cmScMsg_t* mp = (cmScMsg_t*)msg; @@ -1331,228 +1753,10 @@ void cmScorePrint( cmScH_t h, cmRpt_t* rpt ) } } -/* -// Each time line note-on object is decorated (via cmTlObj_t.userDataPtr) with a -// cmScSyncState_t record. -typedef struct -{ - unsigned cnt; // count of candidate sync locations - double dist; // edit distance to the closest sync location - unsigned scEvtIdx; // score record this note-on is assigned to -} cmScSyncState_t; - -void _cmScSyncTimeLineAllocFree( cmTlH_t tlH, bool allocFl ) -{ - cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId); - - for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId)) - if( mep->msg->status == kNoteOnMdId ) - { - if( allocFl ) - mep->obj.userDataPtr = cmMemAllocZ(cmScSyncState_t,1); - else - cmMemPtrFree(&mep->obj.userDataPtr); - } -} - -void _cmScPrintSyncState( cmSc_t* p, cmTlH_t tlH ) -{ - unsigned i = 0; - double sr = cmTimeLineSampleRate(tlH); - cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId); - - for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId)) - if( mep->msg->status == kNoteOnMdId ) - { - cmScSyncState_t* ssp = (cmScSyncState_t*)mep->obj.userDataPtr; - - cmRptPrintf(p->err.rpt,"%5.3f pit:0x%2x (%3i) bar:%3i bni:%3i cnt:%3i dst:%1.6f ref:%s\n", - (mep->obj.ref->begSmpIdx - mep->obj.begSmpIdx) / (sr*60), - mep->msg->u.chMsgPtr->d0, - mep->msg->u.chMsgPtr->d0, - ssp->cnt ? p->array[ ssp->scEvtIdx ].barNumb : 0, - ssp->cnt ? p->array[ ssp->scEvtIdx ].barNoteIdx : 0, - ssp->cnt, - ssp->dist, - cmStringNullGuard(mep->obj.ref->name)); - - ++i; - if( i>=300) - break; - } -} - -double _cmScWndEditDist( cmSc_t* p, unsigned* mtx, const unsigned* tlWnd, cmScSyncState_t* tlObjWnd[], unsigned wndCnt ) -{ - unsigned scWnd[ wndCnt ]; - unsigned scIdxWnd[ wndCnt ]; - unsigned i; - unsigned wn = 0; - double minDist = DBL_MAX; - - // for each note-on score event - for(i=0; icnt; ++i) - if( p->array[i].type == kNonEvtScId ) - { - // shift the score event window to the the left - memmove(scWnd, scWnd+1, (wndCnt-1)*sizeof(scWnd[0])); - memmove(scIdxWnd,scIdxWnd+1,(wndCnt-1)*sizeof(scIdxWnd[0])); - - // insert new score event data on right - scWnd[wndCnt-1] = p->array[i].pitch; - scIdxWnd[wndCnt-1] = i; - ++wn; - - // if the window is full - if(wn >= wndCnt ) - { - // score the edit distance between the time line window and the edit window - double dist = cmVOU_LevEditDist(wndCnt,mtx,scWnd,wndCnt,tlWnd,wndCnt,wndCnt); - - if( dist < minDist ) - minDist = dist; - - // update the match information in the time line window - unsigned j; - for(j=0; jcnt == 0 || dist < tlObjWnd[j]->dist) ) - { - tlObjWnd[j]->cnt += 1; - tlObjWnd[j]->dist = dist; - tlObjWnd[j]->scEvtIdx = scIdxWnd[j]; - } - } - } - } - - return minDist; -} - -cmScRC_t cmScoreSyncTimeLine( cmScH_t scH, cmTlH_t tlH, unsigned edWndCnt, cmReal_t maxSecs ) -{ - cmSc_t* p = _cmScHandleToPtr(scH); - unsigned* edWndMtx = cmVOU_LevEditDistAllocMtx(edWndCnt); - unsigned maxMicroSecs = floor(maxSecs*1000000); - unsigned edWndData[ edWndCnt ]; - cmScSyncState_t* edWndObj[ edWndCnt ]; - - // alloc a sync state record for each MIDI note-on in the time line - _cmScSyncTimeLineAllocFree(tlH, true ); - - // get the first time line object - cmTlObj_t* rfp = cmTimeLineNextTypeObj(tlH,NULL,cmInvalidId,kMidiFileTlId); - - // interate through the time line in search of MIDI file objects - for(; rfp != NULL; rfp = cmTimeLineNextTypeObj(tlH,rfp,cmInvalidId,kMidiFileTlId)) - { - cmTlMidiFile_t* mfp = cmTimeLineMidiFileObjPtr(tlH,rfp); - unsigned curEdWndCnt = 0; - double prog = 0.1; - unsigned progIdx = 0; - - cmRptPrintf(p->err.rpt,"MIDI File:%s\n", cmMidiFileName( mfp->h )); - - // get first midi event object - cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId); - - // iterate through the time line in search of MIDI note-on events with belong to mfp - for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId) ) - { - if( mep->obj.ref == rfp && mep->msg->status == kNoteOnMdId ) - { - // If this notes inter-onset time is greater than maxMicroSecs - // then dispose of the current window and begin refilling it again. - if( mep->msg->dtick > maxMicroSecs ) - curEdWndCnt = 0; - - // shift window one slot to left - unsigned i; - for(i=0; imsg->u.chMsgPtr->d0; // d0=pitch - edWndObj[ edWndCnt-1] = (cmScSyncState_t*)mep->obj.userDataPtr; - - ++curEdWndCnt; - - // if a complete window exists then update the time-line / score match state - if( curEdWndCnt >= edWndCnt ) - _cmScWndEditDist( p, edWndMtx, edWndData, edWndObj, edWndCnt ); - - // print the progress - ++progIdx; - if( progIdx >= prog * mfp->noteOnCnt ) - { - cmRptPrintf(p->err.rpt,"%i ",(unsigned)round(prog*10)); - prog += 0.1; - } - } - } - cmRptPrintf(p->err.rpt,"\n"); - } - - _cmScPrintSyncState(p,tlH ); - - // free sync state records - _cmScSyncTimeLineAllocFree(tlH,false); - - cmMemFree(edWndMtx); - - return kOkScRC; -} - - -cmScRC_t cmScoreSyncTimeLineTest( cmCtx_t* ctx, const cmChar_t* timeLineJsFn, const cmChar_t* scoreCsvFn ) -{ - cmScRC_t rc = kOkScRC; - cmTlH_t tlH = cmTimeLineNullHandle; - cmScH_t scH = cmScNullHandle; - unsigned edWndCnt = 7; - cmReal_t maxSecs = 2.0; - - if((rc = cmTimeLineInitialize(ctx,&tlH,NULL,NULL)) != kOkTlRC ) - return cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line initialization failed.");; - - if((rc = cmTimeLineReadJson(tlH,timeLineJsFn)) != kOkTlRC ) - { - rc = cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line parse failed.");; - goto errLabel; - } - - //cmTimeLinePrint(tlH,&ctx->rpt); - - if(1) - { - if((rc = cmScoreInitialize(ctx,&scH,scoreCsvFn,NULL,NULL)) != kOkScRC ) - goto errLabel; - - - rc = cmScoreSyncTimeLine(scH, tlH, edWndCnt, maxSecs ); - - } - //cmScorePrint(scH, ctx->err.rpt ); - - - - errLabel: - cmScoreFinalize(&scH); - cmTimeLineFinalize(&tlH); - - return rc; - -} -*/ - void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn ) { cmScH_t h = cmScNullHandle; - if( cmScoreInitialize(ctx,&h,fn,NULL,NULL) != kOkScRC ) + if( cmScoreInitialize(ctx,&h,fn,NULL,0,NULL,NULL) != kOkScRC ) return; cmScorePrint(h,&ctx->rpt); diff --git a/app/cmScore.h b/app/cmScore.h index 817d1cd..f757996 100644 --- a/app/cmScore.h +++ b/app/cmScore.h @@ -11,7 +11,8 @@ extern "C" { kCsvFailScRC, kSyntaxErrScRC, kInvalidIdxScRC, - kTimeLineFailScRC + kTimeLineFailScRC, + kInvalidDynRefCntScRC }; @@ -32,6 +33,7 @@ extern "C" { kNonEvtScId }; + // Flags used by cmScoreEvt_t.flags enum { kEvenScFl = 0x01, // This note is marked for evenness measurement @@ -41,17 +43,31 @@ extern "C" { kInvalidScFl = 0x10 // This note has a calculated time }; + + // Id's used by cmScoreSet_t.varId and as indexes into + // cmScoreSection_t.vars[]. + enum + { + kEvenVarScId, + kDynVarScId, + kTempoVarScId, + kScVarCnt + }; + + struct cmScoreLoc_str; + struct cmScoreSet_str; // The score can be divided into arbitrary non-overlapping sections. typedef struct { - const cmChar_t* label; // section label - struct cmScoreLoc_str* locPtr; // location where this section starts - unsigned begIndex; // score element index where this section starts - double evenCoeff; // - double dynCoeff; // - double tempoCeoff; // + const cmChar_t* label; // section label + unsigned index; // index of this record in the internal section array + struct cmScoreLoc_str* locPtr; // location where this section starts + unsigned begEvtIndex; // score element index where this section starts + unsigned setCnt; // Count of elements in setArray[] + struct cmScoreSet_str** setArray; // Ptrs to sets which are applied to this section. + double vars[ kScVarCnt ]; // Set to DBL_MAX by default. } cmScoreSection_t; typedef struct @@ -60,6 +76,7 @@ extern "C" { double secs; // Time location in seconds double durSecs; // Duration in seconds unsigned index; // Index of this event in the event array. + unsigned locIdx; // Index of the location containing this event cmMidiByte_t pitch; // MIDI pitch of this note unsigned flags; // Attribute flags for this event unsigned dynVal; // Dynamcis value pppp to ffff (1 to 11) for this note. @@ -68,28 +85,30 @@ extern "C" { unsigned csvRowNumb; // File row number (not index) from which this record originated unsigned perfSmpIdx; // Time this event was performed or cmInvalidIdx if the event was not performed. unsigned perfVel; // Velocity of the performed note or 0 if the note was not performed. + unsigned perfDynLvl; // Index into dynamic level ref. array assoc'd with perfVel } cmScoreEvt_t; typedef struct cmScoreSet_str { - unsigned typeFl; // See kXXXScFl flags above - cmScoreEvt_t** eleArray; // Events that make up this set in time order - unsigned eleCnt; // - cmScoreSection_t** sectArray; // Array of pointers to sections to apply this set to - unsigned sectCnt; // - struct cmScoreSet_str* link; // cmScoreLoc_t setList link + unsigned varId; // See kXXXVarScId flags above + cmScoreEvt_t** eleArray; // Events that make up this set in time order + unsigned eleCnt; // + bool doneFl; + double value; + struct cmScoreSet_str* llink; // cmScoreLoc_t setList link } cmScoreSet_t; // All events which are simultaneous are collected into a single // cmScoreLoc_t record. typedef struct cmScoreLoc_str - { + { + unsigned index; // index of this location record double secs; // Time of this location unsigned evtCnt; // Count of events in evtArray[]. cmScoreEvt_t** evtArray; // Events which occur at this time. unsigned barNumb; // Bar number this event is contained by. - cmScoreSet_t* setList; // Set's which end on this time location + cmScoreSet_t* setList; // Set's which end on this time location (linked through cmScoreSet_t.llink) cmScoreSection_t* begSectPtr; // NULL if this location does not start a section } cmScoreLoc_t; @@ -107,7 +126,11 @@ extern "C" { // Initialize a score object from a CSV File generated from a score spreadsheet. - cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg ); + // The dynRefArray[dynRefCnt] and cbFunc(cbArg) are optional if these + // features are not used. + // If provided the dynRefArray[] is copied into an internal array. + // The physical array passed here therefore does not need to remain valid. + cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, const unsigned* dynRefArray, unsigned dynRefCnt, cmScCb_t cbFunc, void* cbArg ); cmScRC_t cmScoreFinalize( cmScH_t* hp ); // Filename of last successfuly loaded score file. @@ -120,6 +143,10 @@ extern "C" { unsigned cmScoreEvtCount( cmScH_t h ); cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx ); + // Access section records + unsigned cmScoreSectionCount( cmScH_t h ); + cmScoreSection_t* cmScoreSection( cmScH_t h, unsigned idx ); + // Access the score location data unsigned cmScoreLocCount( cmScH_t h ); cmScoreLoc_t* cmScoreLoc( cmScH_t h, unsigned idx ); @@ -132,21 +159,56 @@ extern "C" { cmScRC_t cmScoreSeqNotify( cmScH_t h ); void cmScoreClearPerfInfo( cmScH_t h ); - void cmScoreSetPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ); - + + // Assign 'smpIdx' and 'vel' to the event matching 'pitch' at 'locIdx' + // but do not trigger any variable calculations. Return true if as a + // result of this call all events assigned to 'locIdx' have been received + // otherwise return false. + bool cmScoreSetPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ); + + // Assign 'smpIdx' and 'vel' to the event matching 'pitch' at 'locIdx' + // but and trigger any variable calculations which may happen on, or before, 'locIdx'. + void cmScoreExecPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel ); + + // Assign 'value' to the section at, or before, 'locIdx'. + void cmScoreSetPerfValue( cmScH_t h, unsigned locIdx, unsigned varId, double value ); + // Set the performed dynamic level of a score event. + void cmScoreSetPerfDynLevel( cmScH_t h, unsigned evtIdx, unsigned dynLvl ); + typedef enum { kInvalidMsgScId, kBeginMsgScId, kEventMsgScId, - kEndMsgScId + kSectionMsgScId, + kEndMsgScId, + kVarMsgScId, + kDynMsgScId } cmScMsgTypeId_t; + typedef struct + { + unsigned varId; // see kXXXVarScId from cmScoreSet_t.varId + double value; // value of a variable + } cmScMeas_t; + + typedef struct + { + unsigned evtIdx; + unsigned dynLvl; + } cmScDyn_t; + typedef struct { cmScMsgTypeId_t typeId; - cmScoreEvt_t evt; // only used when typeId == kEventMsgScId + union + { + cmScoreEvt_t evt; // only used when typeId == kEventMsgScId + cmScMeas_t meas; // only used when typeId == kVarMsgScId + cmScoreSection_t sect; // only used when typeId == kSectionMsgScId + cmScDyn_t dyn; // only used when typeId == kDynLvlMsgScId + } u; } cmScMsg_t; // Decode a serialized cmScMsg_t from a byte stream as passed to the diff --git a/cmGrPlot.c b/cmGrPlot.c index 40e914b..9f7d02d 100644 --- a/cmGrPlot.c +++ b/cmGrPlot.c @@ -47,6 +47,7 @@ typedef struct cmGrPlotObj_str unsigned fontSize; unsigned fontStyle; void* userPtr; + unsigned userByteCnt; // 0 if userPtr does not need to be realease on object destruction cmGrPlotCbFunc_t cbFunc; void* cbArg; @@ -102,6 +103,12 @@ cmGrPlRC_t _cmGrPlotObjDelete( cmGrPlotObj_t* op ) if( cmGrObjDestroy( op->grH, &op->grObjH ) != kOkGrRC ) return cmErrMsg( &p->err, kGrFailGrPlRC, "Delete failed on the object label='%s' id=%i\n",cmStringNullGuard( op->label ), cmGrObjId(op->grObjH) ); + if( op->userByteCnt != 0 ) + { + cmMemFree(op->userPtr); + op->userByteCnt = 0; + } + return kOkGrPlRC; } @@ -424,12 +431,13 @@ bool _cmGrPlotObjRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH ) // expand the ext's according to the physical offsets cmGrPExtExpand(&pext,op->loffs,op->toffs,op->roffs,op->boffs); + switch( op->typeId ) { case kLineGrPlId: - cmGrDcSetColor( dcH, _cmGrPlotColor(op,op->drawColors) ); - cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext) ); - break; + //cmGrDcSetColor( dcH, _cmGrPlotColor(op,op->drawColors) ); + //cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext) ); + //break; case kStarGrPlId: case kCrossGrPlId: @@ -476,6 +484,9 @@ bool _cmGrPlotObjRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH ) cmGrDcFillRect( dcH, pext.loc.x, pext.loc.y, pext.sz.w, pext.sz.h); break; + case kLineGrPlId: + break; + default: { assert(0); } } @@ -522,6 +533,9 @@ bool _cmGrPlotObjRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH ) cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2, cmGrPExtR(&pext), cmGrPExtT(&pext) + cmGrPExtH(&pext)/2); break; + case kLineGrPlId: + cmGrDcDrawLine( dcH, cmGrPExtL(&pext), cmGrPExtT(&pext), cmGrPExtR(&pext), cmGrPExtB(&pext) ); + break; case kRectGrPlId: case kHLineGrPlId: @@ -884,8 +898,35 @@ void cmGrPlotObjSetId( cmGrPlObjH_t oh, unsigned id ) void cmGrPlotObjSetUserPtr( cmGrPlObjH_t oh, void* userPtr ) { cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh); + if( op->userByteCnt != 0 ) + { + cmMemFree(op->userPtr); + op->userByteCnt = 0; + } + op->userPtr = userPtr; } + +void cmGrPlotObjAllocUser( cmGrPlObjH_t oh, const void* data, unsigned byteCnt ) +{ + cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh); + + if( op->userByteCnt != byteCnt ) + { + if( op->userByteCnt != 0 ) + { + cmMemFree(op->userPtr); + op->userByteCnt = 0; + } + + op->userPtr = cmMemAlloc(char,byteCnt); + op->userByteCnt = byteCnt; + } + + memcpy(op->userPtr,data,byteCnt); + +} + void* cmGrPlotObjUserPtr( cmGrPlObjH_t oh ) { cmGrPlotObj_t* op = _cmGrPlObjHandleToPtr(oh); diff --git a/cmGrPlot.h b/cmGrPlot.h index bb61a19..603d79a 100644 --- a/cmGrPlot.h +++ b/cmGrPlot.h @@ -148,6 +148,7 @@ extern "C" { unsigned cmGrPlotObjId( cmGrPlObjH_t oh ); void cmGrPlotObjSetUserPtr( cmGrPlObjH_t oh, void* userPtr ); + void cmGrPlotObjAllocUser( cmGrPlObjH_t oh, const void* data, unsigned byteCnt ); void* cmGrPlotObjUserPtr( cmGrPlObjH_t oh ); void cmGrPlotObjSetLabel( cmGrPlObjH_t oh, const cmChar_t* label ); diff --git a/dsp/cmDspClass.h b/dsp/cmDspClass.h index e4843ff..f04a2b6 100644 --- a/dsp/cmDspClass.h +++ b/dsp/cmDspClass.h @@ -31,7 +31,6 @@ extern "C" { kInstMsgRcvFailDspRC, kNetSendAllocFailDspRC, - kClassNotFoundDspRC, kInstNotFoundDspRC, kDuplInstSymIdDspRC, @@ -60,7 +59,6 @@ extern "C" { kSerializeUiMsgFailDspRC, - kSendToHostFailDspRC, kUiEleCreateFailDspRC, @@ -75,7 +73,6 @@ extern "C" { kInvalidPgmIdxDspRC, kPgmCfgFailDspRC - }; @@ -287,7 +284,7 @@ extern "C" { // Possible values for cmDspSetXXX() enum { - kUpdateUiDspFl = 0x00, + kUpdateUiDspFl = 0x00, // kNoUpdateUiDspFl = 0x01, // don't callback the UI kNoAllocDspFl = 0x02, // the caller is handling memory mgmt for the incoming value don't allocate space for it internally kSetDefaultDspFl = 0x04, // set the var default value rather than the current value @@ -393,7 +390,7 @@ extern "C" { 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 tlFileVarId, unsigned audPathVarId, unsigned selVarId, unsigned cursVarId ); - cmDspRC_t cmDspUiScoreCreate( cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned scFileVarId, unsigned selVarId ); + cmDspRC_t cmDspUiScoreCreate( cmDspCtx_t* ctx,cmDspInst_t* inst, unsigned scFileVarId, unsigned selVarId, unsigned smpIdxVarId, unsigned pitchVarId, unsigned velVarId, unsigned locIdxVarIdx, unsigned evtIdxVarIdx, unsigned dynLvlVarIdx, unsigned valTypeVarIdx, unsigned valueVarIdx ); 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 db96911..9ccf870 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -21,6 +21,7 @@ #include "cmDspCtx.h" #include "cmDspClass.h" #include "cmDspUi.h" +#include "cmDspSys.h" #include "cmMath.h" @@ -404,7 +405,16 @@ enum { kFnScId, kSelScId, - kSendScId + kSendScId, + kStatusScId, + kD0ScId, + kD1ScId, + kSmpIdxScId, + kLocIdxScId, + kEvtIdxScId, + kDynScId, + kValTypeScId, + kValueScId }; cmDspClass_t _cmScoreDC; @@ -413,15 +423,25 @@ typedef struct { cmDspInst_t inst; cmScH_t scH; + cmDspCtx_t* ctx; // temporary ctx ptr used during cmScore callback in _cmDspScoreRecv() } cmDspScore_t; cmDspInst_t* _cmDspScoreAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) { cmDspVarArg_t args[] = { - { "fn", kFnScId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." }, - { "sel", kSelScId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected score element index."}, - { "send", kSendScId, 0, 0, kInDsvFl | kTypeDsvMask, "Resend last selected score element."}, + { "fn", kFnScId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." }, + { "sel", kSelScId, 0, 0, kInDsvFl | kOutDsvFl | kUIntDsvFl, "Selected score element index input."}, + { "send", kSendScId, 0, 0, kInDsvFl | kTypeDsvMask, "Resend last selected score element."}, + { "status", kStatusScId, 0, 0, kInDsvFl | kIntDsvFl, "Performed MIDI status value output" }, + { "d0", kD0ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 0" }, + { "d1", kD1ScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDI msg data byte 1" }, + { "smpidx", kSmpIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performed MIDi msg time tag as a sample index." }, + { "loc", kLocIdxScId, 0, 0, kInDsvFl | kUIntDsvFl, "Performance score location."}, + { "evtidx", kEvtIdxScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Performed event index of following dynamcis level."}, + { "dyn", kDynScId, 0, 0, kOutDsvFl | kUIntDsvFl, "Dynamic level of previous event index."}, + { "type", kValTypeScId,0, 0, kOutDsvFl | kUIntDsvFl, "Output variable type."}, + { "value", kValueScId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output variable value."}, { NULL, 0, 0, 0, 0 } }; @@ -430,7 +450,7 @@ cmDspInst_t* _cmDspScoreAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned cmDspSetDefaultUInt( ctx, &p->inst, kSelScId, 0, cmInvalidId); // create the UI control - cmDspUiScoreCreate(ctx,&p->inst,kFnScId,kSelScId); + cmDspUiScoreCreate(ctx,&p->inst,kFnScId,kSelScId,kSmpIdxScId,kD0ScId,kD1ScId,kLocIdxScId,kEvtIdxScId,kDynScId,kValTypeScId,kValueScId); p->scH = cmScNullHandle; @@ -448,40 +468,94 @@ cmDspRC_t _cmDspScoreFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* return rc; } +// Callback from cmScore triggered from _cmDspScoreRecv() during call to cmScoreSetPerfEvent(). +void _cmDspScoreCb( void* arg, const void* data, unsigned byteCnt ) +{ + cmDspInst_t* inst = (cmDspInst_t*)arg; + cmDspScore_t* p = (cmDspScore_t*)inst; + cmScMsg_t m; + if( cmScoreDecode(data,byteCnt,&m) == kOkScRC ) + { + switch( m.typeId ) + { + case kDynMsgScId: + cmDspSetUInt( p->ctx,inst, kEvtIdxScId, m.u.dyn.evtIdx ); + cmDspSetUInt( p->ctx,inst, kDynScId, m.u.dyn.dynLvl ); + break; + + case kVarMsgScId: + cmDspSetUInt( p->ctx,inst, kValTypeScId, m.u.meas.varId); + cmDspSetDouble(p->ctx,inst, kValueScId, m.u.meas.value); + break; + + default: + { assert(0); } + } + } +} cmDspRC_t _cmDspScoreReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { - cmDspRC_t rc = kOkDspRC; - cmDspScore_t* p = (cmDspScore_t*)inst; + cmDspRC_t rc = kOkDspRC; + cmDspScore_t* p = (cmDspScore_t*)inst; + const cmChar_t* tlFn = NULL; + unsigned* dynRefArray = NULL; + unsigned dynRefCnt = 0; cmDspApplyAllDefaults(ctx,inst); - const cmChar_t* tlFn; + + if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC ) + { + rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found."); + goto errLabel; + } + if((tlFn = cmDspStrcz(inst, kFnScId )) != NULL ) - if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, NULL, NULL ) != kOkTlRC ) + if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, dynRefArray, dynRefCnt, _cmDspScoreCb, p ) != kOkTlRC ) rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Score file open failed."); + errLabel: return rc; } cmDspRC_t _cmDspScoreRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { + cmDspScore_t* p = (cmDspScore_t*)inst; + + if( evt->dstVarId == kSendScId ) + { + unsigned selIdx; + if((selIdx = cmDspUInt(inst,kSelScId)) != cmInvalidIdx ) + { + cmDspSetUInt(ctx,inst,kSelScId, selIdx ); + cmScoreClearPerfInfo(p->scH); + } + return kOkDspRC; + } + + cmDspSetEvent(ctx,inst,evt); + switch( evt->dstVarId ) { case kSelScId: - cmDspSetEvent(ctx,inst,evt); + cmScoreClearPerfInfo(p->scH); break; - case kSendScId: + case kStatusScId: + //printf("st:%x\n",cmDspUInt(inst,kStatusScId)); + break; + + case kLocIdxScId: { - unsigned selIdx; - if((selIdx = cmDspUInt(inst,kSelScId)) != cmInvalidIdx ) - cmDspSetUInt(ctx,inst,kSelScId, selIdx ); + assert( cmDspUInt(inst,kStatusScId ) == kNoteOnMdId ); + p->ctx = ctx; // setup p->ctx for use in _cmDspScoreCb() + + // this call may result in callbacks to _cmDspScoreCb() + cmScoreExecPerfEvent(p->scH, cmDspUInt(inst,kLocIdxScId), cmDspUInt(inst,kSmpIdxScId), cmDspUInt(inst,kD0ScId), cmDspUInt(inst,kD1ScId) ); } break; - default: - {assert(0);} } return kOkDspRC; @@ -619,6 +693,7 @@ cmDspRC_t _cmDspMidiFilePlayOpen(cmDspCtx_t* ctx, cmDspInst_t* inst ) // convert midi msg times to absolute time in samples cmMidiFileTickToSamples(p->mfH,cmDspSampleRate(ctx),true); + } return rc; } @@ -716,6 +791,7 @@ enum kD0SfId, kD1SfId, kSmpIdxSfId, + kCmdSfId, kOutSfId }; @@ -724,8 +800,10 @@ cmDspClass_t _cmScFolDC; typedef struct { cmDspInst_t inst; - cmScFol* sfp; + cmScTrk* sfp; cmScH_t scH; + unsigned printSymId; + unsigned quietSymId; } cmDspScFol_t; cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) @@ -742,6 +820,7 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"}, { "d1", kD1SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 1"}, { "smpidx",kSmpIdxSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI time tag as a sample index"}, + { "cmd", kCmdSfId, 0, 0, kInDsvFl | kSymDsvFl, "Command input: print | quiet"}, { "out", kOutSfId, 0, 0, kOutDsvFl| kUIntDsvFl, "Current score index."}, { NULL, 0, 0, 0, 0, NULL } }; @@ -752,7 +831,9 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned return NULL; - p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, cmScNullHandle, 0, 0, 0, 0 ); + p->sfp = cmScTrkAlloc(ctx->cmProcCtx, NULL, 0, cmScNullHandle, 0, 0, 0, 0 ); + p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"print"); + p->quietSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"quiet"); cmDspSetDefaultUInt( ctx, &p->inst, kBufCntSfId, 0, 7); cmDspSetDefaultUInt( ctx, &p->inst, kMinLkAhdSfId, 0, 10); @@ -760,6 +841,7 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned cmDspSetDefaultUInt( ctx, &p->inst, kMinVelSfId, 0, 5); cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0); cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0); + cmDspSetDefaultSymbol(ctx,&p->inst, kCmdSfId, p->quietSymId ); return &p->inst; } @@ -767,23 +849,33 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { cmDspScFol_t* p = (cmDspScFol_t*)inst; - cmScFolFree(&p->sfp); + cmScTrkFree(&p->sfp); cmScoreFinalize(&p->scH); return kOkDspRC; } cmDspRC_t _cmDspScFolOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst ) { + cmDspRC_t rc = kOkDspRC; + cmDspScFol_t* p = (cmDspScFol_t*)inst; + unsigned* dynRefArray = NULL; + unsigned dynRefCnt = 0; 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 ) + if( cmDspRsrcUIntArray(ctx->dspH, &dynRefCnt, &dynRefArray, "dynRef", NULL ) != kOkDspRC ) + { + rc = cmErrMsg(&inst->classPtr->err, kRsrcNotFoundDspRC, "The dynamics reference array resource was not found."); + goto errLabel; + } + + if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, NULL, 0, NULL, NULL ) != kOkScRC ) return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn); - return kOkDspRC; + errLabel: + return rc; } cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) @@ -796,7 +888,7 @@ cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* return rc; if( cmScoreIsValid(p->scH) ) - if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), p->scH, cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kMinLkAhdSfId), cmDspUInt(inst,kMaxWndCntSfId), cmDspUInt(inst,kMinVelSfId) ) != cmOkRC ) + if( cmScTrkInit(p->sfp, cmDspSampleRate(ctx), p->scH, cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kMinLkAhdSfId), cmDspUInt(inst,kMaxWndCntSfId), cmDspUInt(inst,kMinVelSfId) ) != cmOkRC ) rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed."); return rc; @@ -814,14 +906,14 @@ cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* { case kIndexSfId: if( cmScoreIsValid(p->scH) ) - if( cmScFolReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC ) + if( cmScTrkReset( p->sfp, cmDspUInt(inst,kIndexSfId) ) != cmOkRC ) cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Score follower reset to score index '%i' failed."); break; case kStatusSfId: if( cmScoreIsValid(p->scH)) { - unsigned idx = cmScFolExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId)); + unsigned idx = cmScTrkExec(p->sfp, ctx->cycleCnt, cmDspUInt(inst,kStatusSfId), cmDspUInt(inst,kD0SfId), cmDspUInt(inst,kD1SfId)); if( idx != cmInvalidIdx ) cmDspSetUInt(ctx,inst,kOutSfId,idx); } @@ -830,6 +922,15 @@ cmDspRC_t _cmDspScFolRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* case kFnSfId: _cmDspScFolOpenScore(ctx,inst); break; + + case kCmdSfId: + if( cmDspSymbol(inst,kCmdSfId) == p->printSymId ) + p->sfp->printFl = true; + else + if( cmDspSymbol(inst,kCmdSfId) == p->quietSymId ) + p->sfp->printFl = false; + + break; } } diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index 07b1f29..c88b854 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -86,11 +86,12 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysNewPage(h,"Controls"); cmDspInst_t* onb = cmDspSysAllocInst(h,"Button", "start", 2, kButtonDuiId, 1.0 ); cmDspInst_t* offb = cmDspSysAllocInst(h,"Button", "stop", 2, kButtonDuiId, 1.0 ); + cmDspInst_t* prtb = cmDspSysAllocInst(h,"Button", "print", 2, kButtonDuiId, 1.0 ); + cmDspInst_t* qtb = cmDspSysAllocInst(h,"Button", "quiet", 2, kButtonDuiId, 1.0 ); + cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL, 1, ">" ); + //cmDspInst_t* prd = cmDspSysAllocInst(h,"Printer", NULL, 1, "DYN:" ); + //cmDspInst_t* pre = cmDspSysAllocInst(h,"Printer", NULL, 1, "EVEN:" ); - - - cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL, 1, ">" ); - if((rc = cmDspSysLastRC(h)) != kOkDspRC ) return rc; @@ -125,14 +126,23 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, tlp, "mesi", mfp, "esi", NULL ); cmDspSysInstallCb(h, tlp, "mfn", mfp, "fn", NULL ); - // score to score follower + // score to score follower - to set initial search location cmDspSysInstallCb(h, scp, "sel", sfp, "index", NULL ); + - - // MIDI file player to score-follower - cmDspSysInstallCb(h, mfp, "status", sfp, "status", NULL ); - cmDspSysInstallCb(h, mfp, "d0", sfp, "d0", NULL ); + // MIDI file player to score-follower and score - the order of connections is the same + // as the msg transmision order from MFP + cmDspSysInstallCb(h, mfp, "smpidx", scp, "smpidx", NULL ); + cmDspSysInstallCb(h, mfp, "d1", scp, "d1", NULL ); cmDspSysInstallCb(h, mfp, "d1", sfp, "d1", NULL ); + cmDspSysInstallCb(h, mfp, "d0", scp, "d0", NULL ); + cmDspSysInstallCb(h, mfp, "d0", sfp, "d0", NULL ); + cmDspSysInstallCb(h, mfp, "status", scp, "status", NULL ); + cmDspSysInstallCb(h, mfp, "status", sfp, "status", NULL ); + + + // score follower to score + cmDspSysInstallCb(h, sfp, "out", scp, "loc", NULL ); // Printer connections @@ -141,6 +151,11 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, tlp, "sel", prp, "in", NULL ); //cmDspSysInstallCb(h, sfp, "out", prp, "in", NULL ); + //cmDspSysInstallCb(h, scp, "even", pre, "in", NULL ); + //cmDspSysInstallCb(h, scp, "dyn", prd, "in", NULL ); + + cmDspSysInstallCb(h, prtb, "sym", sfp, "cmd", NULL ); + cmDspSysInstallCb(h, qtb, "sym", sfp, "cmd", NULL ); return rc; } diff --git a/dsp/cmDspUi.c b/dsp/cmDspUi.c index 2d97fb9..c92ecb1 100644 --- a/dsp/cmDspUi.c +++ b/dsp/cmDspUi.c @@ -386,10 +386,10 @@ cmDspRC_t cmDspUiTimeLineCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned return rc; } -cmDspRC_t cmDspUiScoreCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned scFileVarId, unsigned selVarId ) +cmDspRC_t cmDspUiScoreCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned scFileVarId, unsigned selVarId, unsigned smpIdxVarId, unsigned pitchVarId, unsigned velVarId, unsigned locIdxVarId, unsigned evtIdxVarId, unsigned dynVarId, unsigned valTypeVarId, unsigned valueVarId ) { cmDspRC_t rc; - unsigned arr[] = { scFileVarId, selVarId }; + unsigned arr[] = { scFileVarId, selVarId, smpIdxVarId, pitchVarId, velVarId, locIdxVarId, evtIdxVarId, dynVarId, valTypeVarId, valueVarId }; cmDspValue_t v; unsigned vn = sizeof(arr)/sizeof(arr[0]); cmDsvSetUIntMtx(&v,arr,vn,1); @@ -402,6 +402,15 @@ cmDspRC_t cmDspUiScoreCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned scFi // Setting this flag will cause their values to be sent to the UI whenever they change. cmDspInstVarSetFlags( ctx, inst, scFileVarId, kUiDsvFl ); cmDspInstVarSetFlags( ctx, inst, selVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, smpIdxVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, pitchVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, velVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, locIdxVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, evtIdxVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, dynVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, valTypeVarId, kUiDsvFl ); + cmDspInstVarSetFlags( ctx, inst, valueVarId, kUiDsvFl ); + return rc; }