diff --git a/cmProc4.c b/cmProc4.c index f0f7aa4..51c9e19 100644 --- a/cmProc4.c +++ b/cmProc4.c @@ -1442,6 +1442,7 @@ void _cmScMatchPathPop( cmScMatch* r ) r->p_cur = tp; } + double _cmScMatchCalcCandidateCost( cmScMatch* r ) { cmScMatchPath_t* cp = r->p_cur; @@ -1959,7 +1960,7 @@ cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scW p->cbFunc = cbFunc; p->cbArg = cbArg; p->mn = midiWndN; - p->midiBuf = cmMemResize(cmScMatchMidi_t,p->midiBuf,p->mn); + p->midiBuf = cmMemResizeZ(cmScMatchMidi_t,p->midiBuf,p->mn); p->stepCnt = 3; p->maxMissCnt = p->stepCnt+1; p->rn = 2 * cmScoreEvtCount(scH); @@ -2552,8 +2553,8 @@ cmRC_t cmScMeasInit( cmScMeas* p, cmScH_t scH, double srate, const unsigned* p->mn = 2 * cmScoreEvtCount(scH); p->midiBuf = cmMemResizeZ(cmScMatchMidi_t,p->midiBuf,p->mn); p->sn = cmScoreSetCount(scH); - p->set = cmMemResize(cmScMeasSet_t,p->set,p->sn); - p->dynRef = cmMemResize(unsigned,p->dynRef,dynRefCnt); + p->set = cmMemResizeZ(cmScMeasSet_t,p->set,p->sn); + p->dynRef = cmMemResizeZ(unsigned,p->dynRef,dynRefCnt); p->dn = dynRefCnt; p->srate = srate; @@ -2753,7 +2754,7 @@ unsigned _cmScMeasTimeAlign( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, assert(b[0].smpIdx != cmInvalidIdx && b[bn-1].smpIdx != cmInvalidIdx); - // calc avg. smpIdx and insert missing values + // calc avg. smpIdx, insert missing values, and convert b[].smpIdx to delta smp index for(i=0,j=0; i 1 ) @@ -2820,7 +2821,7 @@ double _cmScMeasEven( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsign // calc std-dev of delta time double d_sd = 0; for(i=0; iobj, cmEofRC, "The MIDI buffer is full."); int n_mii = cmInvalidIdx; + // locate the MIDI event assoc'd with 'mni' ... if( p->mii>0 && mni <= p->midiBuf[p->mii-1].mni ) { @@ -3115,6 +3117,7 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI } p->vsi = p->nsi; + p->vsli = p->nsli; // for each cmScore location between p->nsli and scLocIdx for(; p->nsli<=scLocIdx && p->nsi < p->sn; ++p->nsli) @@ -3123,7 +3126,6 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI // ahead of the next sets ending location. while( cmMin(maxScLocIdx,p->set[p->nsi].esli+1) == p->nsli ) { - // calculate the value assoc'd with p->set[p->nsi] _cmScMeasCalcVal(p, p->set + p->nsi, n_mii ); @@ -3158,10 +3160,10 @@ cmRC_t cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top switch( rc ) { - case cmOkRC: // continue processing MIDI events + case cmOkRC: // continue processing MIDI events break; - case cmEofRC: // end of the score was encountered + case cmEofRC: // end of the score was encountered break; case cmInvalidArgRC: // p->eli was not set correctly @@ -3323,3 +3325,399 @@ void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH ) cmScMeasFree(&mp); cmCtxFree(&ctx); } + +//======================================================================================================================= +cmScModulator* cmScModulatorAlloc( cmCtx* c, cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg ) +{ + cmScModulator* op = cmObjAlloc(cmScModulator,c,p); + + if( ctx != NULL ) + if( cmScModulatorInit(op,ctx,stH,srate,samplesPerCycle,fn,modLabel,cbFunc,cbArg) != cmOkRC ) + cmScModulatorFree(&op); + + return op; +} + +cmRC_t cmScModulatorFree( cmScModulator** pp ) +{ + cmRC_t rc = cmOkRC; + if( pp==NULL || *pp==NULL ) + return rc; + + cmScModulator* p = *pp; + if((rc = cmScModulatorFinal(p)) != cmOkRC ) + return rc; + + cmMemFree(p->earray); + cmObjFree(pp); + return rc; +} + +typedef struct +{ + unsigned typeId; + unsigned minArgCnt; + const cmChar_t* label; +} _cmScModTypeMap_t; + +_cmScModTypeMap_t _cmScModTypeArray[] = +{ + { kSetModTId, 1, "set" }, + { kLineModTId, 2, "line" }, + { kSetLineModTId, 3, "sline" }, + { kInvalidModTId, 0, ""} +}; + +const _cmScModTypeMap_t* _cmScModTypeLabelToMap( const cmChar_t* label ) +{ + unsigned i; + for(i=0; _cmScModTypeArray[i].typeId!=kInvalidModTId; ++i) + if( strcmp(_cmScModTypeArray[i].label,label) == 0 ) + return _cmScModTypeArray + i; + + return NULL; +} + +cmScModVar_t* _cmScModulatorInsertValue( cmScModulator* p, unsigned varSymId ) +{ + cmScModVar_t* vp = p->vlist; + for(; vp!=NULL; vp=vp->vlink) + if( varSymId == vp->varSymId ) + return vp; + + vp = cmMemAllocZ(cmScModVar_t,1); + vp->varSymId = varSymId; + vp->vlink = p->vlist; + p->vlist = vp; + return vp; +} + +cmRC_t _cmScModulatorInsertEntry(cmScModulator* p, unsigned idx, unsigned scLocIdx, unsigned modSymId, unsigned varSymId, unsigned typeId, const double* av, unsigned an) +{ + assert( idx < p->en ); + + if( p->modSymId != modSymId ) + return cmOkRC; + + p->earray[idx].scLocIdx = scLocIdx; + p->earray[idx].typeId = typeId; + p->earray[idx].parray = an==0 ? NULL : cmMemAllocZ(double,an); + p->earray[idx].pn = an; + p->earray[idx].valPtr = _cmScModulatorInsertValue(p,varSymId); + + unsigned i; + for(i=0; iearray[idx].parray[i] = av[i]; + + return cmOkRC; +} + + +/* +{ + [ + { loc:123, mod:modlabel, var:varlabel, param:[ ] } + ] +} + */ + + cmRC_t _cmScModulatorParse( cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, const cmChar_t* fn ) +{ + cmRC_t rc = cmOkRC; + cmJsonNode_t* jnp = NULL; + cmJsonH_t jsH = cmJsonNullHandle; + unsigned i; + + // read the JSON file + if( cmJsonInitializeFromFile(&jsH, fn, ctx ) != kOkJsRC ) + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "JSON file parse failed on the modulator file: %s.",cmStringNullGuard(fn) ); + + jnp = cmJsonRoot(jsH); + + // validate that the first child as an array + if( jnp==NULL || ((jnp = cmJsonNodeMemberValue(jnp,"array")) == NULL) || cmJsonIsArray(jnp)==false ) + { + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Modulator file header syntax error in file:%s",cmStringNullGuard(fn) ); + goto errLabel; + } + + // allocate the entry array + p->en = cmJsonChildCount(jnp); + p->earray = cmMemResizeZ(cmScModEntry_t,p->earray,p->en); + + for(i=0; ien; ++i) + { + cmJsRC_t jsRC; + const char* errLabelPtr = NULL; + unsigned scLocIdx = cmInvalidIdx; + const cmChar_t* modLabel = NULL; + const cmChar_t* varLabel = NULL; + const cmChar_t* typeLabel = NULL; + cmJsonNode_t* onp = cmJsonArrayElement(jnp,i); + cmJsonNode_t* dnp = NULL; + const _cmScModTypeMap_t* map = NULL; + + if((jsRC = cmJsonMemberValues( onp, &errLabelPtr, + "loc", kIntTId, &scLocIdx, + "mod", kStringTId, &modLabel, + "var", kStringTId, &varLabel, + "type",kStringTId, &typeLabel, + NULL )) != kOkJsRC ) + { + if( errLabelPtr == NULL ) + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Error:%s on record at index %i in file:%s",errLabelPtr,i,cmStringNullGuard(fn) ); + else + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Synax error in Modulator record at index %i in file:%s",i,cmStringNullGuard(fn) ); + goto errLabel; + } + + // validate the entry type label + if((map = _cmScModTypeLabelToMap(typeLabel)) == NULL ) + { + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Unknown entry type '%s' in Modulator record at index %i in file:%s",cmStringNullGuard(typeLabel),i,cmStringNullGuard(fn) ); + goto errLabel; + } + + // get a data pointer to the data node + if((dnp = cmJsonNodeMemberValue(onp,"data")) == NULL ) + { + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Synax error in Modulator 'data' record at index %i in file:%s",i,cmStringNullGuard(fn) ); + goto errLabel; + } + + unsigned modSymId = cmSymTblRegisterSymbol(stH,modLabel); + unsigned varSymId = cmSymTblRegisterSymbol(stH,varLabel); + + // the data may be an array of doubles .... + if( cmJsonIsArray(dnp) ) + { + unsigned an = cmJsonChildCount(dnp); + double av[an]; + unsigned j; + + // read each element in the data array + for(j=0; jobj, cmInvalidArgRC, "Error parsing in Modulator 'data' record at index %i value index %i in file:%s",i,j,cmStringNullGuard(fn) ); + goto errLabel; + } + + _cmScModulatorInsertEntry(p,i,scLocIdx,modSymId,varSymId,map->typeId,av,an); + } + else // ... or a scalar + { + double v; + if( cmJsonRealValue(dnp,&v) != kOkJsRC ) + { + rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Error paring in Modulator 'data' on record index %i.",i,cmStringNullGuard(fn)); + goto errLabel; + } + + _cmScModulatorInsertEntry(p,i,scLocIdx,modSymId,varSymId,map->typeId,&v,1); + + } + } + + errLabel: + + // release the JSON tree + if( cmJsonIsValid(jsH) ) + cmJsonFinalize(&jsH); + + return rc; +} + +cmRC_t cmScModulatorInit( cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg ) +{ + cmRC_t rc; + + if((rc = cmScModulatorFinal(p)) != cmOkRC ) + return rc; + + p->modSymId = cmSymTblRegisterSymbol(stH,modLabel); + p->cbFunc = cbFunc; + p->cbArg = cbArg; + p->samplesPerCycle = samplesPerCycle; + p->srate = srate; + + if((rc = _cmScModulatorParse(p,ctx,stH,fn)) != cmOkRC ) + goto errLabel; + + errLabel: + if( rc != cmOkRC ) + cmScModulatorFinal(p); + else + cmScModulatorReset(p,0); + + return rc; +} + +cmRC_t cmScModulatorFinal( cmScModulator* p ) +{ + unsigned i; + + // release each value record + cmScModVar_t* vp = p->vlist; + while( vp!=NULL ) + { + cmScModVar_t* np = vp->vlink; + cmMemFree(vp); + vp=np; + } + + // release each entry record + for(i=0; ien; ++i) + cmMemFree(p->earray[i].parray); + + return cmOkRC; +} + +unsigned cmScModulatorVarCount( cmScModulator* p ) +{ + unsigned n = 0; + const cmScModVar_t* vp = p->vlist; + for(; vp!=NULL; vp=vp->vlink) + ++n; + + return n; +} + +cmScModVar_t* cmScModulatorVar( cmScModulator* p, unsigned idx ) +{ + unsigned n = 0; + cmScModVar_t* vp = p->vlist; + for(; vp!=NULL; vp=vp->vlink,++n) + if( n == idx ) + return vp; + + assert(0); + return NULL; +} + +cmRC_t cmScModulatorReset( cmScModulator* p, unsigned scLocIdx ) +{ + p->alist = NULL; + p->nei = 0; + + return cmScModulatorExec(p,scLocIdx); +} + +void _cmScModUnlink( cmScModulator* p, cmScModVar_t* vp, cmScModVar_t* pp ) +{ + if( pp == NULL ) + p->alist = vp->alink; + else + pp->alink = vp->alink; + + vp->flags = 0; + vp->alink = NULL; + vp->entry = NULL; +} + +// Type specific variable activation +cmRC_t _cmScModActivate(cmScModulator* p, cmScModEntry_t* ep ) +{ + cmRC_t rc = cmOkRC; + + cmScModVar_t* vp = ep->valPtr; + + switch( ep->typeId ) + { + case kSetModTId: + break; + + case kLineModTId: + vp->v0 = vp->value; + vp->phase = 0; + break; + + case kSetLineModTId: + vp->value = ep->parray[0]; + vp->v0 = ep->parray[0]; + vp->phase = 0; + ep->parray[0] = ep->parray[1]; + ep->parray[1] = ep->parray[2]; + break; + + default: + { assert(0); } + } + + return rc; +} + +// Return true if vp should be deactivated otherwise return false. +bool _cmScModExec( cmScModulator* p, cmScModVar_t* vp ) +{ + bool fl = false; + switch( vp->entry->typeId ) + { + case kSetModTId: + p->cbFunc(p->cbArg,vp->varSymId,vp->entry->parray[0]); + fl = true; + break; + + case kSetLineModTId: + case kLineModTId: + { + double v1 = vp->entry->parray[0]; + double v = vp->value + (v1-vp->v0) * (vp->phase * p->samplesPerCycle) / (p->srate * vp->entry->parray[1]); + + if((fl = (vp->value <= v1 && v >= v1) || (vp->value >= v1 && v <= v1 )) == true ) + v = v1; + + vp->phase += 1; + vp->value = v; + p->cbFunc(p->cbArg,vp->varSymId,v); + } + break; + + default: + { assert(0); } + } + return fl; +} + + +cmRC_t cmScModulatorExec( cmScModulator* p, unsigned scLocIdx ) +{ + cmRC_t trc; + cmRC_t rc = cmOkRC; + + // trigger entries that have expired since the last call to this function + for(; p->neien && p->earray[p->nei].scLocIdx<=scLocIdx; ++p->nei) + { + cmScModEntry_t* ep = p->earray + p->nei; + + // if the variable assoc'd with this entry is not on the active list ... + if( cmIsFlag(ep->valPtr->flags,kActiveModFl) == false ) + { + // ... then push it onto the front of the active list ... + ep->valPtr->flags = kActiveModFl; + ep->valPtr->alink = p->alist; + p->alist = ep->valPtr; + } + + + // do type specific activation + if((trc = _cmScModActivate(p,ep)) != cmOkRC ) + rc = trc; + + ep->valPtr->entry = ep; + + } + + + cmScModVar_t* pp = NULL; + cmScModVar_t* vp = p->alist; + for(; vp!=NULL; vp=vp->alink) + { + if( _cmScModExec(p,vp) ) + _cmScModUnlink(p,vp,pp); + else + pp = vp; + } + + return rc; +} diff --git a/cmProc4.h b/cmProc4.h index f563f0e..d1a80cc 100644 --- a/cmProc4.h +++ b/cmProc4.h @@ -436,7 +436,7 @@ typedef struct unsigned nsli; // next score location index unsigned vsi; // set[vsi:nsi-1] indicates sets with new values following a call to cmScMeasExec() - + unsigned vsli; // vsli:nsli-1 indicates cmScore loc's to check for section triggers following a call to cmScMeasExec() } cmScMeas; // @@ -448,7 +448,9 @@ typedef struct // 2) dynRef][ is the gives the MIDI velocity range for each dynamics // category: pppp-fff // - +// 3) See a cmDspKr.c _cmScFolMatcherCb() for an example of how +// cmScMeas.vsi and cmScMeas.vsli are used to act on the results of +// a call to cmMeasExec(). cmScMeas* cmScMeasAlloc( cmCtx* c, cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt ); cmRC_t cmScMeasFree( cmScMeas** pp ); @@ -475,6 +477,75 @@ unsigned cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* // notes in each marker region and the score. void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH ); +//======================================================================================================================= +enum +{ + kInvalidModTId, + kSetModTId, // set variable to parray[0] at scLocIdx + kLineModTId, // linear ramp variable to parray[0] over parray[1] seconds + kSetLineModTId, // set variable to parray[0] and ramp to parray[1] over parray[2] seconds +}; + +enum +{ + kActiveModFl = 0x01 +}; + +struct cmScModEntry_str; + +typedef struct cmScModVar_str +{ + unsigned flags; // see kXXXModFl flags above. + unsigned varSymId; // variable name + double value; // current value + double v0; // reserved internal variable + unsigned phase; // cycle phase since activation + struct cmScModEntry_str* entry; // last entry assoc'd with this value + struct cmScModVar_str* vlink; // p->vlist link + struct cmScModVar_str* alink; // p->alist link +} cmScModVar_t; + +typedef struct cmScModEntry_str +{ + unsigned scLocIdx; // entry start time + unsigned typeId; // variable type + double* parray; // parray[pn] - parameter array + unsigned pn; // parameter count + cmScModVar_t* valPtr; // target variable +} cmScModEntry_t; + +typedef void (*cmScModCb_t)( void* cbArg, unsigned varSymId, double value ); + +typedef struct +{ + cmObj obj; + unsigned modSymId; // modulator name + cmScModCb_t cbFunc; // active value callback function + void* cbArg; // first arg to cbFunc() + unsigned samplesPerCycle; // interval in samples between calls to cmScModulatorExec() + double srate; // system sample rate + cmScModEntry_t* earray; // earray[en] - entry array sorted on ascending cmScModEntry_t.scLocIdx + unsigned en; // count + cmScModVar_t* vlist; // variable list + cmScModVar_t* alist; // active variable list + unsigned nei; // next entry index +} cmScModulator; + + +cmScModulator* cmScModulatorAlloc( cmCtx* c, cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg ); +cmRC_t cmScModulatorFree( cmScModulator** pp ); +cmRC_t cmScModulatorInit( cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg ); +cmRC_t cmScModulatorFinal( cmScModulator* p ); + +// Return count of variables. +unsigned cmScModulatorVarCount( cmScModulator* p ); + +// Return a pointer to the variable at vlist[idx]. +cmScModVar_t* cmScModulatorVar( cmScModulator* p, unsigned idx ); + +cmRC_t cmScModulatorReset( cmScModulator* p, unsigned scLocIdx ); +cmRC_t cmScModulatorExec( cmScModulator* p, unsigned scLocIdx ); + #ifdef __cplusplus } #endif diff --git a/dsp/cmDspBuiltIn.c b/dsp/cmDspBuiltIn.c index 1022715..6ac2593 100644 --- a/dsp/cmDspBuiltIn.c +++ b/dsp/cmDspBuiltIn.c @@ -5019,7 +5019,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cmScoreClassCons, cmMidiFilePlayClassCons, cmScFolClassCons, - + cmScModClassCons, NULL, }; diff --git a/dsp/cmDspKr.c b/dsp/cmDspKr.c index f2b40ce..3884459 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -11,6 +11,7 @@ #include "cmFile.h" #include "cmSymTbl.h" #include "cmJson.h" +#include "cmText.h" #include "cmPrefs.h" #include "cmDspValue.h" #include "cmMsgProtocol.h" @@ -154,6 +155,10 @@ cmDspRC_t _cmDspKrExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt unsigned iChIdx = 0; const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kAudioInKrId,iChIdx); unsigned iSmpCnt = cmDspVarRows(inst,kAudioInKrId); + + // if no connected + if( iSmpCnt == 0 ) + return rc; unsigned oChIdx = 0; cmSample_t* op = cmDspAudioBuf(ctx,inst,kAudioOutKrId,oChIdx); @@ -896,16 +901,20 @@ cmDspRC_t _cmDspScFolFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* return kOkDspRC; } +// This is a callback function from cmScMatcherExec() which is called when +// this cmDspFol object receives a new score location index. void _cmScFolMatcherCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp ) { cmDspScFolCbArg_t* ap = (cmDspScFolCbArg_t*)arg; + if( cmScMeasExec(ap->sfp->smp, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel ) == cmOkRC ) { - cmDspInst_t* inst = (cmDspInst_t*)ap->sfp; + cmDspInst_t* inst = &(ap->sfp->inst); + // send 'set' values that were calculated on the previous call to cmScMeasExec() unsigned i; - for(i=ap->sfp->smp->vsi; isfp->smp->nsi; i++) + for(i=ap->sfp->smp->vsi; isfp->smp->nsi; ++i) { switch( ap->sfp->smp->set[i].sp->varId ) { @@ -925,6 +934,16 @@ void _cmScFolMatcherCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp ) { assert(0); } } } + + /* + // trigger 'section' starts + for(i=ap->sfp->smp->vsli; isfp->smp->nsli; ++i) + { + const cmScoreLoc_t* locPtr = cmScoreLoc(ap->sfp->smp->mp->scH,i); + if( locPtr->begSectPtr != NULL ) + cmDspSetUInt(ap->ctx,inst,kSectIndexSfId,locPtr->begSectPtr->index); + } + */ } } @@ -1047,3 +1066,149 @@ struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx ) return &_cmScFolDC; } +//========================================================================================================================================== + +enum +{ + kScLocIdxMdId +}; + +cmDspClass_t _cmModulatorDC; + +typedef struct +{ + cmDspInst_t inst; + cmScModulator* mp; + cmDspCtx_t* tmp_ctx; // used to temporarily hold the current cmDspCtx during callback +} cmDspScMod_t; + +void _cmDspScModCb( void* arg, unsigned varSymId, double value ) +{ + cmDspScMod_t* p = (cmDspScMod_t*)arg; + + cmDspVar_t* varPtr; + if((varPtr = cmDspVarSymbolToPtr( p->tmp_ctx, &p->inst, varSymId, 0 )) == NULL ) + return; + + cmDspSetDouble(p->tmp_ctx,&p->inst,varPtr->constId,value); + +} + +cmDspInst_t* _cmDspScModAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + va_list vl1; + va_copy(vl1,vl); + + cmDspVarArg_t args[] = + { + { "index", kScLocIdxMdId,0,0, kInDsvFl | kUIntDsvFl, "Score follower index input."}, + { NULL, 0, 0, 0, 0 } + }; + + // validate the argument count + if( va_cnt != 2 ) + { + cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The Modulator requires at least two arguments."); + return NULL; + } + + // read the modulator file and label strings + const cmChar_t* fn = va_arg(vl1,const cmChar_t*); + const cmChar_t* modLabel = va_arg(vl1,const cmChar_t*); + + // validate the file + if( fn==NULL || cmFsIsFile(fn)==false ) + { + cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The Modulator file '%s' is not valid.",cmStringNullGuard(fn)); + return NULL; + } + + // allocate the internal modulator object + cmScModulator* mp = cmScModulatorAlloc(ctx->cmProcCtx, NULL, ctx->cmCtx, ctx->stH, cmDspSampleRate(ctx), cmDspSamplesPerCycle(ctx), fn, modLabel, _cmDspScModCb, NULL ); + + if(mp == NULL ) + { + cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The internal modulator object initialization failed."); + return NULL; + } + unsigned fixArgCnt = 1; + unsigned argCnt = fixArgCnt + cmScModulatorVarCount(mp); + cmDspVarArg_t a[ argCnt+1 ]; + unsigned i; + + cmDspArgCopy( a, argCnt, 0, args, fixArgCnt ); + + for(i=fixArgCnt; istH, vp->varSymId ); + const cmChar_t* docStr = cmTsPrintfS("Variable output for %s",label); + + cmDspArgSetup(ctx, a + i, label, cmInvalidId, i, 0, 0, kOutDsvFl | kDoubleDsvFl, docStr ); + } + cmDspArgSetupNull(a+argCnt); // set terminating arg. flags + + cmDspScMod_t* p = cmDspInstAlloc(cmDspScMod_t,ctx,classPtr,a,instSymId,id,storeSymId,0,vl); + + p->mp = mp; + mp->cbArg = p; // set the modulator callback arg + + cmDspSetDefaultUInt(ctx,&p->inst,kScLocIdxMdId,0,0); + + return &p->inst; +} + +cmDspRC_t _cmDspScModFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspScMod_t* p = (cmDspScMod_t*)inst; + + if( cmScModulatorFree(&p->mp) != kOkTlRC ) + return cmErrMsg(&inst->classPtr->err, kInstFinalFailDspRC, "Modulator release failed."); + + return rc; +} + + +cmDspRC_t _cmDspScModReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + + cmDspApplyAllDefaults(ctx,inst); + + return rc; +} + +cmDspRC_t _cmDspScModRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + + cmDspSetEvent(ctx,inst,evt); + + return kOkDspRC; +} + +cmDspRC_t _cmDspScModExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspScMod_t* p = (cmDspScMod_t*)inst; + + p->tmp_ctx = ctx; + cmScModulatorExec(p->mp,cmDspUInt(inst,kScLocIdxMdId)); + return rc; +} + +struct cmDspClass_str* cmScModClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmModulatorDC,ctx,"ScMod", + NULL, + _cmDspScModAlloc, + _cmDspScModFree, + _cmDspScModReset, + _cmDspScModExec, + _cmDspScModRecv, + NULL,NULL, + "Score Driven Variable Modulator."); + + return &_cmModulatorDC; +} diff --git a/dsp/cmDspKr.h b/dsp/cmDspKr.h index ee6853d..b933342 100644 --- a/dsp/cmDspKr.h +++ b/dsp/cmDspKr.h @@ -10,6 +10,7 @@ extern "C" { struct cmDspClass_str* cmScoreClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmScFolClassCons( cmDspCtx_t* ctx ); + struct cmDspClass_str* cmScModClassCons( cmDspCtx_t* ctx ); #ifdef __cplusplus } diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index e33ad1d..1c1af53 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -38,7 +38,7 @@ typedef struct const cmChar_t* tlFn; const cmChar_t* audPath; const cmChar_t* scFn; - + const cmChar_t* modFn; } krRsrc_t; cmDspRC_t krLoadRsrc(cmDspSysH_t h, cmErr_t* err, krRsrc_t* r) @@ -50,6 +50,7 @@ cmDspRC_t krLoadRsrc(cmDspSysH_t h, cmErr_t* err, krRsrc_t* r) cmDspRsrcString(h,&r->tlFn, "timeLineFn", NULL); cmDspRsrcString(h,&r->audPath,"tlAudioFilePath", NULL); cmDspRsrcString(h,&r->scFn, "scoreFn", NULL); + cmDspRsrcString(h,&r->modFn, "modFn", NULL); if((rc = cmDspSysLastRC(h)) != kOkDspRC ) cmErrMsg(err,rc,"A KR DSP resource load failed."); @@ -66,6 +67,8 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) unsigned wtLoopCnt = 1; // 1=play once (-1=loop forever) unsigned wtInitMode = 0; // initial wt mode is 'silence' unsigned wtSmpCnt = floor(cmDspSysSampleRate(h)); // wt length == srate + int krWndSmpCnt = 2048; + int krHopFact = 4; memset(&r,0,sizeof(r)); cmErrSetup(&err,&cmCtx->rpt,"Kr Timeline"); @@ -80,6 +83,9 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* pts = cmDspSysAllocInst(h,"PortToSym", NULL, 2, "on", "off" ); cmDspInst_t* mfp = cmDspSysAllocInst(h,"MidiFilePlay",NULL, 0 ); cmDspInst_t* sfp = cmDspSysAllocInst(h,"ScFol", NULL, 1, r.scFn ); + cmDspInst_t* kr0p = cmDspSysAllocInst(h,"Kr", NULL, 2, krWndSmpCnt, krHopFact ); + cmDspInst_t* kr1p = cmDspSysAllocInst(h,"Kr", NULL, 2, krWndSmpCnt, krHopFact ); + cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 ); cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 ); @@ -89,14 +95,44 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) 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* prd = cmDspSysAllocInst(h,"Printer", NULL, 1, "DYN:" ); + cmDspInst_t* pre = cmDspSysAllocInst(h,"Printer", NULL, 1, "EVEN:" ); + cmDspInst_t* prt = cmDspSysAllocInst(h,"Printer", NULL, 1, "TEMPO:"); + //cmDspInst_t* prv = cmDspSysAllocInst(h,"Printer", NULL, 1, "Value:"); + cmDspSysNewColumn(h,0); + + cmDspInst_t* md0p = cmDspSysAllocInst(h,"Scalar", "Mode", 5, kNumberDuiId, 0.0, 4.0, 1.0, 1.0); + cmDspInst_t* ws0p = cmDspSysAllocInst(h,"MsgList","wndSmpCnt", 3, "wndSmpCnt", NULL, 2); + cmDspInst_t* hf0p = cmDspSysAllocInst(h,"MsgList","hopFact", 3, "hopFact", NULL, 2); + cmDspInst_t* th0p = cmDspSysAllocInst(h,"Scalar", "threshold", 5, kNumberDuiId, 0.0, 100.0, 1.0, 60.0 ); + cmDspInst_t* us0p = cmDspSysAllocInst(h,"Scalar", "upr slope", 5, kNumberDuiId, 0.0, 10.0, 0.01, 0.0 ); + cmDspInst_t* ls0p = cmDspSysAllocInst(h,"Scalar", "lwr slope", 5, kNumberDuiId, 0.3, 10.0, 0.01, 2.0 ); + cmDspInst_t* of0p = cmDspSysAllocInst(h,"Scalar", "offset", 5, kNumberDuiId, 0.0, 100.0, 0.01, 30.0 ); + cmDspInst_t* iv0p = cmDspSysAllocInst(h,"Scalar", "invert", 5, kNumberDuiId, 0.0, 1.0, 1.0, 0.0 ); + cmDspSysNewColumn(h,0); + + //cmDspInst_t* al1p = cmDspSysAllocInst(h,"MsgList","audFiles", 2, "audFiles",NULL); + //cmDspInst_t* fl1p = cmDspSysAllocInst(h,"MsgList","audFrags1", 2, "audFrags",NULL); + //cmDspInst_t* fn1p = cmDspSysAllocInst(h,"Sprintf","filename", 1, "%s/%s_%02i.wav"); + cmDspInst_t* md1p = cmDspSysAllocInst(h,"Scalar", "Mode1", 5, kNumberDuiId, 0.0, 4.0, 1.0, 1.0); + cmDspInst_t* ws1p = cmDspSysAllocInst(h,"MsgList","wndSmpCnt1", 3, "wndSmpCnt", NULL, 2); + cmDspInst_t* hf1p = cmDspSysAllocInst(h,"MsgList","hopFact1", 3, "hopFact", NULL, 2); + cmDspInst_t* th1p = cmDspSysAllocInst(h,"Scalar", "threshold1", 5, kNumberDuiId, 0.0, 100.0, 1.0, 60.0 ); + cmDspInst_t* us1p = cmDspSysAllocInst(h,"Scalar", "upr slope1", 5, kNumberDuiId, 0.0, 10.0, 0.01, 0.0 ); + cmDspInst_t* ls1p = cmDspSysAllocInst(h,"Scalar", "lwr slope1", 5, kNumberDuiId, 0.3, 10.0, 0.01, 2.0 ); + cmDspInst_t* of1p = cmDspSysAllocInst(h,"Scalar", "offset1", 5, kNumberDuiId, 0.0, 100.0, 0.01, 30.0 ); + cmDspInst_t* iv1p = cmDspSysAllocInst(h,"Scalar", "invert1", 5, kNumberDuiId, 0.0, 1.0, 1.0, 0.0 ); + if((rc = cmDspSysLastRC(h)) != kOkDspRC ) return rc; // phasor->wt->aout cmDspSysConnectAudio(h, php, "out", wtp, "phs" ); // phs -> wt + //cmDspSysConnectAudio(h, wtp, "out", kr0p, "in" ); // wt->kr + //cmDspSysConnectAudio(h, wtp, "out", kr1p, "in" ); + //cmDspSysConnectAudio(h, kr0p, "out", ao0p, "in"); // kr->aout- 0 + //cmDspSysConnectAudio(h, kr1p, "out", ao1p, "in"); cmDspSysConnectAudio(h, wtp, "out", ao0p, "in" ); // wt -> aout0 cmDspSysConnectAudio(h, wtp, "out", ao1p, "in" ); // wt -> aout1 @@ -132,27 +168,51 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) // 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, "smpidx", scp, "smpidx", NULL ); + cmDspSysInstallCb(h, mfp, "smpidx", sfp, "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", scp, "d0", NULL ); cmDspSysInstallCb(h, mfp, "d0", sfp, "d0", NULL ); - cmDspSysInstallCb(h, mfp, "status", scp, "status", 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 ); + //cmDspSysInstallCb(h, sfp, "out", modp, "index", NULL ); + cmDspSysInstallCb(h, ws0p, "out", kr0p, "wndn", NULL ); // wndSmpCnt->kr + cmDspSysInstallCb(h, hf0p, "out", kr0p, "hopf", NULL ); // hopFact->kr + cmDspSysInstallCb(h, md0p, "val", kr0p, "mode", NULL ); // mode->kr + cmDspSysInstallCb(h, th0p, "val", kr0p, "thrh", NULL ); // thresh->kr + cmDspSysInstallCb(h, ls0p, "val", kr0p, "lwrs", NULL ); // lwrSlope->kr + cmDspSysInstallCb(h, us0p, "val", kr0p, "uprs", NULL ); // uprSlope->kr + cmDspSysInstallCb(h, of0p, "val", kr0p, "offs", NULL ); // offset->kr + cmDspSysInstallCb(h, iv0p, "val", kr0p, "invt", NULL ); // invert->kr + + cmDspSysInstallCb(h, ws1p, "out", kr1p, "wndn", NULL ); // wndSmpCnt->kr + cmDspSysInstallCb(h, hf1p, "out", kr1p, "hopf", NULL ); // hopFact->kr + cmDspSysInstallCb(h, md1p, "val", kr1p, "mode", NULL ); // mode->kr + cmDspSysInstallCb(h, th1p, "val", kr1p, "thrh", NULL ); // thresh->kr + cmDspSysInstallCb(h, ls1p, "val", kr1p, "lwrs", NULL ); // lwrSlope->kr + cmDspSysInstallCb(h, us1p, "val", kr1p, "uprs", NULL ); // uprSlope->kr + cmDspSysInstallCb(h, of1p, "val", kr1p, "offs", NULL ); // offset->kr + cmDspSysInstallCb(h, iv1p, "val", kr1p, "invt", NULL ); // invert->kr + // Printer connections cmDspSysInstallCb(h, tlp, "afn", prp, "in", NULL ); cmDspSysInstallCb(h, tlp, "mfn", prp, "in", NULL ); 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, sfp, "even", pre, "in", NULL ); + cmDspSysInstallCb(h, sfp, "dyn", prd, "in", NULL ); + cmDspSysInstallCb(h, sfp, "tempo",prt, "in", NULL ); + //cmDspSysInstallCb(h, modp,"v0", prv, "in", NULL ); + //cmDspSysInstallCb(h, modp,"v1", prv, "in", NULL ); + //cmDspSysInstallCb(h, modp,"v2", prv, "in", NULL ); + cmDspSysInstallCb(h, prtb, "sym", sfp, "cmd", NULL ); cmDspSysInstallCb(h, qtb, "sym", sfp, "cmd", NULL );