diff --git a/.gitignore b/.gitignore index d07bba3..badd313 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,20 @@ Makefile.in .DS_Store +aclocal.m4 +config.h.in +config.h.in~ +configure +Makefile.in + +autom4te.cache +build-aux + +m4/libtool.m4 +m4/lt~obsolete.m4 +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +m4/.DS_Store diff --git a/Makefile.am b/Makefile.am index 099e3a8..c89c509 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,10 +111,10 @@ endif lib_LTLIBRARIES= include_HEADERS= - +AM_LDFLAGS= AM_CPPFLAGS = -D _GNU_SOURCE -I.. -I$(srcdir)/src -I$(srcdir)/src/dsp -I$(srcdir)/src/vop -I$(srcdir)/src/app -AM_CFLAGS = -Wno-multichar +AM_CFLAGS = -Wall -Wno-multichar AM_CXXFLAGS = # debug/release switches @@ -128,6 +128,7 @@ endif # Linux specific compiler flags if OS_LINUX + AM_LDFLAGS += -lasound # why add this link flag? here's why: https://stackoverflow.com/questions/35480928/alsa-unexpected-results-when-called-from-shared-library if OS_64 AM_CFLAGS += -m64 endif @@ -143,13 +144,15 @@ src_libcm_la_SOURCES = $(cmSRC) $(cmHDR) include_HEADERS += $(cmHDR) lib_LTLIBRARIES += src/libcm.la - -# distclean-local sets the source tree back to it's minimal, pre-configure, state. +# See: https://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/Clean.html#Clean +# 'distclean-local' is used by automake 'distclean' to perform customized local actions +# ${exec_prefix} is the install prefix given to 'configure' by the user. +# ${srcdir} is the directory of this Makefile and is set by autoconf. distclean-local: rm -rf ${exec_prefix}/src - rm -rf ${srcdir}/autom4te.cache - rm -rf ${srcdir}/build-aux - rm -f ${srcdir}/m4/libtool.m4 ${srcdir}/m4/lt~obsolete.m4 ${srcdir}/m4/ltsugar.m4 - rm -f ${srcdir}/m4/ltversion.m4 ${srcdir}/m4/ltoptions.m4 - rm -f ${srcdir}/aclocal.m4 ${srcdir}/config.h.in ${srcdir}/config.h.in~ - rm -f ${srcdir}/Makefile.in ${srcdir}/configure + rm -rf ${exec_prefix}/lib + rm -rf ${exec_prefix}/include + +maintainer-clean-local: + ${srcdir}/config.h.in~ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a987ef --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ + +libcm is a C application development framework with an emphasis on audio signal processing. + diff --git a/build/clean.sh b/build/clean.sh index 00fc879..f76078b 100755 --- a/build/clean.sh +++ b/build/clean.sh @@ -14,9 +14,9 @@ function clean_dir { rm -f $1/bin/kc.app/Contents/MacOS/kc - rm -rf $1/include - rm -rf $1/lib - rm -rf $1/bin + #rm -rf $1/include + #rm -rf $1/lib + #rm -rf $1/bin rm -rf $1/.deps } @@ -30,11 +30,12 @@ clean_dir osx/release rm -rf osx/debug/a.out.dSYM - -#rm -rf ../octave/results - -# remove all of emacs backup files (files ending width '~') -# find ../ -name "*~" -exec rm {} \; +# delete everything created by 'autoreconf'. +rm -rf ../build-aux +rm -rf ../autom4te.cache +rm -f ../config.h.in ../config.h.in~ ../configure ../libtool.m4 +rm -f ../Makefile.in ../aclocal.m4 +rm -f ../m4/libtool.m4 ../m4/ltoptions.m4 ../m4/ltsugar.m4 ../m4/ltversion.m4 ../m4/lt~obsolete.m4 diff --git a/src/app/cmMidiScoreFollow.c b/src/app/cmMidiScoreFollow.c index a837159..1b32b67 100644 --- a/src/app/cmMidiScoreFollow.c +++ b/src/app/cmMidiScoreFollow.c @@ -149,6 +149,7 @@ unsigned _cmMsf_WriteMatchFileLine( cmFileH_t fH, cmScH_t scH, const cmScMatcher return scUid; } +// This is the score follower callback function void _cmMsf_ScoreFollowCb( struct cmScMatcher_str* p, void* arg, cmScMatcherResult_t* rp ) { _cmMsf_ScoreFollow_t* r = (_cmMsf_ScoreFollow_t*)arg; @@ -193,7 +194,7 @@ cmMsfRC_t cmMidiScoreFollowMain( goto errLabel; } - // setup the callback record + // setup the callback record with an array that has twice as many records as there are score events if((sfr.rAllocN = cmScoreEvtCount( scH )*2) == 0) { rc = cmErrMsg(&err,kFailMsfRC,"The score %s appears to be empty.",cmStringNullGuard(scoreCsvFn)); diff --git a/src/app/cmTakeSeqBldr.c b/src/app/cmTakeSeqBldr.c index 4da3939..61477cb 100644 --- a/src/app/cmTakeSeqBldr.c +++ b/src/app/cmTakeSeqBldr.c @@ -960,7 +960,7 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov //cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), false ); // calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks) - cmMidiFileCalcNoteDurations( mfH ); + cmMidiFileCalcNoteDurations( mfH, 0 ); unsigned i = 0; unsigned n = cmMidiFileMsgCount(mfH); diff --git a/src/app/cmTimeLine.c b/src/app/cmTimeLine.c index 708f7a0..2897353 100644 --- a/src/app/cmTimeLine.c +++ b/src/app/cmTimeLine.c @@ -733,7 +733,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh //cmMidiFileTickToSamples(mfH,p->srate,false); // assign note durations to all note-on msg's - cmMidiFileCalcNoteDurations(mfH); + cmMidiFileCalcNoteDurations(mfH,0); unsigned recdByteCnt = sizeof(cmTlMidiFile_t) + strlen(fn) + 1; diff --git a/src/app/cmXScore.c b/src/app/cmXScore.c index 3e3c75c..c98abb6 100644 --- a/src/app/cmXScore.c +++ b/src/app/cmXScore.c @@ -110,12 +110,14 @@ typedef struct cmXsNote_str unsigned locIdx; // location index (chords share the same location index) double rvalue; // 1/rvalue = rythmic value (1/0.5 double whole 1/1 whole 1/2 half 1/4=quarter note, 1/8=eighth note, ...) const cmChar_t* tvalue; // text value + const cmChar_t* editStr; // merged manual edit string unsigned evenGroupId; // eveness group id unsigned dynGroupId; // dynamics group id unsigned tempoGroupId; // tempo group id unsigned graceGroupId; // grace note group id + struct cmXsVoice_str* voice; // voice this note belongs to struct cmXsMeas_str* meas; // measure this note belongs to @@ -230,6 +232,33 @@ cmXsVoice_t* _cmXScoreIdToVoice( cmXsMeas_t* meas, unsigned voiceId ) return NULL; } +cmXsMeas_t* _cmXsFindMeas( cmXsPart_t* part, unsigned measNumb ) +{ + cmXsMeas_t* m = part->measL; + for(; m!=NULL; m=m->link) + if( m->number == measNumb ) + return m; + + return NULL; +} + +cmXsNote_t* _cmXsFindNote( cmXsMeas_t* m, unsigned idx, unsigned midi, double rval, unsigned durtn, unsigned* idxRef ) +{ + unsigned i; + cmXsNote_t* np = m->noteL; + for(i=0; np!=NULL; np=np->slink,++i) + { + //printf("idx:%i %i midi:%i %i rval:%f %f durtn:%i %i\n", i,idx, np->pitch,midi, np->rvalue,rval, np->tied_dur,durtn); + if( i>=idx && np->pitch==midi && np->rvalue==rval && np->tied_dur==durtn ) + { + *idxRef = i; + return np; + } + } + + return NULL; +} + cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note ) { cmXsVoice_t* v; @@ -612,6 +641,7 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1); unsigned voiceId; + note->pitch = kInvalidMidiPitch; note->meas = meas; note->xmlNode = nnp; @@ -681,12 +711,14 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* return _cmXScorePushNote(p, meas, voiceId, note ); } -cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags ) +cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, unsigned staff, double rvalue, const cmChar_t* tvalue, unsigned flags ) { cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1); unsigned voiceId = 0; // non-note's are always assigned to voiceId=0; + note->pitch = kInvalidMidiPitch; note->tick = tick; + note->staff = staff; note->flags = flags; note->rvalue = rvalue; note->tvalue = tvalue; @@ -797,6 +829,11 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo flags = kSectionXsFl; } + else + { + // we only care about 'words' in 'enclosures' + pushFl = false; + } } else @@ -822,7 +859,7 @@ cmXsRC_t _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo } if( pushFl ) - rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,rvalue,tvalue,flags); + rc = _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,staff,rvalue,tvalue,flags); return rc; } @@ -868,7 +905,7 @@ cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t* } // store the bar line - if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,NULL,kBarXsFl)) != kOkXsRC ) + if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,0,NULL,kBarXsFl)) != kOkXsRC ) return rc; np = mnp->children; @@ -1367,7 +1404,10 @@ void _cmXScoreProcessOverlappingNotes( cmXScore_t* p ) fnp->tied_dur -= d; // move the second note just past it - np->tick = fnp->tick + fnp->tied_dur + 1; + np->tick = fnp->tick + fnp->tied_dur; + + cmErrWarnMsg(&p->err,kOverlapWarnXsRC,"A shorten/shift operation was done to reconcile two overlapped %s (ticks:%i %i) notes in measure %i.",cmMidiToSciPitch(np->pitch,NULL,0),fnp->tick,np->tick,np->meas->number); + } } } @@ -1562,7 +1602,7 @@ void _cmXScoreFixBarLines( cmXScore_t* p ) } // Assign pedal down durations to pedal down events. -cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p ) +cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p, bool reportFl ) { cmXsRC_t rc = kOkXsRC; cmXsPart_t* pp = p->partL; @@ -1584,48 +1624,63 @@ cmXsRC_t _cmXScoreProcessPedals( cmXScore_t* p ) case 0: break; - case kDampDnXsFl: + case kDampDnXsFl: if( dnp != NULL ) - cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i.",mp->number); + cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper down not preceded by damper up in measure:%i tick:%i.",mp->number,np->tick); else dnp = np; + + if( reportFl ) + cmRptPrintf(p->err.rpt,"Damp Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick); break; case kDampUpXsFl: if( dnp == NULL ) - cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up not preceded by damper down in measure:%i.",mp->number); + cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up not preceded by damper down in measure:%i tick:%i.",mp->number,np->tick); else { dnp->duration = np->tick - dnp->tick; dnp = NULL; } + + if( reportFl ) + cmRptPrintf(p->err.rpt,"Damp Up : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick); + break; case kDampUpDnXsFl: if( dnp == NULL ) - cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up/down not preceded by damper down in measure:%i.",mp->number); + cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Damper up/down not preceded by damper down in measure:%i tick:%i.",mp->number,np->tick); else { dnp->duration = np->tick - dnp->tick; dnp = np; } + + if( reportFl ) + cmRptPrintf(p->err.rpt,"Damp UpDn : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick); break; case kSostDnXsFl: if( snp != NULL ) - cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i.",mp->number); + cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto down not preceded by sostenuto up in measure:%i tick:%i.",mp->number, np->tick); else - snp = np; + snp = np; + + if( reportFl ) + cmRptPrintf(p->err.rpt,"Sost Down : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick); break; case kSostUpXsFl: if( snp == NULL ) - cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto up not preceded by sostenuto down in measure:%i.",mp->number); + cmErrWarnMsg(&p->err,kPedalStateErrorXsRc,"Sostenuto up not preceded by sostenuto down in measure:%i tick:%i.",mp->number,np->tick); else { snp->duration = np->tick - snp->tick; snp = NULL; } + if( reportFl ) + cmRptPrintf(p->err.rpt,"Sost Up : staff:%i meas:%i tick:%i\n", np->staff, mp->number, np->tick); break; default: @@ -2009,7 +2064,7 @@ cmXsRC_t _cmXScoreProcessDynamicForks( cmXScore_t* p ) //------------------------------------------------------------------------------------------- -typedef struct +typedef struct _cmXsReorder_str { unsigned idx; // Fields from the reordering input file which are unsigned voice; // used to match the reorder record to @@ -2027,8 +2082,26 @@ typedef struct unsigned graceFlags; // 0=ignore See kXXXGraceXsFl unsigned graceGroupId; // 0=ignore >0=grace note group id unsigned pitch; // 0=ignore >0 new pitch + + const char* editStr; + + struct _cmXsReorder_str* link; } cmXsReorder_t; +typedef struct _cmXsReorderMeas_str +{ + unsigned measNumb; + cmXsReorder_t* beg; + cmXsReorder_t* end; + struct _cmXsReorderMeas_str* link; +} cmXsReorderMeas_t; + +typedef struct +{ + cmXsReorderMeas_t* beg; + cmXsReorderMeas_t* end; +} cmXsReorderFile_t; + typedef struct _cmXScoreDynMark_str { const cmChar_t* mark; // @@ -2069,6 +2142,90 @@ _cmXScoreDynMark_t _cmXScoreDynMarkArray[] = }; +cmXsReorderMeas_t* _cmXsReorderFileAllocMeas( cmXScore_t* p, cmXsReorderFile_t* rfp, unsigned measNumb ) +{ + cmXsReorderMeas_t* m = cmLhAllocZ(p->lhH,cmXsReorderMeas_t,1); + m->measNumb = measNumb; + + if( rfp->end == NULL ) + { + rfp->beg = m; + rfp->end = m; + } + else + { + rfp->end->link = m; + rfp->end = m; + } + return m; +} + +cmXsReorderMeas_t* _cmXsReorderFileFindMeas( cmXsReorderFile_t* rfp, unsigned measNumb ) +{ + cmXsReorderMeas_t* m = rfp->beg; + for(; m!=NULL; m=m->link) + if( m->measNumb == measNumb ) + return m; + + return NULL; +} + + +cmXsReorder_t* _cmXsReorderMeasAllocEvent( cmXScore_t* p, cmXsReorderMeas_t* m ) +{ + cmXsReorder_t* r = cmLhAllocZ(p->lhH, cmXsReorder_t,1); + + r->midi = kInvalidMidiPitch; + + if( m->end == NULL ) + { + m->beg = r; + m->end = r; + } + else + { + m->end->link = r; + m->end = r; + } + + return r; +} + +// find key in meas (m) by searching after event idx0. +cmXsReorder_t* _cmXsReorderFindEvent( cmXsReorderMeas_t* m, unsigned idx0, cmXsReorder_t* key ) +{ + cmXsReorder_t* r; + for(r=m->beg; r!=NULL; r=r->link) + if( r->idx >= idx0 && r->midi==key->midi && r->rval==key->rval && r->durtn==key->durtn ) + return r; + + return NULL; +} + +cmXsReorder_t* _cmXsReorderMeasPop( cmXsReorderMeas_t* m ) +{ + cmXsReorder_t* r0 = NULL; + cmXsReorder_t* r = NULL; + for(r=m->beg; r!=NULL; r=r->link) + { + if( r == m->end ) + break; + r0 = r; + } + + if( r0 == NULL ) + { + m->beg = NULL; + m->end = NULL; + } + else + { + m->end = r0; + m->end->link = NULL; + } + + return r; +} cmXsNote_t* _cmXsReorderFindNote( cmXScore_t* p, unsigned measNumb, const cmXsReorder_t* r, unsigned iii ) { @@ -2086,7 +2243,7 @@ cmXsNote_t* _cmXsReorderFindNote( cmXScore_t* p, unsigned measNumb, const cmXsR { - if( 0 /*mp->number==19*/ ) + if( 0 /*mp->number==27*/ ) printf("voice: %i %i loc:%i %i tick:%i %i pitch:%i %i rval:%f %f idx:%i %i \n", np->voice->id, r->voice, np->locIdx , r->locIdx , @@ -2119,7 +2276,8 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned { // Create a new score event record cmXsNote_t* nn = cmLhAllocZ(p->lhH,cmXsNote_t,1); - + + nn->pitch = kInvalidMidiPitch; nn->uid = p->nextUid++; nn->voice = r->note->voice; nn->meas = r->note->meas; @@ -2146,7 +2304,108 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned } -cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN ) +cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, cmXsReorderMeas_t* m ) +{ + unsigned i; + cmXsReorder_t* r; + + if( m->beg == NULL ) + return kOkXsRC; + + // set the 'note' field on each cmXsReorder_t record + for(r=m->beg,i=0; r!=NULL; r=r->link,++i) + if((r->note = _cmXsReorderFindNote(p,m->measNumb,r,i)) == NULL ) + return kSyntaxErrorXsRC; + + // remove deleted notes + for(r=m->beg; r!=NULL; r=r->link) + if( cmIsFlag(r->newFlags,kDeleteXsFl) ) + if( _cmXScoreRemoveNote( r->note ) != kOkXsRC ) + return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Event marked to skip was not found in measure: %i",m->measNumb); + + cmXsMeas_t* mp = m->beg->note->meas; + cmXsNote_t* n0p = NULL; + + assert( mp->number == m->measNumb ); + + // Reassign the slink of the cmXsNote_t records in this measure + // according to their order in rV[]. + for(r=m->beg; r!=NULL; r=r->link) + { + + if( cmIsFlag(r->newFlags,kDeleteXsFl) ) + continue; + + if( n0p == NULL ) + mp->noteL = r->note; + else + n0p->slink = r->note; + + // if a new tick was specified + if( r->newTick != 0 ) + r->note->tick = r->newTick; + + // if a dynamic or velocity mark was included + if( r->dynIdx != cmInvalidIdx ) + { + r->note->dynamics = _cmXScoreDynMarkArray[ r->dynIdx ].dyn; + r->note->vel = _cmXScoreDynMarkArray[ r->dynIdx ].vel; + } + + // Set the dynamic fork begin/end flags for later _cmXScoreProcessDynamicForks() + if( cmIsFlag(r->newFlags,kDynBegForkXsFl) ) + r->note->flags = cmSetFlag(r->note->flags,kDynBegForkXsFl); + + if( cmIsFlag(r->newFlags,kDynEndForkXsFl) ) + r->note->flags = cmSetFlag(r->note->flags,kDynEndForkXsFl); + + + // if the tie end flag was set + if( cmIsFlag(r->newFlags,kTieEndXsFl) ) + { + r->note->flags |= kTieEndXsFl; + r->note->flags = cmClrFlag( r->note->flags, kOnsetXsFl ); + r->newFlags = cmClrFlag( r->newFlags, kTieEndXsFl); + } + + // if a new note value was specified + if( r->pitch != 0 ) + r->note->pitch = r->pitch; + + r->note->flags |= r->graceFlags; + r->note->graceGroupId = r->graceGroupId; + + + + n0p = r->note; + n0p->slink = NULL; + } + + + // Insert new note records for pedal up/dn events. + for(r=m->beg; r!=NULL; r=r->link) + { + if( r->newFlags != 0 ) + { + if( cmIsFlag(r->newFlags,kDampDnXsFl ) ) + _cmXScoreInsertPedalEvent(p,r,kDampDnXsFl); + + if( cmIsFlag(r->newFlags,kSostDnXsFl ) ) + _cmXScoreInsertPedalEvent(p,r,kSostDnXsFl); + + if( cmIsFlag(r->newFlags,kDampUpXsFl ) ) + _cmXScoreInsertPedalEvent(p,r,kDampUpXsFl); + + if( cmIsFlag(r->newFlags,kSostUpXsFl ) ) + _cmXScoreInsertPedalEvent(p,r,kSostUpXsFl); + } + } + + return kOkXsRC; + +} + +cmXsRC_t _cmXScoreReorderMeas0( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN ) { unsigned i; @@ -2247,19 +2506,22 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* } -cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb ) -{ - cmXsRC_t rc = kOkXsRC; - const cmChar_t* s = NULL; - bool begForkFl = false; - bool endForkFl = false; - +cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, char** s0, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb ) +{ + cmXsRC_t rc = kOkXsRC; + cmChar_t* s = NULL; + bool begForkFl = false; + bool endForkFl = false; + *dynIdxRef = cmInvalidIdx; // locate the '!' which indicates the start of a dynamic marking if( (s = strchr(b,'!')) == NULL ) return rc; + + if( *s0==NULL || s<*s0 ) + *s0 = s; ++s; // increment past the '!' @@ -2354,19 +2616,22 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin } -cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* newFlagsRef ) +cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* newFlagsRef ) { - cmXsRC_t rc = kOkXsRC; - const cmChar_t* s; - bool doneFl = false; - unsigned i = 0; - + cmXsRC_t rc = kOkXsRC; + cmChar_t* s; + bool doneFl = false; + unsigned i = 0; + *newFlagsRef = 0; // tilde indicates a pedal event if((s = strchr(b,'~')) == NULL ) return rc; + if( *s0==NULL || s<*s0) + *s0 = s; + do { ++s; @@ -2415,14 +2680,17 @@ cmXsRC_t _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned return rc; } -cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* tickRef ) +cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* tickRef ) { cmXsRC_t rc = kOkXsRC; - const cmChar_t* s; + cmChar_t* s; if((s = strchr(b,'@')) == NULL ) return rc; + if( *s0 == NULL || s<*s0 ) + *s0 = s; + ++s; if(!isdigit(*s)) @@ -2434,14 +2702,17 @@ cmXsRC_t _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned l return rc; } -cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, cmXsReorder_t* r, unsigned* graceGroupIdRef ) +cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, cmXsReorder_t* r, unsigned* graceGroupIdRef ) { - cmXsRC_t rc = kOkXsRC; - const cmChar_t* s; + cmXsRC_t rc = kOkXsRC; + cmChar_t* s; if((s = strchr(b,'%')) == NULL ) return rc; + if( *s0==NULL || s<*s0 ) + *s0 = s; + ++s; r->graceGroupId = *graceGroupIdRef; @@ -2483,12 +2754,12 @@ cmXsRC_t _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned } -cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* pitchRef ) +cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* pitchRef ) { - cmXsRC_t rc = kOkXsRC; + cmXsRC_t rc = kOkXsRC; cmChar_t* s; - cmChar_t buf[4]; - unsigned i,j; + cmChar_t buf[4]; + unsigned i,j; memset(buf,0,sizeof(buf)); *pitchRef = 0; @@ -2496,6 +2767,9 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned if((s = strchr(b,'$')) == NULL ) return rc; + if( *s0==NULL || s<*s0) + *s0 = s; + ++s; j=2; @@ -2527,7 +2801,232 @@ cmXsRC_t _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned return rc; } +cmXsRC_t _cmXsReadEditFile( cmXScore_t* p, const cmChar_t* fn, unsigned* graceGroupIdPtr, cmXsReorderFile_t* rfp ) +{ + typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t; + + cmXsRC_t rc = kOkXsRC; + cmFileH_t fH = cmFileNullHandle; + cmChar_t* b = NULL; + unsigned bN = 0; + unsigned ln = 0; + stateId_t stateId = kFindMeasStId; + cmXsReorderMeas_t* curMeas = NULL; + + *graceGroupIdPtr = 1; + + if( cmFileOpen(&fH,fn,kReadFileFl,p->err.rpt) != kOkFileRC ) + { + rc = cmErrMsg(&p->err,kFileFailXsRC,"The reordering file '%s' could not be opened.",cmStringNullGuard(fn)); + return rc; + } + + for(; cmFileGetLineAuto(fH,&b,&bN) == kOkFileRC; ++ln) + { + switch( stateId ) + { + case kFindEventStId: // scanning past labels to an event line + { + unsigned voice,loc; + if( sscanf(b,"%i %i",&voice,&loc) != 2 ) + continue; + + stateId = kReadEventStId; + } + // fall through + + case kReadEventStId: + { + cmXsReorder_t* r = _cmXsReorderMeasAllocEvent(p, curMeas ); + char pitchStr[4]; + char* s0 = NULL; + + // parse an event line + if( sscanf(b,"%i %i %i %i %i %f",&r->idx,&r->voice,&r->locIdx,&r->tick,&r->durtn,&r->rval) == 6 ) + { + assert( strlen(b)>=52); + int PC = 39; // text file column where first pitch char occurs + + if( b[PC] == ' ') + r->midi = kInvalidMidiPitch; + else + { + pitchStr[0] = b[PC+0]; + pitchStr[1] = b[PC+1]; + pitchStr[2] = b[PC+2]; + pitchStr[3] = 0; + + if( !isdigit(pitchStr[2]) ) + r->midi = kInvalidMidiPitch; + else + { + if( pitchStr[1] == ' ') + { + pitchStr[1] = pitchStr[2]; + pitchStr[2] = 0; + } + + r->midi = cmSciPitchToMidi(pitchStr); + + //printf("%i %i %s %s\n",curMeas->measNumb,r->midi,pitchStr,fn); + } + } + + // parse the flag edits following a '~' + if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r->newFlags)) != kOkXsRC ) + goto errLabel; + + // parse the dynamic marking following a '!' + if((rc = _cmXScoreReorderParseDyn(p,b,ln+1, &s0, &r->dynIdx, &r->newFlags, curMeas->measNumb)) != kOkXsRC ) + goto errLabel; + + // parse the @newtick marker + if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r->newTick)) != kOkXsRC ) + goto errLabel; + + // parse the %grace note marker + if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, r, graceGroupIdPtr)) != kOkXsRC ) + goto errLabel; + + // parse the $pitch marker + if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r->pitch )) != kOkXsRC ) + goto errLabel; + + if( s0 != NULL ) + r->editStr = cmTextTrimEnd(cmLhAllocStrN( p->lhH, s0, strlen(s0)+1 )); + + continue; + } + + // remove the last reorder record because it was not filled + _cmXsReorderMeasPop(curMeas); + + stateId = kFindMeasStId; + // fall through + } + + case kFindMeasStId: // scanning for a bar-line + { + char colon; + unsigned measNumb = 0; + + if( sscanf(b,"%i %c",&measNumb,&colon) == 2 && colon == ':' ) + { + curMeas = _cmXsReorderFileAllocMeas( p, rfp, measNumb ); + stateId = kFindEventStId; + } + } + break; + } + + } + errLabel: + cmMemFree(b); + cmFileClose(&fH); + return rc; +} + cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) +{ + cmXsRC_t rc = kOkXsRC; + unsigned graceGroupId = 1; + cmXsReorderFile_t rf; + cmXsReorderMeas_t* m; + memset(&rf,0,sizeof(rf)); + + if((rc = _cmXsReadEditFile( p, fn, &graceGroupId, &rf )) != kOkXsRC ) + return rc; + + // reorder each measure + for(m=rf.beg; m!=NULL; m=m->link) + if((rc = _cmXScoreReorderMeas(p, m)) != kOkXsRC ) + goto errLabel; + + // the ticks may have changed so the 'secs' and 'dsecs' must be updated + _cmXScoreSetAbsoluteTime( p ); + + // the bar lines should be the first event in the measure + _cmXScoreFixBarLines(p); + + // resort to force the links to be correct + _cmXScoreSort(p); + + // process the grace notes. + _cmXScoreProcessGraceNotes( p, graceGroupId ); + + // inserting grace notes may have left the score unsorted + _cmXScoreSort(p); + + // process the dynamic forks + _cmXScoreProcessDynamicForks(p); + + //_cmXScoreReport(p, NULL, true ); + + errLabel: + return rc; +} + + + +cmXsRC_t _cmXsMergeEditFiles( cmXScore_t* p, unsigned measNumb0, const cmChar_t* keyEditFn, unsigned keyMeasNumb, const cmChar_t* outFn ) +{ + cmXsRC_t rc = kOkXsRC; + unsigned graceGroup1Id = 1; + unsigned measNumb1 = keyMeasNumb; + cmXsReorderFile_t rf1; + memset(&rf1,0,sizeof(rf1)); + + if((rc = _cmXsReadEditFile( p, keyEditFn, &graceGroup1Id, &rf1 )) != kOkXsRC ) + return rc; + + while(1) + { + cmXsMeas_t* m0 = _cmXsFindMeas( p->partL, measNumb0 ); + cmXsReorderMeas_t* m1 = _cmXsReorderFileFindMeas( &rf1, measNumb1 ); + cmXsReorder_t* key = NULL; + unsigned idx0 = 0; + + if( m1==NULL ) + { + rc = cmErrMsg(&p->err,kEventNotFoundXsRC,"The measure %i was not found in the key edit file '%s'.",keyMeasNumb,cmStringNullGuard(keyEditFn)); + break; + } + + key = m1->beg; + + for(; key!=NULL; key=key->link) + { + unsigned idx1 = cmInvalidIdx; + cmXsNote_t* np = _cmXsFindNote( m0, idx0, key->midi, key->rval, key->durtn, &idx1); + + if( np==NULL ) + { + if( key->editStr != NULL ) + { + const char* sciPitch = key->midi!=kInvalidMidiPitch ? cmMidiToSciPitch(key->midi,NULL,0) : ""; + cmErrWarnMsg(&p->err,kEventNotFoundXsRC,"Sync error: meas: ref:%i key:%i index:%i %s (midi:%i) edit:%s did not match to the reference edit file.", measNumb0,m1->measNumb,key->idx, sciPitch, key->midi, key->editStr); + } + } + else + { + np->editStr = key->editStr; + + if( key->editStr != NULL ) + idx0 = idx1; + } + } + + ++measNumb0; + ++measNumb1; + + } + + return rc; +} + + + +cmXsRC_t _cmXsApplyEditFile0( cmXScore_t* p, const cmChar_t* fn ) { typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t; @@ -2567,6 +3066,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) { cmXsReorder_t r; char pitchStr[4]; + char* s0 = NULL; memset(&r,0,sizeof(r)); @@ -2577,7 +3077,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) int PC = 39; // text file column where first pitch char occurs if( b[PC] == ' ') - r.midi = 0; + r.midi = kInvalidMidiPitch; else { pitchStr[0] = b[PC+0]; @@ -2586,7 +3086,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) pitchStr[3] = 0; if( !isdigit(pitchStr[2]) ) - r.midi = 0; + r.midi = kInvalidMidiPitch; else { if( pitchStr[1] == ' ') @@ -2602,40 +3102,24 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) // parse the flag edits following a '~' - if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &r.newFlags)) != kOkXsRC ) + if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r.newFlags)) != kOkXsRC ) goto errLabel; // parse the dynamic marking following a '!' - if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC ) + if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&s0, &r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC ) goto errLabel; // parse the @newtick marker - if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &r.newTick)) != kOkXsRC ) + if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r.newTick)) != kOkXsRC ) goto errLabel; // parse the %grace note marker - if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &r, &graceGroupId)) != kOkXsRC ) + if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, &r, &graceGroupId)) != kOkXsRC ) goto errLabel; // parse the $pitch marker - if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &r.pitch )) != kOkXsRC ) + if((rc = _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r.pitch )) != kOkXsRC ) goto errLabel; - - // process grace notes - these need to be processed separate from - // the _cmXScoreReorderMeas() because grace notes may cross measure boundaries. - /* - if( r.graceType != 0 ) - { - r.graceGroupId = graceGroupId; - - // if this is an end of a grace note group - if( r.graceType != 'g' && r.graceType != 'b' ) - { - graceGroupId += 1; - } - - } - */ // store the record assert( ri < rN ); @@ -2647,7 +3131,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) // the end of the measure was encountered - // reorder the measure based on the cmXsReorder_t in rV[ri] - if((rc = _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC ) + if((rc = _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC ) goto errLabel; ri = 0; @@ -2673,7 +3157,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) // If reorder records remain to be processed if( ri > 0 ) - if((rc = _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC ) + if((rc = _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC ) goto errLabel; @@ -2705,8 +3189,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn ) } - -cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn ) +cmXsRC_t cmXScoreAlloc( cmCtx_t* ctx, cmXsH_t* hp ) { cmXsRC_t rc = kOkXsRC; @@ -2721,6 +3204,21 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false ) return cmErrMsg(&p->err,kLHeapFailXsRC,"Lheap create failed."); + hp->h = p; + + return rc; +} + +cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl ) +{ + cmXsRC_t rc; + cmXScore_t* p = NULL; + + if((rc = cmXScoreAlloc(ctx,hp)) != kOkXsRC ) + goto errLabel; + + p = _cmXScoreHandleToPtr(*hp); + // open the music xml file if( cmXmlAlloc(ctx, &p->xmlH, xmlFn) != kOkXmlRC ) { @@ -2771,7 +3269,7 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c } // assign durations to pedal down events - _cmXScoreProcessPedals(p); + _cmXScoreProcessPedals(p,damperRptFl); // remove some notes which share a pitch and are overlapped or embedded within another note. _cmXScoreProcessOverlappingNotes(p); @@ -2779,9 +3277,8 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c errLabel: if( rc != kOkXsRC ) - _cmXScoreFinalize(p); - else - hp->h = p; + cmXScoreFinalize(hp); + return rc; } @@ -2836,7 +3333,7 @@ cmXsRC_t _cmXScoreWriteCsvHdr( cmXScore_t* p ) { "id","trk","evt","opcode","dticks","micros","status", "meta","ch","d0","d1","arg0","arg1","bar","skip", - "even","grace","tempo","t frac","dyn","section","play_recd","remark",NULL + "even","grace","tempo","t_frac","dyn","section","play_recd","remark",NULL }; cmCsvCell_t* lcp = NULL; @@ -3302,6 +3799,9 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index ) if( note->dynamics != 0) cmRptPrintf(rpt," dyn=%i %i",note->dynamics,note->vel); + + if( note->editStr != NULL ) + cmRptPrintf(rpt, " %s", note->editStr ); /* if( cmIsFlag(note->flags,kBegGraceXsFl) ) @@ -3352,6 +3852,7 @@ void _cmXScoreReport( cmXScore_t* p, cmRpt_t* rpt, bool sortFl ) t1 = note->slink==NULL ? note->tick : note->slink->tick; + // check that this note is in tick order if( !(t0 <= note->tick && note->tick <= t1) ) { cmRptPrintf(rpt," +"); @@ -3408,32 +3909,41 @@ void _cmXScoreGenEditFileWrite( void* arg, const cmChar_t* text ) } } -cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn ) +cmXsRC_t _cmXScoreEditFileRpt( cmCtx_t* ctx, cmXScore_t* p, const cmChar_t* outFn, bool damperRptFl ) { - cmXsH_t xsH = cmXsNullHandle; - cmFileH_t fH = cmFileNullHandle; cmXsRC_t rc = kOkXsRC; cmErr_t err; cmRpt_t rpt; + cmFileH_t fH = cmFileNullHandle; cmErrSetup(&err,&ctx->rpt,"cmXScoreGenEditFile"); cmRptSetup(&rpt,_cmXScoreGenEditFileWrite,_cmXScoreGenEditFileWrite,&fH); - - if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL)) != kOkXsRC ) - return rc; - + if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC ) { cmErrMsg(&err,kFileFailXsRC,"Unable to open the output file '%s'.",cmStringNullGuard(outFn)); goto errLabel; } - cmXScoreReport(xsH,&rpt,true); + _cmXScoreReport(p,&rpt,true); errLabel: if( cmFileClose(&fH) != kOkFileRC ) rc = cmErrMsg(&err,kFileFailXsRC,"File close failed on '%s'.",cmStringNullGuard(outFn)); + + return rc; +} + +cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl ) +{ + cmXsH_t xsH = cmXsNullHandle; + cmXsRC_t rc = kOkXsRC; + + if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC ) + return rc; + + rc = _cmXScoreEditFileRpt( ctx, _cmXScoreHandleToPtr(xsH), outFn, damperRptFl ); cmXScoreFinalize(&xsH); @@ -4077,21 +4587,22 @@ cmXsRC_t cmXScoreTest( int beginMeasNumb, int beginBPM, bool standAloneFl, - bool panZoomFl ) + bool panZoomFl, + bool damperRptFl) { cmXsRC_t rc; cmXsH_t h = cmXsNullHandle; if( editFn!=NULL && !cmFsIsFile(editFn) ) { - cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.",editFn); - cmXScoreGenEditFile(ctx,xmlFn,editFn); + cmRptPrintf(&ctx->rpt,"The edit file %s does not exist. A new edit file will be created.\n",editFn); + cmXScoreGenEditFile(ctx,xmlFn,editFn,damperRptFl); editFn = NULL; } // Parse the XML file and apply the changes in editFn. - if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn)) != kOkXsRC ) + if((rc = cmXScoreInitialize( ctx, &h, xmlFn,editFn, damperRptFl )) != kOkXsRC ) return cmErrMsg(&ctx->err,rc,"XScore alloc failed."); if( csvOutFn != NULL ) @@ -4101,14 +4612,14 @@ cmXsRC_t cmXScoreTest( _cmXsIsCsvValid(ctx,h,csvOutFn); } + + // measure the score complexity + double wndSecs = 1.0; + + _cmXsMeasComplexity(h,wndSecs); if( midiOutFn != NULL ) - { - // measure the score complexity - double wndSecs = 1.0; - - _cmXsMeasComplexity(h,wndSecs); - + { cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn); _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr ); @@ -4128,3 +4639,24 @@ cmXsRC_t cmXScoreTest( return cmXScoreFinalize(&h); } + + +cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn, unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn ) +{ + cmXsH_t h = cmXsNullHandle; + cmXsRC_t rc; + bool damperRptFl = false; + + if((rc = cmXScoreInitialize(ctx, &h, xmlFn, refEditFn, damperRptFl )) == kOkXsRC ) + { + cmXScore_t* p = _cmXScoreHandleToPtr(h); + + if((rc = _cmXsMergeEditFiles(p, refBegMeasNumb, editFn, keyMeasNumb, outFn )) == kOkXsRC ) + rc = _cmXScoreEditFileRpt( ctx, p, outFn, damperRptFl ); + + + cmXScoreFinalize(&h); + } + + return rc; +} diff --git a/src/app/cmXScore.h b/src/app/cmXScore.h index 19b6205..df7a352 100644 --- a/src/app/cmXScore.h +++ b/src/app/cmXScore.h @@ -20,7 +20,8 @@ extern "C" { kFileFailXsRC, kSvgFailXsRC, kOverlapWarnXsRC, - kZeroLengthEventXsRC + kZeroLengthEventXsRC, + kEventNotFoundXsRC }; typedef cmRC_t cmXsRC_t; @@ -47,7 +48,7 @@ extern "C" { // Initialize an cmXScore object from a Sibelius generated MusicXML file. // 'editFn' is used to add additional information to the score. // See cmXScoreGenEditFile() - cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn ); + cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl ); cmXsRC_t cmXScoreFinalize( cmXsH_t* hp ); @@ -60,7 +61,7 @@ extern "C" { // Generate a template 'edit file'. This file can be edited by hand to included additional // information in the score. See the 'editFn' argument to cmXScoreInitialize() for where // this file is used. - cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn ); + cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl ); // Generate the CSV file suitable for use by cmScore. // @@ -72,7 +73,9 @@ extern "C" { // Set reportFl to true to print a report of the score following processing. // Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files. // Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb. - cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl ); + cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl ); + + cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn, unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn ); #ifdef __cplusplus } diff --git a/src/cmAudDsp.c b/src/cmAudDsp.c index 4b97570..213a7dd 100644 --- a/src/cmAudDsp.c +++ b/src/cmAudDsp.c @@ -354,10 +354,15 @@ cmAdRC_t _cmAdParseSysJsonTree( cmAd_t* p ) { cmAudioSysArgs_t* asap = &p->asCfgArray[i].cfg.ssArray[j].args; const cmJsonNode_t* argsNodePtr = cmJsonArrayElementC(ssArrayNodePtr,j); + + asap->inDevIdx = cmInvalidIdx; + asap->outDevIdx = cmInvalidIdx; + asap->inDevLabel = NULL; + asap->outDevLabel = NULL; if((jsRC = cmJsonMemberValues( argsNodePtr, &errLabelPtr, - "inDevIdx", kIntTId, &asap->inDevIdx, - "outDevIdx", kIntTId, &asap->outDevIdx, + "inDevLabel", kStringTId, &asap->inDevLabel, + "outDevLabel", kStringTId, &asap->outDevLabel, "syncToInputFl", kTrueTId, &asap->syncInputFl, "msgQueueByteCnt", kIntTId, &asap->msgQueueByteCnt, "devFramesPerCycle", kIntTId, &asap->devFramesPerCycle, @@ -443,6 +448,35 @@ cmAdRC_t _cmAdCreateAggDevices( cmAd_t* p ) return rc; } +cmAdRC_t _cmAdResolveDeviceLabels( cmAd_t* p ) +{ + cmAdRC_t rc = kOkAdRC; + unsigned i,j; + + // for each cmAsAudioSysCfg record in audioSysCfgArray[] + for(i=0; iasCfgCnt; ++i) + { + // for each audio system sub-subsystem + for(j=0; jasCfgArray[i].cfg.ssCnt; ++j) + { + cmAudioSysArgs_t* asap = &p->asCfgArray[i].cfg.ssArray[j].args; + if((asap->inDevIdx = cmApDeviceLabelToIndex( asap->inDevLabel )) == cmInvalidId ) + { + rc = cmErrMsg(&p->err,kInvalidAudioDevIdxAdRC,"The audio input device '%s' could not be found.", cmStringNullGuard(asap->inDevLabel)); + goto errLabel; + } + + if((asap->outDevIdx = cmApDeviceLabelToIndex( asap->outDevLabel )) == cmInvalidId ) + { + rc = cmErrMsg(&p->err,kInvalidAudioDevIdxAdRC,"The audio input device '%s' could not be found.", cmStringNullGuard(asap->inDevLabel)); + goto errLabel; + } + } + } + errLabel: + return rc; +} + cmAdRC_t _cmAdCreateNrtDevices( cmAd_t* p ) { cmAdRC_t rc = kOkAdRC; @@ -721,10 +755,11 @@ cmAdRC_t cmAudDspAlloc( cmCtx_t* ctx, cmAdH_t* hp, cmMsgSendFuncPtr_t cbFunc, vo if((rc = _cmAdParseSysJsonTree(p)) != kOkAdRC ) goto errLabel; + // create the aggregate device if( _cmAdCreateAggDevices(p) != kOkAdRC ) goto errLabel; - + // create the non-real-time devices if( _cmAdCreateNrtDevices(p) != kOkAdRC ) goto errLabel; @@ -740,6 +775,12 @@ cmAdRC_t cmAudDspAlloc( cmCtx_t* ctx, cmAdH_t* hp, cmMsgSendFuncPtr_t cbFunc, vo goto errLabel; } + if( _cmAdResolveDeviceLabels(p) != kOkApRC ) + { + rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio device labels could not be resolved.."); + goto errLabel; + } + // initialize the audio buffer if( cmApBufInitialize( cmApDeviceCount(), p->meterMs ) != kOkApRC ) { diff --git a/src/cmAudDsp.h b/src/cmAudDsp.h index 152c94e..6e0c88b 100644 --- a/src/cmAudDsp.h +++ b/src/cmAudDsp.h @@ -27,7 +27,8 @@ extern "C" { kAggDevCreateFailAdRC, kNrtDevSysFailAdRC, kAfpDevSysFailAdRC, - kNetSysFailAdRC + kNetSysFailAdRC, + kInvalidAudioDevIdxAdRC }; diff --git a/src/cmAudioNrtDev.c b/src/cmAudioNrtDev.c index c22f770..1408df3 100644 --- a/src/cmAudioNrtDev.c +++ b/src/cmAudioNrtDev.c @@ -189,6 +189,10 @@ cmApRC_t cmApNrtAllocate( cmRpt_t* rpt ) cmApRC_t cmApNrtFree() { cmApRC_t rc = kOkApRC; + + if( _cmNrt == NULL ) + return rc; + cmApNrtDev_t* dp = _cmNrt->devs; while( dp != NULL ) { diff --git a/src/cmAudioSys.h b/src/cmAudioSys.h index 9a5b28e..7fc5c8d 100644 --- a/src/cmAudioSys.h +++ b/src/cmAudioSys.h @@ -130,16 +130,18 @@ extern "C" { // Audio device sub-sytem configuration record typedef struct cmAudioSysArgs_str { - cmRpt_t* rpt; // system console object - unsigned inDevIdx; // input audio device - unsigned outDevIdx; // output audio device - bool syncInputFl; // true/false sync the DSP update callbacks with audio input/output - unsigned msgQueueByteCnt; // Size of the internal msg queue used to buffer msgs arriving via cmAudioSysDeliverMsg(). - unsigned devFramesPerCycle; // (512) Audio device samples per channel per device update buffer. - unsigned dspFramesPerCycle; // (64) Audio samples per channel per DSP cycle. - unsigned audioBufCnt; // (3) Audio device buffers. - double srate; // Audio sample rate. - int srateMult; // Sample rate multiplication factor (negative for divide) + cmRpt_t* rpt; // system console object + const cmChar_t* inDevLabel; // input audio device text label + const cmChar_t* outDevLabel; // output audio device text label + unsigned inDevIdx; // input audio device index + unsigned outDevIdx; // output audio device index + bool syncInputFl; // true/false sync the DSP update callbacks with audio input/output + unsigned msgQueueByteCnt; // Size of the internal msg queue used to buffer msgs arriving via cmAudioSysDeliverMsg(). + unsigned devFramesPerCycle; // (512) Audio device samples per channel per device update buffer. + unsigned dspFramesPerCycle; // (64) Audio samples per channel per DSP cycle. + unsigned audioBufCnt; // (3) Audio device buffers. + double srate; // Audio sample rate. + int srateMult; // Sample rate multiplication factor (negative for divide) } cmAudioSysArgs_t; // Audio sub-system configuration record. diff --git a/src/cmDList.c b/src/cmDList.c index 831b106..29b6a63 100644 --- a/src/cmDList.c +++ b/src/cmDList.c @@ -150,7 +150,7 @@ void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x ) // x is the first index if( x0 == NULL ) { - assert( x1 = p->indexes ); + assert( x1 == p->indexes ); p->indexes = x->link; } else diff --git a/src/cmMidi.h b/src/cmMidi.h index 653941e..b9ae113 100644 --- a/src/cmMidi.h +++ b/src/cmMidi.h @@ -88,9 +88,9 @@ extern "C" { #define cmMidiIsStatus( s ) (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ ) #define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) < kSysExMdId) -#define cmMidiIsNoteOn( s ) ( kNoteOnMdId <= (s) && (s) <= (kNoteOnMdId + kMidiChCnt) ) -#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) <= (kNoteOffMdId + kMidiChCnt)) ) -#define cmMidiIsCtl( s ) ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) ) +#define cmMidiIsNoteOn( s ) ( kNoteOnMdId <= (s) && (s) < (kNoteOnMdId + kMidiChCnt) ) +#define cmMidiIsNoteOff( s, d1 ) ( (cmMidiIsNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) < (kNoteOffMdId + kMidiChCnt)) ) +#define cmMidiIsCtl( s ) ( kCtlMdId <= (s) && (s) < (kCtlMdId + kMidiChCnt) ) #define cmMidiIsSustainPedal( s, d0 ) ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId ) #define cmMidiIsSustainPedalDown( s, d0, d1) ( cmMidiIsSustainPedal(s,d0) && (d1)>=64 ) diff --git a/src/cmMidiFile.c b/src/cmMidiFile.c index bf52be2..a47f413 100644 --- a/src/cmMidiFile.c +++ b/src/cmMidiFile.c @@ -423,6 +423,34 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp ) return rc; } +void _cmMidiFileDrop( _cmMidiFile_t* p ) +{ + unsigned i; + unsigned n = 0; + for(i=0; itrkN; ++i) + { + _cmMidiTrack_t* trk = p->trkV + i; + cmMidiTrackMsg_t* m0 = NULL; + cmMidiTrackMsg_t* m = trk->base; + + for(; m!=NULL; m=m->link) + { + if( cmIsFlag(m->flags,kDropTrkMsgFl) ) + { + ++n; + if( m0 == NULL ) + trk->base = m->link; + else + m0->link = m->link; + } + else + { + m0 = m; + } + } + } +} + int _cmMidiFileSortFunc( const void *p0, const void* p1 ) { if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick ) @@ -1369,7 +1397,6 @@ cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiBy mfp->msgVDirtyFl = true; return kOkMfRC; - } cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg ) @@ -1532,6 +1559,38 @@ unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, un return mi; } +/* +1.Move closest previous tempo msg to begin. +2.The first msg in each track must be the first msg >= begin.time +3.Remove all msgs > end.time - except the 'endMsg' for each note/pedal that is active at end time. + + + */ + +unsigned _cmMidiFileIsEndMsg( cmMidiTrackMsg_t* m, cmMidiTrackMsg_t** endMsgArray, unsigned n ) +{ + unsigned i = 0; + for(; imsgN-1 ]->amicro / 1000000.0; } -typedef struct _cmMidiVoice_str -{ - const cmMidiTrackMsg_t* mp; - unsigned durMicros; - bool sustainFl; - struct _cmMidiVoice_str* link; -} _cmMidiVoice_t; - void _cmMidiFileSetDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1 ) { @@ -1574,10 +1625,11 @@ bool _cmMidiFileCalcNoteDur( cmMidiTrackMsg_t* m0, cmMidiTrackMsg_t* m1, int not return true; } -void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) +void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags ) { _cmMidiFile_t* p; - + bool warningFl = cmIsFlag(flags,kWarningsMfFl); + if((p = _cmMidiFileHandleToPtr(h)) == NULL ) return; @@ -1586,13 +1638,14 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) unsigned mi = cmInvalidId; cmMidiTrackMsg_t* noteM[ kMidiNoteCnt * kMidiChCnt ]; // ptr to note-on or NULL if the note is not sounding - cmMidiTrackMsg_t* sustV[ kMidiChCnt ]; - cmMidiTrackMsg_t* sostV[ kMidiChCnt ]; + cmMidiTrackMsg_t* sustV[ kMidiChCnt ]; // ptr to last sustain pedal down msg or NULL if susteain pedal is not down + cmMidiTrackMsg_t* sostV[ kMidiChCnt ]; // ptr to last sost. pedal down msg or NULL if sost. pedal is not down int noteGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note key is depressed bool sostGateM[ kMidiNoteCnt * kMidiChCnt ]; // true if the associated note was active when the sost. pedal went down int sustGateV[ kMidiChCnt]; // true if the associated sustain pedal is down int sostGateV[ kMidiChCnt]; // true if the associated sostenuto pedal is down unsigned i,j; + unsigned n = 0; const cmMidiTrackMsg_t** msgV = _cmMidiFileMsgArray(p); @@ -1634,12 +1687,22 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) unsigned k = ch*kMidiNoteCnt + d0; // there should be no existing sounding note instance for this pitch - //if( noteGateM[k] == 0 && noteM[k] != NULL ) - // cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0)); + if( noteGateM[k] == 0 && noteM[k] != NULL ) + { + if( warningFl ) + cmErrWarnMsg(&p->err,kMissingNoteOffMfRC,"%i : Missing note-off instance for note on:%s",m->uid,cmMidiToSciPitch(d0,NULL,0)); + if( cmIsFlag(flags,kDropReattacksMfFl) ) + { + m->flags |= kDropTrkMsgFl; + n += 1; + } + + } + // if this is a re-attack if( noteM[k] != NULL ) noteGateM[k] += 1; - else + else // this is a new attack { noteM[k] = m; noteGateM[k] = 1; @@ -1676,8 +1739,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) if( cmMidiFileIsSustainPedalDown(m) ) { // if the sustain channel is already down - //if( sustGateV[ch] ) - // cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid); + if( warningFl && sustGateV[ch] ) + cmErrWarnMsg(&p->err,kSustainPedalMfRC,"%i : The sustain pedal went down twice with no intervening release.",m->uid); sustGateV[ch] += 1; @@ -1722,8 +1785,8 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) if( cmMidiFileIsSostenutoPedalDown(m) ) { // if the sustain channel is already down - //if( sostGateV[ch] ) - // cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid); + if( warningFl && sostGateV[ch] ) + cmErrWarnMsg(&p->err,kSostenutoPedalMfRC,"%i : The sostenuto pedal went down twice with no intervening release.",m->uid); // record the notes that are active when the sostenuto pedal went down unsigned k = ch * kMidiNoteCnt; @@ -1770,6 +1833,46 @@ void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ) } } // for each midi file event + + + if( warningFl ) + { + unsigned sustChN = 0; // count of channels where the sustain pedal was left on at the end of the file + unsigned sostChN = 0; // sostenuto + unsigned sustInstN = 0; // count of sustain on with no previous sustain off + unsigned sostInstN = 0; // sostenuto on + unsigned noteN = 0; // count of notes left on at the end of the file + unsigned noteInstN = 0; // count of reattacks + + // initialize the state tracking variables + for(i=0; ierr,kEventTerminationMfRC,"note:%i inst:%i sustain: %i inst: %i sost: %i inst: %i",noteN,noteInstN,sustChN,sustInstN,sostChN,sostInstN); + } + + // drop + if( cmIsFlag(flags,kDropReattacksMfFl) ) + _cmMidiFileDrop(p); + + + } void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks ) @@ -1833,15 +1936,16 @@ void _cmMidiFilePrintHdr( const _cmMidiFile_t* mfp, cmRpt_t* rpt ) cmRptPrintf(rpt,"fmt:%i ticksPerQN:%i tracks:%i\n",mfp->fmtId,mfp->ticksPerQN,mfp->trkN); - cmRptPrintf(rpt," UID dtick atick amicro type ch D0 D1\n"); - cmRptPrintf(rpt,"----- ---------- ---------- ---------- : ---- --- --- ---\n"); + cmRptPrintf(rpt," UID trk dtick atick amicro type ch D0 D1\n"); + cmRptPrintf(rpt,"----- --- ---------- ---------- ---------- : ---- --- --- ---\n"); } void _cmMidiFilePrintMsg( cmRpt_t* rpt, const cmMidiTrackMsg_t* tmp ) { - cmRptPrintf(rpt,"%5i %10u %10llu %10llu : ", + cmRptPrintf(rpt,"%5i %3i %10u %10llu %10llu : ", tmp->uid, + tmp->trkIdx, tmp->dtick, tmp->atick, tmp->amicro ); @@ -1980,7 +2084,7 @@ cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCh goto errLabel; } - cmMidiFileCalcNoteDurations( mfH ); + cmMidiFileCalcNoteDurations( mfH, 0 ); if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC ) return cmErrMsg(&p->err,kFileFailMfRC,"Unable to create the file '%s'.",cmStringNullGuard(outFn)); @@ -2013,7 +2117,7 @@ cmMfRC_t cmMidiFileGenSvgFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmCha goto errLabel; } - cmMidiFileCalcNoteDurations( mfH ); + cmMidiFileCalcNoteDurations( mfH, 0 ); msgN = cmMidiFileMsgCount(mfH); msgs = cmMidiFileMsgArray(mfH); @@ -2159,7 +2263,7 @@ void cmMidiFileTest( const char* fn, cmCtx_t* ctx ) return; } - cmMidiFileCalcNoteDurations( h ); + cmMidiFileCalcNoteDurations( h, 0 ); if( 1 ) { diff --git a/src/cmMidiFile.h b/src/cmMidiFile.h index 6775f31..b5428e2 100644 --- a/src/cmMidiFile.h +++ b/src/cmMidiFile.h @@ -63,11 +63,16 @@ extern "C" { struct cmMidiTrackMsg_str* end; // note-off or pedal-up message } cmMidiChMsg_t; + enum + { + kDropTrkMsgFl = 0x01 + }; typedef struct cmMidiTrackMsg_str { + unsigned flags; // see k???TrkMsgFl unsigned uid; // uid's are unique among all msg's in the file - unsigned dtick; // delta ticks between events on this track + unsigned dtick; // delta ticks between events on this track (ticks between this event and the previous event on this track) unsigned long long atick; // global (all tracks interleaved) accumulated ticks unsigned long long amicro; // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch) @@ -91,9 +96,12 @@ extern "C" { } u; } cmMidiTrackMsg_t; -#define cmMidiFileIsNoteOn(m) (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0) +#define cmMidiFileIsNoteOn(m) (cmMidiIsNoteOn((m)->status) && ((m)->u.chMsgPtr->d1>0)) #define cmMidiFileIsNoteOff(m) (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1)) - + +#define cmMidiFileIsPedalUp(m) (cmMidiIsPedalUp( (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) ) +#define cmMidiFileIsPedalDown(m) (cmMidiIsPedalDown( (m)->status, (m)->u.chMsgPtr->d0, (m)->u.chMsgPtr->d1) ) + #define cmMidiFileIsSustainPedalUp(m) (cmMidiIsSustainPedalUp( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1)) #define cmMidiFileIsSustainPedalDown(m) (cmMidiIsSustainPedalDown( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1)) @@ -118,7 +126,9 @@ extern "C" { kUidNotFoundMfRC, // 13 kUidNotANoteMsgMfRC, // 14 kInvalidTrkIndexMfRC,// 15 - kSvgFailMfRC // 16 + kSvgFailMfRC, // 16 + kMsgNotFoundMfRC, // 17 + kEventTerminationMfRC // 18 }; extern cmMidiFileH_t cmMidiFileNullHandle; @@ -172,6 +182,7 @@ extern "C" { // Set the velocity of a note-on/off msg identified by 'uid'. cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel ); + // Insert a MIDI message relative to the reference msg identified by 'uid'. // If dtick is positive/negative then the new msg is inserted after/before the reference msg. cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 ); @@ -199,8 +210,9 @@ extern "C" { double cmMidiFileDurSecs( cmMidiFileH_t h ); - // Calculate Note Duration - void cmMidiFileCalcNoteDurations( cmMidiFileH_t h ); + // Calculate Note Duration + enum { kWarningsMfFl=0x01, kDropReattacksMfFl=0x02 }; + void cmMidiFileCalcNoteDurations( cmMidiFileH_t h, unsigned flags ); // Set the delay prior to the first non-zero msg. void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks ); @@ -218,8 +230,7 @@ extern "C" { { unsigned uid; unsigned long long amicro; - unsigned density; - + unsigned density; } cmMidiFileDensity_t; // Generate the note onset density measure for each note in the MIDI file. diff --git a/src/cmMsgProtocol.h b/src/cmMsgProtocol.h index d4f29db..e96e96a 100644 --- a/src/cmMsgProtocol.h +++ b/src/cmMsgProtocol.h @@ -41,6 +41,7 @@ extern "C" { kDeviceDuiId, // ui<--eng device label kProgramDuiId, // ui<--eng program label kProgramDfltDuiId, // ui<--eng dflt program label + kPgmDoneDuiId, // ui<--end the program is done // The following selId's are used by cmAudDsp to indicate various commands. kSetAudioCfgDuiId, // 1) select an audio system setup @@ -54,7 +55,7 @@ extern "C" { kSendMsgDuiId, // forward msg to the audio system kDevReportDuiId, // print a device report kPrintPgmDuiId, // write the currently loaded pgm as a JSON file - + kRightAlignDuiId = 0, // label alignment id used by kLabelDuiId kLeftAlignDuiId, kCenterAlignDuiId diff --git a/src/cmPP_NARG.h b/src/cmPP_NARG.h new file mode 100644 index 0000000..edf54ec --- /dev/null +++ b/src/cmPP_NARG.h @@ -0,0 +1,45 @@ +#ifndef cmPP_NARG_H +#define cmPP_NARG_H + + +// Taken from here: +// https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s +// and here: +// https://stackoverflow.com/questions/4421681/how-to-count-the-number-of-arguments-passed-to-a-function-that-accepts-a-variabl + +#define PP_NARG(...) \ + PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) + +#define PP_NARG_(...) \ + PP_128TH_ARG(__VA_ARGS__) + +#define PP_128TH_ARG( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \ + _71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \ + _81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \ + _91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \ + _101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \ + _111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \ + _121,_122,_123,_124,_125,_126,_127,N,...) N +#define PP_RSEQ_N() \ + 127,126,125,124,123,122,121,120, \ + 119,118,117,116,115,114,113,112,111,110, \ + 109,108,107,106,105,104,103,102,101,100, \ + 99,98,97,96,95,94,93,92,91,90, \ + 89,88,87,86,85,84,83,82,81,80, \ + 79,78,77,76,75,74,73,72,71,70, \ + 69,68,67,66,65,64,63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +#endif diff --git a/src/cmProc2.c b/src/cmProc2.c index ff2c3b0..1fd2545 100644 --- a/src/cmProc2.c +++ b/src/cmProc2.c @@ -6501,7 +6501,8 @@ cmRC_t cmSpecDist2Init( cmSpecDist2_t* p, unsigned procSmpCnt, double srate, uns p->wndSmpCnt = wndSmpCnt; p->hopSmpCnt = (unsigned)floor(wndSmpCnt/hopFcmt); p->procSmpCnt = procSmpCnt; - + p->igain = 1.0; + p->ceiling = 30; p->expo = 2.0; @@ -6511,8 +6512,9 @@ cmRC_t cmSpecDist2Init( cmSpecDist2_t* p, unsigned procSmpCnt, double srate, uns p->mix = 0.0; - p->pva = cmPvAnlAlloc( p->obj.ctx, NULL, procSmpCnt, srate, wndSmpCnt, p->hopSmpCnt, flags ); - p->pvs = cmPvSynAlloc( p->obj.ctx, NULL, procSmpCnt, srate, wndSmpCnt, p->hopSmpCnt, olaWndTypeId ); + p->igainV = cmMemResizeZ( cmSample_t, p->igainV, procSmpCnt ); + p->pva = cmPvAnlAlloc( p->obj.ctx, NULL, procSmpCnt, srate, wndSmpCnt, p->hopSmpCnt, flags ); + p->pvs = cmPvSynAlloc( p->obj.ctx, NULL, procSmpCnt, srate, wndSmpCnt, p->hopSmpCnt, olaWndTypeId ); return rc; @@ -6522,7 +6524,7 @@ cmRC_t cmSpecDist2Final(cmSpecDist2_t* p ) { cmRC_t rc = cmOkRC; - + cmMemFree(p->igainV); cmPvAnlFree(&p->pva); cmPvSynFree(&p->pvs); return rc; @@ -6585,8 +6587,12 @@ cmRC_t cmSpecDist2Exec( cmSpecDist2_t* p, const cmSample_t* sp, unsigned sn ) unsigned binN = p->pva->binCnt; + cmVOS_MultVVS( p->igainV, sn, sp, p->igain ); + + //printf("%f\n",p->igainV[0]); + // cmPvAnlExec() returns true when it calc's a new spectral output frame - if( cmPvAnlExec( p->pva, sp, sn ) ) + if( cmPvAnlExec( p->pva, p->igainV, sn ) ) { cmReal_t X0m[binN]; cmReal_t X1m[binN]; @@ -6652,7 +6658,7 @@ const cmSample_t* cmSpecDist2Out( cmSpecDist2_t* p ) void cmSpecDist2Report( cmSpecDist2_t* p ) { - printf("ceil:%f expo:%f mix:%f thresh:%f upr:%f lwr:%f\n", p->ceiling,p->expo,p->mix,p->thresh,p->lwrSlope,p->uprSlope); + printf("igain:%f ceil:%f expo:%f mix:%f thresh:%f upr:%f lwr:%f\n", p->igain, p->ceiling,p->expo,p->mix,p->thresh,p->lwrSlope,p->uprSlope); } diff --git a/src/cmProc2.h b/src/cmProc2.h index 21b0b6c..2b9ec49 100644 --- a/src/cmProc2.h +++ b/src/cmProc2.h @@ -1318,15 +1318,16 @@ extern "C" { typedef struct { - cmObj obj; - double srate; - unsigned wndSmpCnt; - unsigned hopFcmt; - unsigned hopSmpCnt; - unsigned procSmpCnt; - - cmPvAnl* pva; - cmPvSyn* pvs; + cmObj obj; + double srate; + unsigned wndSmpCnt; + unsigned hopFcmt; + unsigned hopSmpCnt; + unsigned procSmpCnt; + double igain; + cmSample_t* igainV; + cmPvAnl* pva; + cmPvSyn* pvs; double ceiling; double expo; diff --git a/src/cmProc4.c b/src/cmProc4.c index cdc49e2..89d312b 100644 --- a/src/cmProc4.c +++ b/src/cmProc4.c @@ -3342,6 +3342,8 @@ cmRC_t _cmScModActivateGroup( cmScModulator* p, cmScModEntry_t* ep ) { unsigned idx = 0; + printf("Activating:%s\n",cmSymTblLabel(p->stH,ep->beg.symId)); + return _cmScModActivateEntries( p, g->earray, &idx, g->en, ep->beg.symId ); } diff --git a/src/cmXml.c b/src/cmXml.c index cfbd27d..05399ee 100644 --- a/src/cmXml.c +++ b/src/cmXml.c @@ -650,6 +650,9 @@ cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent ) return rc; } + if( np==NULL && p->stack==NULL) + break; + // if an end-tag was just read or node was created but closed then pop the stack if( np==NULL || (np==p->stack && cmIsFlag(np->flags,kClosedXmlFl)) ) p->stack = p->stack->parent; diff --git a/src/dsp/cmDspBuiltIn.c b/src/dsp/cmDspBuiltIn.c index 7864709..eea6070 100644 --- a/src/dsp/cmDspBuiltIn.c +++ b/src/dsp/cmDspBuiltIn.c @@ -1067,6 +1067,7 @@ enum { kChAoId, kGainAoId, + kEnableAoId, kInAoId }; @@ -1075,23 +1076,30 @@ cmDspClass_t _cmAudioOutDC; typedef struct { cmDspInst_t inst; + unsigned onSymId; + unsigned offSymId; } cmDspAudioOut_t; cmDspInst_t* _cmDspAudioOutAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) { cmDspVarArg_t args[] = { - { "ch", kChAoId, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Audio output channel index"}, - { "gain",kGainAoId,0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Output gain multiplier"}, - { "in", kInAoId, 0, 1, kInDsvFl | kAudioBufDsvFl, "Audio input" }, + { "ch", kChAoId, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Audio output channel index"}, + { "gain", kGainAoId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Output gain multiplier"}, + { "enable",kEnableAoId,0, 0, kInDsvFl | kSymDsvFl | kOptArgDsvFl, "Enable: on off"}, + { "in", kInAoId, 0, 1, kInDsvFl | kAudioBufDsvFl, "Audio input" }, { NULL, 0, 0, 0, 0 } }; cmDspAudioOut_t* p = cmDspInstAlloc(cmDspAudioOut_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + p->offSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"off"); + p->onSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"on"); + cmDspSetDefaultUInt( ctx, &p->inst, kChAoId, 0, 0); cmDspSetDefaultDouble( ctx, &p->inst, kGainAoId, 0, 1.0); + cmDspSetDefaultSymbol( ctx, &p->inst, kEnableAoId, p->onSymId ); return &p->inst; } @@ -1106,10 +1114,12 @@ cmDspRC_t _cmDspAudioOutReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt cmDspRC_t _cmDspAudioOutExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { - cmDspRC_t rc = kOkDspRC; - unsigned chIdx = cmDspUInt(inst,kChAoId); - unsigned oChCnt = ctx->ctx->oChCnt; - double gain = cmDspDouble(inst,kGainAoId); + cmDspRC_t rc = kOkDspRC; + cmDspAudioOut_t* p = (cmDspAudioOut_t*)inst; + unsigned chIdx = cmDspUInt(inst,kChAoId); + bool enableFl = cmDspSymbol(inst,kEnableAoId) == p->onSymId; + unsigned oChCnt = ctx->ctx->oChCnt; + double gain = cmDspDouble(inst,kGainAoId); if( chIdx >= oChCnt ) { @@ -1118,7 +1128,7 @@ cmDspRC_t _cmDspAudioOutExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_ return rc; } - const cmSample_t* sp = cmDspAudioBuf(ctx,inst,kInAoId,0); + const cmSample_t* sp = cmDspAudioBuf(ctx,inst,kInAoId,0); if( sp == NULL ) { @@ -1132,7 +1142,7 @@ cmDspRC_t _cmDspAudioOutExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_ // if this channel is disabled or set to pass-through then chArray[chIdx] will be NULL if( ctx->ctx->oChArray[chIdx] != NULL ) - cmVOS_MultVVS(ctx->ctx->oChArray[chIdx],n,sp,(cmSample_t)gain); + cmVOS_MultVVS(ctx->ctx->oChArray[chIdx],n,sp, (cmSample_t)(enableFl ? gain : 0)); return kOkDspRC; } @@ -1154,6 +1164,11 @@ cmDspRC_t _cmDspAudioOutRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_ case kGainAoId: cmDspSetEvent(ctx,inst,evt); break; + + case kEnableAoId: + cmDspSetEvent(ctx,inst,evt); + break; + } return rc; } @@ -1687,7 +1702,8 @@ cmDspClass_t* cmMeterClassCons( cmDspCtx_t* ctx ) enum { kInLbId, - kAlignLbId + kAlignLbId, + kTextLbId }; cmDspClass_t _cmLabelDC; @@ -1695,27 +1711,68 @@ cmDspClass_t _cmLabelDC; typedef struct { cmDspInst_t inst; + cmChar_t* label; } cmDspLabel_t; cmDspInst_t* _cmDspLabelAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) { - cmDspVarArg_t args[] = + const unsigned argCnt = 3; + cmDspVarArg_t args[argCnt+1]; + cmChar_t* label = NULL; + unsigned align = kLeftAlignDuiId; + va_list vl1; + + va_copy(vl1,vl); + + if( va_cnt < 1 ) { - { "in", kInLbId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "LabelText" }, - { "align",kAlignLbId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Alignment 0=right 1=left 2=center" }, - { NULL, 0, 0, 0, 0 } - }; + va_end(vl1); + cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'label' constructor argument list must contain at least one argument."); + return NULL; + } - cmDspLabel_t* p = cmDspInstAlloc(cmDspLabel_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl); + // get the default label + const char* clabel = va_arg(vl,const char*); + if( clabel != NULL && strlen(clabel) > 0 ) + { + label = cmLhAllocStr(ctx->lhH,clabel); + printf("%s\n",label); + } - cmDspSetDefaultDouble(ctx, &p->inst, kAlignLbId, 0.0, kLeftAlignDuiId); + // if an alignment id was provided + if( va_cnt > 1 ) + align = va_arg(vl,double); + // setup the arg. config. array. + cmDspArgSetup(ctx,args+0,"in", cmInvalidId, kInLbId, 0,0, kInDsvFl | kTypeDsvMask, "Input to set label" ); + cmDspArgSetup(ctx,args+1,"align",cmInvalidId, kAlignLbId, 0,0, kInDsvFl | kUIntDsvFl, "Justification: 0=right 1=center 2=left" ); + cmDspArgSetup(ctx,args+2,"text", cmInvalidId, kTextLbId, 0,0, kInDsvFl | kStrzDsvFl, "Label text"); + cmDspArgSetupNull(args + argCnt); + + // create the instance + cmDspLabel_t* p = cmDspInstAlloc(cmDspLabel_t,ctx,classPtr,args,instSymId,id,storeSymId,0,vl1); + + p->label = label; + + // set the default variable values + cmDspSetDefaultDouble(ctx, &p->inst, kAlignLbId, 0.0, align); + cmDspSetDefaultStrcz( ctx, &p->inst, kTextLbId, NULL, label==NULL ? "" : label ); + // create the UI control - cmDspUiLabelCreate(ctx,&p->inst,kInLbId,kAlignLbId); + cmDspUiLabelCreate(ctx,&p->inst,kTextLbId,kAlignLbId); + va_end(vl1); + return &p->inst; } +cmDspRC_t _cmDspLabelFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspLabel_t* p = (cmDspLabel_t*)inst; + cmLhFree(ctx->lhH,p->label); + return kOkDspRC; +} + cmDspRC_t _cmDspLabelReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { cmDspApplyAllDefaults(ctx,inst); @@ -1724,6 +1781,21 @@ cmDspRC_t _cmDspLabelReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* cmDspRC_t _cmDspLabelRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) { + const unsigned bN = 128; + cmChar_t b[ bN+1 ]; + + // if this event is arriving on the 'in' port ... + if( evt->dstVarId == kInLbId ) + { + cmDspLabel_t* p = (cmDspLabel_t*)inst; + // ... then convert it to a string + cmDsvToString( evt->valuePtr, p->label, b, bN ); + + // and set the 'label' variable + return cmDspSetStrcz(ctx, inst, kTextLbId, b ); + } + + return cmDspSetEvent(ctx,inst,evt); } @@ -1732,7 +1804,7 @@ cmDspClass_t* cmLabelClassCons( cmDspCtx_t* ctx ) cmDspClassSetup(&_cmLabelDC,ctx,"Label", NULL, _cmDspLabelAlloc, - NULL, + _cmDspLabelFree, _cmDspLabelReset, NULL, _cmDspLabelRecv, @@ -2907,6 +2979,7 @@ enum kLoopWtId, kBegWtId, kEndWtId, + kChWtId, kCmdWtId, kOtWtId, kGainWtId, @@ -2951,6 +3024,7 @@ typedef struct cmAudioFileH_t afH; // current audio file handle int nxtBegSmpIdx; // the beg/end sample index to use with the next filename to arrive at port 'fn' int nxtEndSmpIdx; // + unsigned nxtChIdx; cmThreadH_t thH; bool loadFileFl; cmDspCtx_t* ctx; @@ -2976,6 +3050,7 @@ cmDspInst_t* _cmDspWaveTableAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsi { "loop", kLoopWtId, 0, 0, kInDsvFl | kIntDsvFl | kOptArgDsvFl, "-1=loop forever >0=loop count (dflt:-1)"}, { "beg", kBegWtId, 0, 0, kInDsvFl | kIntDsvFl | kOptArgDsvFl, "File begin sample index" }, { "end", kEndWtId, 0, 0, kInDsvFl | kIntDsvFl | kOptArgDsvFl, "File end sample index (-1=play all)" }, + { "ch", kChWtId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "File channel index 0=left, 1=right" }, { "cmd", kCmdWtId, 0, 0, kInDsvFl | kSymDsvFl | kOptArgDsvFl, "Command: on off"}, { "ot", kOtWtId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Overtone count"}, { "gain", kGainWtId, 0, 0, kInDsvFl | kDoubleDsvFl|kOptArgDsvFl, "Gain"}, @@ -3005,6 +3080,7 @@ cmDspInst_t* _cmDspWaveTableAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsi cmDspSetDefaultInt( ctx, &p->inst, kLoopWtId, 0, -1 ); cmDspSetDefaultInt( ctx, &p->inst, kBegWtId, 0, 0 ); cmDspSetDefaultInt( ctx, &p->inst, kEndWtId, 0, -1 ); + cmDspSetDefaultUInt( ctx, &p->inst, kChWtId, 0, 0 ); cmDspSetDefaultSymbol(ctx, &p->inst, kCmdWtId, p->onSymId ); cmDspSetDefaultUInt( ctx, &p->inst, kOtWtId, 0, 5 ); cmDspSetDefaultDouble(ctx, &p->inst, kGainWtId, 0, 1.0 ); @@ -3038,10 +3114,9 @@ cmDspRC_t _cmDspWaveTableFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt // mode then the the function will automatically begin reading from the begining of the // file segment. If the end of the file segment is encountered and the wave table is not // in loop mode then the empty portion of wt[] will be set to zero. -cmDspRC_t _cmDspWaveTableReadBlock( cmDspCtx_t* ctx, cmDspWaveTable_t* p, cmSample_t* wt, unsigned rdSmpCnt, int begSmpIdx, int endSmpIdx, int maxLoopCnt ) +cmDspRC_t _cmDspWaveTableReadBlock( cmDspCtx_t* ctx, cmDspWaveTable_t* p, cmSample_t* wt, unsigned rdSmpCnt, unsigned chIdx, int begSmpIdx, int endSmpIdx, int maxLoopCnt ) { unsigned actFrmCnt = 0; - unsigned chIdx = 0; unsigned chCnt = 1; unsigned fn = endSmpIdx - p->fi + 1; // count of samples between p->fi and endSmpIdx unsigned n0 = rdSmpCnt; @@ -3117,9 +3192,10 @@ cmDspRC_t _cmDspWaveTableReadAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p, un { unsigned n0 = rdSmpCnt; unsigned n1 = 0; - int begSmpIdx = cmDspInt(&p->inst,kBegWtId); - int endSmpIdx = cmDspInt(&p->inst,kEndWtId); - int maxLoopCnt= cmDspInt(&p->inst,kLoopWtId); + int begSmpIdx = cmDspInt( &p->inst,kBegWtId); + int endSmpIdx = cmDspInt( &p->inst,kEndWtId); + unsigned chIdx = cmDspUInt(&p->inst,kChWtId); + int maxLoopCnt= cmDspInt( &p->inst,kLoopWtId); if( endSmpIdx < begSmpIdx ) endSmpIdx = p->fn-1; @@ -3137,7 +3213,7 @@ cmDspRC_t _cmDspWaveTableReadAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p, un if( p->doneFl ) cmVOS_Zero(p->wt + p->wti,n0); else - if( _cmDspWaveTableReadBlock(ctx, p, p->wt+p->wti, n0,begSmpIdx,endSmpIdx,maxLoopCnt ) != kOkDspRC ) + if( _cmDspWaveTableReadBlock(ctx, p, p->wt+p->wti, n0, chIdx, begSmpIdx,endSmpIdx,maxLoopCnt ) != kOkDspRC ) return cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"An error occured while reading the wave table file."); p->wtn -= n0; // decrease the count of available samples @@ -3149,7 +3225,7 @@ cmDspRC_t _cmDspWaveTableReadAudioFile( cmDspCtx_t* ctx, cmDspWaveTable_t* p, un if( p->doneFl ) cmVOS_Zero(p->wt,n1); else - if( _cmDspWaveTableReadBlock(ctx, p, p->wt, n1,begSmpIdx,endSmpIdx,maxLoopCnt ) != kOkDspRC ) + if( _cmDspWaveTableReadBlock(ctx, p, p->wt, n1, chIdx, begSmpIdx,endSmpIdx,maxLoopCnt ) != kOkDspRC ) return cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"An error occured while reading the wave table file."); p->wtn -= n1; // decrease the count of available samples @@ -3382,6 +3458,7 @@ cmDspRC_t _cmDspWaveTableReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEv p->nxtBegSmpIdx = cmDspInt(&p->inst,kBegWtId); p->nxtEndSmpIdx = cmDspInt(&p->inst,kEndWtId); + p->nxtChIdx = cmDspUInt(&p->inst,kChWtId); return _cmDspWaveTableCreateTable(ctx,p); @@ -3490,6 +3567,7 @@ cmDspRC_t _cmDspWaveTableRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt cmDspSetEvent(ctx,inst,evt); // set the file name variable cmDspSetInt(ctx,inst,kBegWtId,p->nxtBegSmpIdx); // set the beg/end smp idx var's from the stored nxtBeg/EndSmpIdx values cmDspSetInt(ctx,inst,kEndWtId,p->nxtEndSmpIdx); // + cmDspSetUInt(ctx,inst,kChWtId, p->nxtChIdx); // cmDspSetUInt(ctx,inst,kShapeWtId,kFileWtId); // switch to file mode rc = _cmDspWaveTableCreateTable(ctx,p); // reload the wavetable } @@ -3506,6 +3584,11 @@ cmDspRC_t _cmDspWaveTableRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt p->nxtEndSmpIdx = cmDsvGetInt(evt->valuePtr); break; + case kChWtId: + // store for next incoming file name msg + p->nxtChIdx = cmDsvGetUInt(evt->valuePtr); + break; + case kShapeWtId: if( cmDsvGetUInt(evt->valuePtr) < kShapeWtCnt ) { @@ -5546,6 +5629,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cm1UpClassCons, cmGateToSymClassCons, cmPortToSymClassCons, + cmIntToSymClassCons, cmRouterClassCons, cmAvailChClassCons, diff --git a/src/dsp/cmDspClass.h b/src/dsp/cmDspClass.h index c1c4ed0..8d2da2e 100644 --- a/src/dsp/cmDspClass.h +++ b/src/dsp/cmDspClass.h @@ -390,6 +390,9 @@ extern "C" { // Used to transmit messages to the audio system. cmDspRC_t cmDspSendValueToAudioSys( cmDspCtx_t* ctx, unsigned msgTypeId, unsigned selId, unsigned valId, const cmDspValue_t* valPtr ); + // Notify the system that the program is done and can be shutdown + cmDspRC_t cmDspProgramIsDone( cmDspCtx_t* ctx ); + // The following functions are used to send message to the UI and are // implemented in cmDspUi.c. They are declared here because they are // visible to the cmDspInst functions which use them but are not available @@ -417,7 +420,7 @@ extern "C" { cmDspRC_t cmDspUiFnameCreate( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned valVarId, unsigned patVarId, unsigned dirVarId ); cmDspRC_t cmDspUiMsgListCreate(cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned height, unsigned listVarId, unsigned selVarId ); - + //) #ifdef __cplusplus diff --git a/src/dsp/cmDspFx.c b/src/dsp/cmDspFx.c index 5b7a860..bbb1c68 100644 --- a/src/dsp/cmDspFx.c +++ b/src/dsp/cmDspFx.c @@ -2909,6 +2909,7 @@ typedef struct cmDspScalar_str cmDspInst_t inst; _cmDspScalarOpFunc_t func; unsigned inPortCnt; + bool allActiveFl; } cmDspScalarOp_t; cmDspRC_t _cmDspScalarOpFuncMult(cmDspCtx_t* ctx, cmDspInst_t* inst ) @@ -2966,6 +2967,7 @@ cmDspInst_t* _cmDspScalarOpAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig double dfltVal[ inPortCnt ]; unsigned i; _cmDspScalarOpFunc_t fp = NULL; + bool allActiveFl = false; // validate the count of input ports if( inPortCnt == 0 ) @@ -2974,12 +2976,26 @@ cmDspInst_t* _cmDspScalarOpAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig goto errLabel; } - // locate the operation function - if( strcmp(opIdStr,"*") == 0 ) - fp = _cmDspScalarOpFuncMult; - else - if( strcmp(opIdStr,"+") == 0 ) - fp = _cmDspScalarOpFuncAdd; + if( opIdStr != NULL ) + { + switch( opIdStr[0] ) + { + case '*': + fp = _cmDspScalarOpFuncMult; + break; + case '+': + fp = _cmDspScalarOpFuncAdd; + break; + } + + // if the second character of the operator string is '$' then all input ports trigger an output + if( strlen( opIdStr ) > 0 && opIdStr[1]=='$' ) + allActiveFl = true; + + + } + + // validate the operation function if( fp == NULL ) @@ -3012,7 +3028,7 @@ cmDspInst_t* _cmDspScalarOpAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsig p->inPortCnt = inPortCnt; p->func = fp; - + p->allActiveFl = allActiveFl; va_end(vl1); return &p->inst; @@ -3039,7 +3055,7 @@ cmDspRC_t _cmDspScalarOpRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_ if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC ) { - if( evt->dstVarId == kBaseOpdSoId ) + if( evt->dstVarId == kBaseOpdSoId || p->allActiveFl ) p->func(ctx,inst); } @@ -5587,6 +5603,7 @@ cmDspInst_t* _cmDspPortToSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, uns // register the symbol symIdArray[i] = cmSymTblRegisterSymbol(ctx->stH,symLabel); + // input port - any msg in this port will generate an output from 'out' as well as the associated output port cmDspArgSetup(ctx, args+kBaseInPtsId+i, symLabel, cmInvalidId, kBaseInPtsId+i, 0, 0, kInDsvFl | kTypeDsvMask, cmTsPrintfH(ctx->lhH,"%s Input.",symLabel) ); cmDspArgSetup(ctx, args+baseOutPtsId+i, symLabel, cmInvalidId, baseOutPtsId+i, 0, 0, kOutDsvFl | kSymDsvFl, cmTsPrintfH(ctx->lhH,"%s Output.",symLabel) ); @@ -5631,7 +5648,7 @@ cmDspRC_t _cmDspPortToSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEv unsigned idx = evt->dstVarId - kBaseInPtsId; assert( idx < p->symIdCnt ); cmDspSetSymbol(ctx,inst,p->baseOutPtsId + idx, p->symIdArray[idx]); - return cmDspSetSymbol(ctx,inst,kOutPtsId,p->symIdArray[ evt->dstVarId - kBaseInPtsId ]); + return cmDspSetSymbol(ctx,inst,kOutPtsId, p->symIdArray[idx]); } return rc; @@ -5652,6 +5669,178 @@ cmDspClass_t* cmPortToSymClassCons( cmDspCtx_t* ctx ) return &_cmPortToSym_DC; } +//------------------------------------------------------------------------------------------------------------ +//) +//( { label:cmDspIntToSym file_desc:"Send a pre-defined symbol every time a message arrives a given input port." kw:[sunit] } +enum +{ + kInItsId, + kOutItsId, + kBaseInItsId +}; + +cmDspClass_t _cmIntToSym_DC; + +typedef struct +{ + cmDspInst_t inst; + int* intArray; + unsigned* symIdArray; + unsigned symIdCnt; + unsigned baseIntItsId; + unsigned baseOutItsId; + +} cmDspIntToSym_t; + +cmDspInst_t* _cmDspIntToSym_Alloc(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); + + if( va_cnt < 2 || va_cnt % 2 !=0 ) + { + va_end(vl1); + cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'IntToSym' constructor argument list must contain at least one int/symbol pair and all pairs must be complete."); + return NULL; + } + + unsigned symCnt = va_cnt/2; + unsigned argCnt = 2 + 3*symCnt; + cmDspVarArg_t args[argCnt+1]; + + unsigned* symIdArray = cmMemAllocZ(unsigned,symCnt); + int* intArray = cmMemAllocZ(int,symCnt); + unsigned baseIntItsId = kBaseInItsId + symCnt; + unsigned baseOutItsId = baseIntItsId + symCnt; + + // setup the integer input and symbol output port arg recd + cmDspArgSetup(ctx,args, "in", cmInvalidId, kInItsId, 0, 0, kInDsvFl | kIntDsvFl, "Integer input" ); + cmDspArgSetup(ctx,args+1,"out", cmInvalidId, kOutItsId, 0, 0, kOutDsvFl | kSymDsvFl, "Output" ); + + unsigned i; + + for(i=0; istH,symLabel); + + // trigger port associated with this symbol (any msg on this port will trigger an output) + cmDspArgSetup(ctx, args+kBaseInItsId+i, symLabel, cmInvalidId, kBaseInItsId+i, 0, 0, kInDsvFl | kTypeDsvMask, cmTsPrintfH(ctx->lhH,"%s Input.",symLabel) ); + + // this port is used to set the integer value associated with this symbol + cmDspArgSetup(ctx, args+baseIntItsId+i, intLabel, cmInvalidId, baseIntItsId+i, 0, 0, kInDsvFl | kIntDsvFl, cmTsPrintfH(ctx->lhH,"Set the integer value associated with %s.",symLabel) ); + + // symbol output port - when ever this symbol is sent out it will go out this port as well as the 'out' port + cmDspArgSetup(ctx, args+baseOutItsId+i, symLabel, cmInvalidId, baseOutItsId+i, 0, 0, kOutDsvFl | kSymDsvFl, cmTsPrintfH(ctx->lhH,"%s Output.",symLabel) ); + + + } + + cmDspArgSetupNull(args + argCnt); + + cmDspIntToSym_t* p = cmDspInstAlloc(cmDspIntToSym_t,ctx,classPtr,args,instSymId,id,storeSymId,0,vl1); + + p->symIdCnt = symCnt; + p->intArray = intArray; + p->symIdArray = symIdArray; + p->baseOutItsId = baseOutItsId; + p->baseIntItsId = baseIntItsId; + + cmDspSetDefaultSymbol(ctx,&p->inst,kOutItsId,cmInvalidId); + + va_end(vl1); + + return &p->inst; +} +cmDspRC_t _cmDspIntToSym_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst; + cmMemFree(p->symIdArray); + return kOkDspRC; +} + +cmDspRC_t _cmDspIntToSym_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + return cmDspApplyAllDefaults(ctx,inst); +} + +cmDspRC_t _cmDspIntToSymSendOut( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned idx ) +{ + cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst; + assert( idx < p->symIdCnt ); + cmDspSetSymbol(ctx,inst,p->baseOutItsId + idx, p->symIdArray[idx]); + return cmDspSetSymbol(ctx, inst, kOutItsId, p->symIdArray[ idx ]); +} + + +cmDspRC_t _cmDspIntToSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst; + + // if an integer arrived at 'in' + if( evt->dstVarId == kInItsId ) + { + cmDspSetEvent(ctx,inst,evt); + + unsigned i; + int intVal = cmDspInt(inst,kInItsId); + + for(i=0; isymIdCnt; ++i) + if( intVal == p->intArray[i] ) + { + rc = _cmDspIntToSymSendOut( ctx, inst, i ); + break; + } + } + else + { + // if a msg of any type is recieved on an input port - send out the associated symbol + if( kBaseInItsId <= evt->dstVarId && evt->dstVarId < kBaseInItsId + p->symIdCnt ) + { + _cmDspIntToSymSendOut( ctx, inst, evt->dstVarId - kBaseInItsId ); + } + else + + // if this is a new interger value for this symbol + if( p->baseIntItsId <= evt->dstVarId && evt->dstVarId < p->baseIntItsId + p->symIdCnt ) + { + cmDspSetEvent(ctx,inst,evt); + + p->intArray[ evt->dstVarId - p->baseIntItsId ] = cmDspInt( inst, evt->dstVarId ); + } + } + + + return rc; +} + +cmDspClass_t* cmIntToSymClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmIntToSym_DC,ctx,"IntToSym", + NULL, + _cmDspIntToSym_Alloc, + _cmDspIntToSym_Free, + _cmDspIntToSym_Reset, + NULL, + _cmDspIntToSym_Recv, + NULL,NULL, + "If a message of any kind is received on a port then send the symbol associated with the port."); + + return &_cmIntToSym_DC; +} + //------------------------------------------------------------------------------------------------------------ //) //( { label:cmDspRouter file_desc:"Route the input value to one of multiple output ports." kw:[sunit] } diff --git a/src/dsp/cmDspFx.h b/src/dsp/cmDspFx.h index fe84570..c5af6bb 100644 --- a/src/dsp/cmDspFx.h +++ b/src/dsp/cmDspFx.h @@ -36,6 +36,7 @@ extern "C" { struct cmDspClass_str* cm1UpClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmGateToSymClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmPortToSymClassCons( cmDspCtx_t* ctx ); + struct cmDspClass_str* cmIntToSymClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmRouterClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmAvailChClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmPresetClassCons( cmDspCtx_t* ctx ); diff --git a/src/dsp/cmDspKr.c b/src/dsp/cmDspKr.c index 5af96bb..187a233 100644 --- a/src/dsp/cmDspKr.c +++ b/src/dsp/cmDspKr.c @@ -302,6 +302,8 @@ enum kMixKr2Id, kWetKr2Id, + kIgainKr2Id, + kAudioInKr2Id, kAudioOutKr2Id }; @@ -320,7 +322,7 @@ cmDspInst_t* _cmDspKr2Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned s { cmDspVarArg_t args[] = { - { "wndn", kWndSmpCntKr2Id, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Window sample count" }, + { "wndn", kWndSmpCntKr2Id, 0, 0, kInDsvFl | kUIntDsvFl | kReqArgDsvFl, "Window sample count" }, { "hopf", kHopFactKr2Id, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Hop factor" }, { "ceil", kCeilKr2Id, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Ceiling" }, @@ -333,6 +335,8 @@ cmDspInst_t* _cmDspKr2Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned s { "mix", kMixKr2Id, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Mix"}, { "wet", kWetKr2Id, 0, 0, kInDsvFl | kSampleDsvFl, "Wet mix level."}, + { "igain", kIgainKr2Id, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Input gain."}, + { "in", kAudioInKr2Id, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio Input" }, { "out", kAudioOutKr2Id, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio Output" }, { NULL, 0, 0, 0, 0 } @@ -355,7 +359,10 @@ cmDspInst_t* _cmDspKr2Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned s cmDspSetDefaultDouble( ctx,&p->inst, kMixKr2Id, 0, 0.0 ); cmDspSetDefaultSample( ctx,&p->inst, kWetKr2Id, 0, 1.0); + + cmDspSetDefaultDouble( ctx,&p->inst, kIgainKr2Id, 0, 0.0 ); + //_cmDspKr2CmInit(ctx,p); // initialize the cm library p->ctx = cmCtxAlloc(NULL,ctx->rpt,ctx->lhH,ctx->stH); @@ -504,11 +511,15 @@ cmDspRC_t _cmDspKr2Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* ev case kWetKr2Id: break; + case kIgainKr2Id: + p->sdp->igain = cmDspDouble(inst,kIgainKr2Id); + break; + default: { assert(0); } } - cmSpecDist2Report(p->sdp); + //cmSpecDist2Report(p->sdp); return rc; } diff --git a/src/dsp/cmDspPgm.c b/src/dsp/cmDspPgm.c index 897ffe6..fb347bb 100644 --- a/src/dsp/cmDspPgm.c +++ b/src/dsp/cmDspPgm.c @@ -21,6 +21,7 @@ #include "cmTime.h" #include "cmAudioSys.h" #include "cmProcObj.h" +#include "cmPP_NARG.h" #include "cmDspCtx.h" #include "cmDspClass.h" #include "cmDspSys.h" @@ -897,7 +898,7 @@ cmDspRC_t _cmDspSysPgm_UiTest(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* prp = cmDspSysAllocInst(h,"Printer", NULL, 1, ">" ); cmDspInst_t* mtp = cmDspSysAllocInst(h,"Meter", "meter", 3, 0.0, 0.0, 4.0); cmDspInst_t* ctp = cmDspSysAllocInst(h,"Counter", NULL, 3, 0.0, 10.0, 1.0 ); - cmDspSysAllocInst(h,"Label", "label1", 1, "label2"); + cmDspInst_t* lbl = cmDspSysAllocInst(h,"Label", "label1", 1, "label2"); if((rc = cmDspSysLastRC(h)) != kOkDspRC ) return rc; @@ -923,6 +924,8 @@ cmDspRC_t _cmDspSysPgm_UiTest(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, chb, "out", prp, "in", NULL ); cmDspSysInstallCb(h, chb, "sym", prp, "in", NULL ); + cmDspSysInstallCb(h, mdp, "val", lbl, "in", NULL ); + return rc; } @@ -2054,8 +2057,8 @@ cmDspRC_t _cmDspSysPgm_ScalarOp( cmDspSysH_t h, void** userPtrPtr ) { cmDspRC_t rc; - cmDspInst_t* add = cmDspSysAllocInst( h, "ScalarOp", NULL, 6, 2, "+", "in-0", 0.0, "in-1", 0.0 ); - cmDspInst_t* mul0 = cmDspSysAllocInst( h, "ScalarOp", NULL, 6, 2, "*", "in-0", 0.0, "in-1", 0.0 ); + cmDspInst_t* add = cmDspSysAllocInst( h, "ScalarOp", NULL, 6, 2, "+", "in-0", 0.0, "in-1", 0.0 ); + cmDspInst_t* mul0 = cmDspSysAllocInst( h, "ScalarOp", NULL, 6, 2, "*$", "in-0", 0.0, "in-1", 0.0 ); cmDspInst_t* mul1 = cmDspSysAllocInst( h, "ScalarOp", NULL, 6, 2, "*", "in-0", 0.0, "in-1", 0.0 ); cmDspInst_t* in = cmDspSysAllocScalar( h, "Input", 0.0, 10.0, 0.001, 0.0); cmDspInst_t* in_m = cmDspSysAllocScalar( h, "Input_M", 0.0, 10.0, 0.001, 0.0); @@ -2067,6 +2070,18 @@ cmDspRC_t _cmDspSysPgm_ScalarOp( cmDspSysH_t h, void** userPtrPtr ) if((rc = cmDspSysLastRC(h)) != kOkDspRC ) goto errLabel; + // Notice that changing 'in' or 'in_m' causes 'out' to be recomputed, but other + // changes are cached prior to 'add'. This prevents the program from going into + // an infinite loop. + // + // in -> mult0 + // in_m -> mult0--+ + // +-->fb -> mult1 +----> add + // | fb_m -> mult1-------> add --------+------> out + // | | + // +-------------------------------------+ + // + cmDspSysInstallCb( h, in, "val", mul0, "in-0", NULL ); cmDspSysInstallCb( h, in_m, "val", mul0, "in-1", NULL ); cmDspSysInstallCb( h, fb, "val", mul1, "in-0", NULL ); @@ -2870,36 +2885,77 @@ cmDspRC_t _cmDspSysPgm_PortToSym( cmDspSysH_t h, void** userPtrPtr ) { cmDspRC_t rc = kOkDspRC; - cmDspInst_t* btn0 = cmDspSysAllocButton( h, "Btn0", 0.0 ); - cmDspInst_t* btn1 = cmDspSysAllocButton( h, "Btn1", 0.0 ); - cmDspInst_t* btn2 = cmDspSysAllocButton( h, "Btn2", 0.0 ); + inst_t* btn0 = button( "Btn0", 0.0 ); + inst_t* btn1 = button( "Btn1", 0.0 ); + inst_t* btn2 = button( "Btn2", 0.0 ); - cmDspInst_t* pts = cmDspSysAllocInst( h, "PortToSym", NULL, 3, "one", "two", "three"); + inst_t* pts = inst( "PortToSym", NULL, "one", "two", "three"); - cmDspInst_t* pr0 = cmDspSysAllocInst( h, "Printer", NULL, 1, "0:" ); - cmDspInst_t* pr1 = cmDspSysAllocInst( h, "Printer", NULL, 1, "1:" ); + inst_t* pr0 = inst( "Printer", NULL, "sym:" ); + inst_t* pr1 = inst( "Printer", NULL, "btn:" ); + inst_t* pr2 = inst( "Printer", NULL, "out:" ); // check for allocation errors if((rc = cmDspSysLastRC(h)) != kOkDspRC ) goto errLabel; - cmDspSysInstallCb( h, btn0, "out", pts, "one",NULL); - cmDspSysInstallCb( h, btn1, "out", pts, "two",NULL); - cmDspSysInstallCb( h, btn2, "out", pts, "three",NULL); + event( btn0, out, pts, one ); + event( btn1, out, pts, two ); + event( btn2, out, pts, three ); - cmDspSysInstallCb( h, btn0, "out", pr1, "in",NULL); - cmDspSysInstallCb( h, btn1, "out", pr1, "in",NULL); - cmDspSysInstallCb( h, btn2, "out", pr1, "in",NULL); - - cmDspSysInstallCb( h, pts, "one", pr0, "in", NULL ); - cmDspSysInstallCb( h, pts, "two", pr0, "in", NULL ); - cmDspSysInstallCb( h, pts, "three", pr0, "in", NULL ); + event( btn0, out, pr1, in ); + event( btn1, out, pr1, in ); + event( btn2, out, pr1, in ); + event( pts, one, pr0, in ); + event( pts, two, pr0, in ); + event( pts, three, pr0, in ); + event( pts, out, pr2, in ); errLabel: return rc; } +//------------------------------------------------------------------------------ +//) +//( { label:cmDspPgm_IntToSym file_desc:"IntToSym example program." kw:[spgm] } +cmDspRC_t _cmDspSysPgm_IntToSym( cmDspSysH_t h, void** userPtrPtr ) +{ + cmDspRC_t rc = kOkDspRC; + + inst_t* sel0 = scalar( "Sel0", 0.0, 10.0, 1.0, 1.0 ); + inst_t* sel1 = scalar( "Sel1", 0.0, 10.0, 1.0, 1.0 ); + inst_t* sel2 = scalar( "Sel2", 0.0, 10.0, 1.0, 1.0 ); + inst_t* val = scalar( "Val", 0.0, 10.0, 1.0, 1.0 ); + + inst_t* pts = inst( "IntToSym", NULL, 0, "one", 0, "two", 0, "three"); + + inst_t* pr0 = inst( "Printer", NULL, "val:" ); + inst_t* pr1 = inst( "Printer", NULL, "sym:" ); + inst_t* pr2 = inst( "Printer", NULL, "out:" ); + + // check for allocation errors + if((rc = cmDspSysLastRC(h)) != kOkDspRC ) + goto errLabel; + + event( sel0, val, pts, one-int ); + event( sel1, val, pts, two-int ); + event( sel2, val, pts, three-int ); + + event( val, val, pts, in ); + event( val, val, pr0, in ); + + event( pts, one, pr1, in ); + event( pts, two, pr1, in ); + event( pts, three, pr1, in ); + + event( pts, out, pr2, in ); + + errLabel: + return rc; +} + + //------------------------------------------------------------------------------ //) //( { label:cmDspPgm_Line file_desc:"Line generator example program." kw:[spgm] } @@ -3288,6 +3344,7 @@ _cmDspSysPgm_t _cmDspSysPgmArray[] = { "line", _cmDspSysPgm_Line, NULL, NULL }, { "1Up", _cmDspSysPgm_1Up, NULL, NULL }, { "PortToSym", _cmDspSysPgm_PortToSym, NULL, NULL }, + { "IntToSym", _cmDspSysPgm_IntToSym, NULL, NULL }, { "preset", _cmDspSysPgm_Preset, NULL, NULL }, { "rsrcWr", _cmDspSysPgm_RsrcWr, NULL, NULL }, { "router", _cmDspSysPgm_Router, NULL, NULL }, diff --git a/src/dsp/cmDspPgmKrChain2.c b/src/dsp/cmDspPgmKrChain2.c index 21aaf78..051b509 100644 --- a/src/dsp/cmDspPgmKrChain2.c +++ b/src/dsp/cmDspPgmKrChain2.c @@ -105,6 +105,7 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS unsigned paramRtChCnt = 2; cmDspInst_t* wnd_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); cmDspInst_t* hop_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); + cmDspInst_t* ign_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); cmDspInst_t* cel_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); cmDspInst_t* exp_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); cmDspInst_t* mix_rt = cmDspSysAllocInst(h, "Router", NULL, 2, paramRtChCnt, paramRtChCnt-1 ); @@ -118,7 +119,9 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspInst_t* kr1 = cmDspSysAllocInst(h, "Kr2", NULL, 2, krWndSmpCnt, krHopFact ); cmDspInst_t* xfad = cmDspSysAllocInst(h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl ); cmDspInst_t* mix = cmDspSysAllocInst(h, "AMix", NULL, 3, xfadeChCnt, mixGain, mixGain ); - cmDspInst_t* cmp = cmDspSysAllocInst(h, "Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs ); + cmDspInst_t* cmp = cmDspSysAllocInst(h, "Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs ); + + // Internal audio connections cmDspSysConnectAudio(h, kr0, "out", xfad, "in-0"); @@ -158,6 +161,7 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspSysNewColumn(h,0); cmDspInst_t* wnd_ctl = cmDspSysAllocMsgListP(h,preGrpSymId,NULL, lbl("WndSmpCnt"), NULL, "wndSmpCnt", 2); cmDspInst_t* hop_ctl = cmDspSysAllocMsgListP(h,preGrpSymId,NULL, lbl("HopFact"), NULL, "hopFact", 2); + cmDspInst_t* ign_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("In Gain"), 0.0, 10.0, 0.001, 1.0 ); cmDspInst_t* cel_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("Ceiling"), 0.0, 100.0, 0.1, 30.0 ); cmDspInst_t* exp_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("Expo"), -10.0, 10.0, 0.01, 2.0 ); cmDspInst_t* mix_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("Mix"), 0.0, 1.0, 0.01, 0.0 ); @@ -166,7 +170,6 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspInst_t* lwr_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("Lwr slope"), 0.3, 10.0, 0.01, 2.0 ); cmDspInst_t* wet_ctl = cmDspSysAllocScalarP( h,preGrpSymId,NULL, lbl("Wet Dry"), 0.0, 1.0, 0.001, 1.0 ); - cmDspSysInstallCb(h, wnd_ctl, "out", wnd_rt, "f-in", NULL ); cmDspSysInstallCb(h, achan, "ch", wnd_rt, "sel", NULL ); // ach->rt sel cmDspSysInstallCb(h, wnd_rt, "f-out-0", kr0, "wndn", NULL ); // wndn->kr @@ -176,7 +179,12 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspSysInstallCb(h, achan, "ch", hop_rt, "sel", NULL ); // ach->rt sel cmDspSysInstallCb(h, hop_rt, "f-out-0", kr0, "hopf", NULL ); // hopf->kr cmDspSysInstallCb(h, hop_rt, "f-out-1", kr1, "hopf", NULL ); // hopf->kr - + + cmDspSysInstallCb(h, ign_ctl, "val", ign_rt, "f-in", NULL ); + cmDspSysInstallCb(h, achan, "ch", ign_rt, "sel", NULL ); // ach->rt sel + cmDspSysInstallCb(h, ign_rt, "f-out-0", kr0, "igain", NULL ); // ign->kr + cmDspSysInstallCb(h, ign_rt, "f-out-1", kr1, "igain", NULL ); // ign->kr + cmDspSysInstallCb(h, thr_ctl, "val", thr_rt, "f-in", NULL ); cmDspSysInstallCb(h, achan, "ch", thr_rt, "sel", NULL ); // ach->rt sel cmDspSysInstallCb(h, thr_rt, "f-out-0", kr0, "thrh", NULL ); // thr->kr @@ -260,6 +268,7 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspSysInstallCb(h, modp, mlbl("hop"), hop_ctl, "sel", NULL ); + cmDspSysInstallCb(h, modp, mlbl("ign"), ign_ctl, "val", NULL ); cmDspSysInstallCb(h, modp, mlbl("ceil"), cel_ctl, "val", NULL ); cmDspSysInstallCb(h, modp, mlbl("expo"), exp_ctl, "val", NULL ); cmDspSysInstallCb(h, modp, mlbl("mix"), mix_ctl, "val", NULL ); @@ -267,7 +276,7 @@ void _cmDspSys_TlXformChain( cmDspSysH_t h, cmDspTlXform_t* c, unsigned preGrpS cmDspSysInstallCb(h, modp, mlbl("upr"), upr_ctl, "val", NULL ); cmDspSysInstallCb(h, modp, mlbl("lwr"), lwr_ctl, "val", NULL ); cmDspSysInstallCb(h, modp, mlbl("wet"), wet_ctl, "val", NULL ); - cmDspSysInstallCb(h, modp, mlbl("sw"), achan, "trig", NULL ); // See also: amp.sfloc->achan.trig + cmDspSysInstallCb(h, modp, mlbl("sw"), achan, "trig", NULL ); // See also: amp.sfloc->achan.trig c->achan = achan; diff --git a/src/dsp/cmDspPgmKrTimeLineLiteAf.c b/src/dsp/cmDspPgmKrTimeLineLiteAf.c index 100fda6..dc07094 100644 --- a/src/dsp/cmDspPgmKrTimeLineLiteAf.c +++ b/src/dsp/cmDspPgmKrTimeLineLiteAf.c @@ -62,32 +62,30 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) //int baseAudioInCh = 0; // 2; int baseAudioOutCh = 0;// 2; - //cmDspInst_t* ai0 = cmDspSysAllocInst(h,"AudioIn", NULL, 1, baseAudioInCh + 0); - //cmDspInst_t* ai1 = cmDspSysAllocInst(h,"AudioIn", NULL, 1, baseAudioInCh + 1); - //cmDspInst_t* mip = cmDspSysAllocInst(h,"MidiIn", NULL, 2, "MOTU - Traveler mk3", "MIDI Port"); - //cmDspInst_t* mip = cmDspSysAllocInst(h,"MidiIn", NULL, 2, "Apple Inc. - IAC Driver", "Bus 1"); cmDspInst_t* tlp = cmDspSysAllocInst(h,"TimeLine", "tl", 2, r.tlFn, r.tlPrefixPath ); cmDspInst_t* scp = cmDspSysAllocInst(h,"Score", "sc", 1, r.scFn ); cmDspInst_t* pts = cmDspSysAllocInst(h,"PortToSym", NULL, 2, "on", "off" ); - cmDspInst_t* php = cmDspSysAllocInst(h,"Phasor", NULL, 0 ); - cmDspInst_t* wtp = cmDspSysAllocInst(h,"WaveTable",NULL, 2, ((int)cmDspSysSampleRate(h)), 1 ); + cmDspInst_t* php = cmDspSysAllocInst(h,"Phasor", NULL, 0 ); + cmDspInst_t* wt0 = cmDspSysAllocInst(h,"WaveTable", NULL, 7, ((int)cmDspSysSampleRate(h)), 1, NULL, -1, 0, -1, 0 ); + cmDspInst_t* wt1 = cmDspSysAllocInst(h,"WaveTable", NULL, 7, ((int)cmDspSysSampleRate(h)), 1, NULL, -1, 0, -1, 1 ); cmDspInst_t* mfp = cmDspSysAllocInst(h,"MidiFilePlay",NULL, 0 ); cmDspInst_t* nmp = cmDspSysAllocInst(h,"NanoMap", NULL, 0 ); - //cmDspInst_t* pic = cmDspSysAllocInst(h,"Picadae", NULL, 0 ); - cmDspInst_t* mop = cmDspSysAllocInst(h,"MidiOut", NULL, 2, "Fastlane","Fastlane MIDI A" ); - cmDspInst_t* mo2p = cmDspSysAllocInst(h,"MidiOut", NULL, 2, "Fastlane","Fastlane MIDI B"); cmDspInst_t* sfp = cmDspSysAllocInst(h,"ScFol", NULL, 5, r.scFn, sfBufCnt, sfMaxWndCnt, sfMinVel, sfEnaMeasFl ); cmDspInst_t* amp = cmDspSysAllocInst(h,"ActiveMeas", NULL, 1, 100 ); cmDspInst_t* modp = cmDspSysAllocInst(h,"ScMod", NULL, 2, r.modFn, "m1" ); + cmDspInst_t* its = cmDspSysAllocInst(h,"IntToSym", NULL, 2, 0, "off"); unsigned preGrpSymId = cmDspSysPresetRegisterGroup(h,"tl"); unsigned cmpPreGrpSymId = cmDspSysPresetRegisterGroup(h,"tl_cmp"); cmDspTlXform_t c0,c1; + memset(&c0,0,sizeof(c0)); + memset(&c1,0,sizeof(c1)); + cmDspSysNewPage(h,"Controls-0"); _cmDspSys_TlXformChain(h, &c0, preGrpSymId, cmpPreGrpSymId, amp, modp, 0, 0 ); @@ -95,14 +93,14 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspSysNewPage(h,"Controls-1"); _cmDspSys_TlXformChain(h, &c1, preGrpSymId, cmpPreGrpSymId, amp, modp, 1, 1 ); + cmDspInst_t* lmix = cmDspSysAllocInst(h, "AMix", NULL, 1, 2 ); + cmDspInst_t* rmix = cmDspSysAllocInst(h, "AMix", NULL, 1, 2 ); - cmDspInst_t* ao0 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+2 ); // 4 Piano 1 Output - cmDspInst_t* ao1 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+3 ); // 5 2 - cmDspInst_t* ao2 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+0 ); // 2 Transform 1 OUtput - cmDspInst_t* ao3 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+1 ); // 3 2 + cmDspInst_t* ao0 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+0 ); + cmDspInst_t* ao1 = cmDspSysAllocInst(h,"AudioOut", NULL, 1, baseAudioOutCh+1 ); cmDspSysNewPage(h,"Main"); - cmDspInst_t* notesOffb= cmDspSysAllocInst(h,"Button", "notesOff", 2, kButtonDuiId, 1.0 ); + //cmDspInst_t* notesOffb= cmDspSysAllocInst(h,"Button", "notesOff", 2, kButtonDuiId, 1.0 ); cmDspInst_t* onb = cmDspSysAllocInst(h,"Button", "start", 2, kButtonDuiId, 1.0 ); cmDspInst_t* offb = cmDspSysAllocInst(h,"Button", "stop", 2, kButtonDuiId, 1.0 ); cmDspInst_t* mod_sel = cmDspSysAllocMsgList(h, NULL, "mod_sel", 1 ); @@ -115,11 +113,7 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) // Record <-> Live switches cmDspInst_t* tlRt = cmDspSysAllocInst(h,"Router", NULL, 2, 2, 0); // time line swich cmDspInst_t* mfpRt = cmDspSysAllocInst(h,"Router", NULL, 2, 2, 0); - //cmDspInst_t* amRt = cmDspSysAllocInst(h,"Router", NULL, 2, 2, 0); - //cmDspSysNewColumn(h,0); - //cmDspInst_t* igain0 = cmDspSysAllocInst(h,"Scalar", "In Gain-0", 5, kNumberDuiId, 0.0, 100.0,0.01, 1.0 ); - //cmDspInst_t* igain1 = cmDspSysAllocInst(h,"Scalar", "In Gain-1", 5, kNumberDuiId, 0.0, 100.0,0.01, 1.0 ); //cmDspSysNewColumn(h,0); cmDspInst_t* ogain0 = cmDspSysAllocInst(h,"Scalar", "Dry Out Gain-0", 5, kNumberDuiId, 0.0, 10.0,0.01, 1.0 ); @@ -127,6 +121,16 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* ogain2 = cmDspSysAllocInst(h,"Scalar", "Wet Out Gain-2", 5, kNumberDuiId, 0.0, 10.0,0.01, 1.0 ); cmDspInst_t* ogain3 = cmDspSysAllocInst(h,"Scalar", "Wet Out Gain-3", 5, kNumberDuiId, 0.0, 10.0,0.01, 1.0 ); + cmDspInst_t* ogainW = cmDspSysAllocInst(h,"Scalar", "Wet Master", 5, kNumberDuiId, 0.0, 10.0,0.01, 1.0 ); + cmDspInst_t* ogainD = cmDspSysAllocInst(h,"Scalar", "Dry Master", 5, kNumberDuiId, 0.0, 10.0,0.01, 1.0 ); + + cmDspInst_t* gmult0 = cmDspSysAllocInst(h,"ScalarOp", NULL, 6, 2, "*$", "in-0", 1.0, "in-1", 1.0 ); + cmDspInst_t* gmult1 = cmDspSysAllocInst(h,"ScalarOp", NULL, 6, 2, "*$", "in-0", 1.0, "in-1", 1.0 ); + cmDspInst_t* gmult2 = cmDspSysAllocInst(h,"ScalarOp", NULL, 6, 2, "*$", "in-0", 1.0, "in-1", 1.0 ); + cmDspInst_t* gmult3 = cmDspSysAllocInst(h,"ScalarOp", NULL, 6, 2, "*$", "in-0", 1.0, "in-1", 1.0 ); + + + // Audio file recording cmDspInst_t* recdGain= cmDspSysAllocInst(h,"Scalar", "Recd Gain", 5, kNumberDuiId, 0.0, 100.0,0.01, 1.5 ); cmDspInst_t* recdChk = cmDspSysAllocInst(h,"Button", "Record", 2, kCheckDuiId, 0.0 ); @@ -135,10 +139,13 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* mi0p = cmDspSysAllocInst(h,"AMeter","In 0", 0); cmDspInst_t* mi1p = cmDspSysAllocInst(h,"AMeter","In 1", 0); - cmDspInst_t* meas = cmDspSysAllocInst(h,"Scalar", "Meas", 5, kNumberDuiId, 1.0, 59.0,1.0, 1.0 ); + cmDspInst_t* meas = cmDspSysAllocInst(h,"Scalar", "Begin Meas", 5, kNumberDuiId, 1.0, 1000.0, 1.0, 1.0 ); + cmDspInst_t* eloc = cmDspSysAllocInst(h,"Scalar", "End Loc", 5, kNumberDuiId, 1.0, 1000.0, 1.0, 1.0 ); + cmDspInst_t* sfp_loc = cmDspSysAllocInst(h,"Label", NULL, 1, "sf loc:"); + cmDspSysInstallCb( h, meas, "val", scp, "meas", NULL); cmDspSysInstallCb( h, meas, "val", tlp, "meas", NULL); - + @@ -173,37 +180,34 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, recdPtS, "out", afop, "sel", NULL ); // Audio connections - - cmDspSysConnectAudio(h, php, "out", wtp, "phs" ); // phasor -> wave table - cmDspSysConnectAudio(h, wtp, "out", ao0, "in" ); // wave table -> audio out (dry output) - cmDspSysConnectAudio(h, wtp, "out", ao1, "in" ); // + cmDspSysConnectAudio(h, php, "out", wt0, "phs" ); // phasor -> wave table + cmDspSysConnectAudio(h, php, "out", wt1, "phs" ); // - //cmDspSysConnectAudio( h, ai0, "out", ao0, "in" ); // dry signal through - //cmDspSysConnectAudio( h, ai1, "out", ao1, "in" ); // - - //cmDspSysConnectAudio( h, ai0, "out", mi0p, "in" ); // - //cmDspSysConnectAudio( h, ai0, "out", c0.kr0, "in" ); // ain -> ch0.kr0 - //cmDspSysConnectAudio( h, ai0, "out", c0.kr1, "in" ); // ain -> ch0.kr1 + cmDspSysConnectAudio(h, wt0, "out", lmix, "in-0" ); // wave table -> audio out (dry output) + cmDspSysConnectAudio(h, wt1, "out", rmix, "in-0" ); // - cmDspSysConnectAudio( h, wtp, "out", mi0p, "in" ); // - cmDspSysConnectAudio( h, wtp, "out", c0.kr0, "in" ); // ain -> ch0.kr0 - cmDspSysConnectAudio( h, wtp, "out", c0.kr1, "in" ); // ain -> ch0.kr1 + //cmDspSysConnectAudio(h, wt0, "out", lmix, "in-1" ); // wave table -> audio out (dry output) + //cmDspSysConnectAudio(h, wt1, "out", rmix, "in-1" ); // + + + cmDspSysConnectAudio( h, wt0, "out", mi0p, "in" ); // + cmDspSysConnectAudio( h, wt0, "out", c0.kr0, "in" ); // ain -> ch0.kr0 + cmDspSysConnectAudio( h, wt0, "out", c0.kr1, "in" ); // ain -> ch0.kr1 - cmDspSysConnectAudio( h, c0.cmp,"out", ao2, "in" ); // ch0.cmp -> aout + cmDspSysConnectAudio( h, c0.cmp,"out", lmix, "in-1" ); // ch0.cmp -> aout cmDspSysConnectAudio( h, c0.cmp,"out", afop, "in0"); // ch0.cmp -> audio_file_out - //cmDspSysConnectAudio( h, ai1, "out", mi1p, "in" ); // - //cmDspSysConnectAudio( h, ai1, "out", c1.kr0, "in" ); // ain -> ch1.kr0 - //cmDspSysConnectAudio( h, ai1, "out", c1.kr1, "in" ); // ain -> ch1.kr1 - cmDspSysConnectAudio( h, wtp, "out", mi1p, "in" ); // - cmDspSysConnectAudio( h, wtp, "out", c1.kr0, "in" ); // ain -> ch1.kr0 - cmDspSysConnectAudio( h, wtp, "out", c1.kr1, "in" ); // ain -> ch1.kr1 + cmDspSysConnectAudio( h, wt1, "out", mi1p, "in" ); // + cmDspSysConnectAudio( h, wt1, "out", c1.kr0, "in" ); // ain -> ch1.kr0 + cmDspSysConnectAudio( h, wt1, "out", c1.kr1, "in" ); // ain -> ch1.kr1 - cmDspSysConnectAudio( h, c1.cmp,"out", ao3, "in" ); // ch1.cmp -> aout + cmDspSysConnectAudio( h, c1.cmp,"out", rmix, "in-1" ); // ch1.cmp -> aout cmDspSysConnectAudio( h, c1.cmp,"out", afop, "in1"); // ch1.cmp ->audio_file_out + cmDspSysConnectAudio( h, lmix, "out", ao0, "in" ); + cmDspSysConnectAudio( h, rmix, "out", ao1, "in" ); cmDspSysInstallCb( h, clrBtn, "sym", amp, "cmd", NULL ); // clear active meas. @@ -252,8 +256,9 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb( h, sfp, "vcost",prt, "in", NULL ); // cmDspSysInstallCb( h, sfp, "vtyp", prc, "in", NULL ); // */ + // wave-table to time-line cursor - //cmDspSysInstallCb( h, wtp, "fidx",tlp, "curs", NULL); + cmDspSysInstallCb( h, wt0, "fidx",tlp, "curs", NULL); cmDspSysInstallCb(h, prePath, "out", tlp, "path", NULL ); @@ -267,7 +272,8 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, mfpRt,"s-out-0",mfp, "sel", NULL ); cmDspSysInstallCb(h, onb, "sym", pts, "on", NULL ); - cmDspSysInstallCb(h, pts, "on", wtp, "cmd", NULL ); + cmDspSysInstallCb(h, pts, "on", wt0, "cmd", NULL ); + cmDspSysInstallCb(h, pts, "on", wt1, "cmd", NULL ); cmDspSysInstallCb(h, pts, "on", modp, "cmd", NULL ); cmDspSysInstallCb(h, onb, "sym", amCmd, "rewind", NULL ); cmDspSysInstallCb(h, onb, "out", c0.achan,"reset", NULL ); @@ -278,11 +284,10 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) // stop connections cmDspSysInstallCb(h, tlp, "mfn", pts, "off", NULL ); // Prevents WT start on new audio file from TL. cmDspSysInstallCb(h, offb, "sym", mfp, "sel", NULL ); - cmDspSysInstallCb(h, offb, "sym", pts, "off", NULL ); - cmDspSysInstallCb(h, pts, "off", wtp, "cmd", NULL ); + cmDspSysInstallCb(h, offb, "sym", pts, "off", NULL ); + cmDspSysInstallCb(h, pts, "off", wt0, "cmd", NULL ); + cmDspSysInstallCb(h, pts, "off", wt1, "cmd", NULL ); cmDspSysInstallCb(h, pts, "off", modp,"cmd", NULL ); - cmDspSysInstallCb(h, offb, "sym", mop, "reset", NULL ); - cmDspSysInstallCb(h, offb, "sym", mo2p,"reset", NULL ); // time-line to MIDI file player selection @@ -292,9 +297,13 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) // time-line to Audio file player selection - cmDspSysInstallCb(h, tlp, "absi", wtp, "beg", NULL ); - cmDspSysInstallCb(h, tlp, "aesi", wtp, "end", NULL ); - cmDspSysInstallCb(h, tlp, "afn", wtp, "fn", NULL ); + cmDspSysInstallCb(h, tlp, "absi", wt0, "beg", NULL ); + cmDspSysInstallCb(h, tlp, "aesi", wt0, "end", NULL ); + cmDspSysInstallCb(h, tlp, "afn", wt0, "fn", NULL ); + + cmDspSysInstallCb(h, tlp, "absi", wt1, "beg", NULL ); + cmDspSysInstallCb(h, tlp, "aesi", wt1, "end", NULL ); + cmDspSysInstallCb(h, tlp, "afn", wt1, "fn", NULL ); // score to score follower - to set initial search location cmDspSysInstallCb(h, scp, "sel", sfp, "index", NULL ); @@ -309,41 +318,46 @@ cmDspRC_t _cmDspSysPgm_TimeLineLiteAf(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, msrc, "d1", sfp, "d1", NULL ); cmDspSysInstallCb(h, msrc, "d1", nmp, "d1", NULL ); - cmDspSysInstallCb(h, nmp, "d1", mop, "d1", NULL ); - //cmDspSysInstallCb(h, nmp, "d1", pic, "d1", NULL ); - //cmDspSysInstallCb(h, pic, "d1", mo2p, "d1", NULL ); cmDspSysInstallCb(h, msrc, "d0", sfp, "d0", NULL ); cmDspSysInstallCb(h, msrc, "d0", nmp, "d0", NULL ); - cmDspSysInstallCb(h, nmp, "d0", mop, "d0", NULL ); - //cmDspSysInstallCb(h, nmp, "d0", pic, "d0", NULL ); - //cmDspSysInstallCb(h, pic, "d0", mo2p, "d0", NULL ); cmDspSysInstallCb(h, msrc, "status", sfp, "status",NULL ); cmDspSysInstallCb(h, msrc, "status", nmp, "status",NULL ); - cmDspSysInstallCb(h, nmp, "status", mop, "status",NULL ); - //cmDspSysInstallCb(h, nmp, "status", pic, "status",NULL ); - //cmDspSysInstallCb(h, pic, "status", mo2p, "status", NULL ); // score follower to recd_play,modulator and printers cmDspSysInstallCb(h, sfp, "out", modp, "index", NULL ); - cmDspSysInstallCb(h, sfp, "recent", prp, "in", NULL ); // report 'recent' but only act on 'max' loc index + cmDspSysInstallCb(h, sfp, "recent", sfp_loc, "in", NULL ); // report 'recent' but only act on 'max' loc index - //cmDspSysInstallCb(h, igain0, "val", ai0, "gain", NULL ); // input gain control - //cmDspSysInstallCb(h, igain1, "val", ai1, "gain", NULL ); + cmDspSysInstallCb( h, eloc , "val", its, "off-int", NULL); + cmDspSysInstallCb( h, sfp, "out", its, "in", NULL); + cmDspSysInstallCb( h, its, "out", offb, "in", NULL); + cmDspSysInstallCb( h, its, "out", prp, "in", NULL); + - - cmDspSysInstallCb(h, modp, "dgain0", ogain0, "val", NULL ); + cmDspSysInstallCb(h, modp, "dgain0", ogain0, "val", NULL ); // mod -> ogain cmDspSysInstallCb(h, modp, "dgain1", ogain1, "val", NULL ); cmDspSysInstallCb(h, modp, "wgain0", ogain2, "val", NULL ); cmDspSysInstallCb(h, modp, "wgain1", ogain3, "val", NULL ); - cmDspSysInstallCb(h, ogain0, "val", ao0, "gain", NULL ); // output gain control - dry 0 - cmDspSysInstallCb(h, ogain1, "val", ao1, "gain", NULL ); // dry 1 - cmDspSysInstallCb(h, ogain2, "val", ao2, "gain", NULL ); // wet 0 - cmDspSysInstallCb(h, ogain3, "val", ao3, "gain", NULL ); // wet 1 + cmDspSysInstallCb(h, ogain0, "val", gmult0, "in-0", NULL ); // ogain scalars -> gmult 0 + cmDspSysInstallCb(h, ogain1, "val", gmult1, "in-0", NULL ); + cmDspSysInstallCb(h, ogain2, "val", gmult2, "in-0", NULL ); + cmDspSysInstallCb(h, ogain3, "val", gmult3, "in-0", NULL ); + + cmDspSysInstallCb(h, ogainD, "val", gmult0, "in-1", NULL ); // master scalars -> gmult 1 + cmDspSysInstallCb(h, ogainD, "val", gmult1, "in-1", NULL ); + cmDspSysInstallCb(h, ogainW, "val", gmult2, "in-1", NULL ); + cmDspSysInstallCb(h, ogainW, "val", gmult3, "in-1", NULL ); + + cmDspSysInstallCb(h, gmult0, "out", lmix, "gain-0", NULL ); // gmult -> wdmix - l dry + cmDspSysInstallCb(h, gmult1, "out", rmix, "gain-0", NULL ); // r dry + cmDspSysInstallCb(h, gmult2, "out", lmix, "gain-1", NULL ); // l wet + cmDspSysInstallCb(h, gmult3, "out", rmix, "gain-1", NULL ); // r wet + + //cmDspSysInstallCb(h, gmult2, "out", prp, "in", NULL ); return rc; } diff --git a/src/dsp/cmDspSys.h b/src/dsp/cmDspSys.h index 28fef38..5d78501 100644 --- a/src/dsp/cmDspSys.h +++ b/src/dsp/cmDspSys.h @@ -109,8 +109,7 @@ extern "C" { cmDspRC_t cmDspSysInsertHorzBorder( cmDspSysH_t h ); cmDspRC_t cmDspSysNewPage( cmDspSysH_t h, const cmChar_t* title ); - - + //---------------------------------------------------------------------------------------------------- // Connection Functions. // @@ -278,6 +277,18 @@ extern "C" { //) + typedef cmDspInst_t inst_t; + +#define inst( classLabel, instLabel, ... ) cmDspSysAllocInst( h, classLabel, instLabel, PP_NARG(__VA_ARGS__), __VA_ARGS__ ) +#define button( label, real_val ) cmDspSysAllocButton( h, label, real_val ) +#define scalar( label, rmin, rmax, rstep, rval ) cmDspSysAllocScalar( h, label, rmin, rmax, rstep, rval ) + + +#define audio( src, sarg, dst, darg ) cmDspSysConnectAudio( h, src, #sarg, dst, #darg ) +#define event( src, sarg, dst, darg ) cmDspSysInstallCb( h, src, #sarg, dst, #darg, NULL ) + + + #ifdef __cplusplus } #endif diff --git a/src/dsp/cmDspUi.c b/src/dsp/cmDspUi.c index 2aff36c..4ae728f 100644 --- a/src/dsp/cmDspUi.c +++ b/src/dsp/cmDspUi.c @@ -188,6 +188,9 @@ cmDspRC_t _cmDspUiUseInstSymbolAsLabel( cmDspCtx_t* ctx, cmDspInst_t* inst, unsi cmDspRC_t cmDspSendValueToAudioSys( cmDspCtx_t* ctx, unsigned msgTypeId, unsigned selId, unsigned valId, const cmDspValue_t* valPtr ) { return _cmDspUiMsg(ctx, msgTypeId, selId, 0, NULL, valId, valPtr ); } +cmDspRC_t cmDspProgramIsDone( cmDspCtx_t* ctx ) +{ return _cmDspUiMsg(ctx, kUiSelAsId, kPgmDoneDuiId, 0, NULL, cmInvalidId, NULL ); } + cmDspRC_t cmDspUiConsolePrint( cmDspCtx_t* ctx, cmChar_t* text ) { cmDspValue_t v; @@ -514,3 +517,4 @@ cmDspRC_t cmDspUiNewPage( cmDspCtx_t* ctx, const cmChar_t* title ) return rc; } + diff --git a/src/dsp/cmDspValue.c b/src/dsp/cmDspValue.c index 1f5fc30..8a97b32 100644 --- a/src/dsp/cmDspValue.c +++ b/src/dsp/cmDspValue.c @@ -1527,3 +1527,76 @@ void cmDsvPrint( const cmDspValue_t* vp, const cmChar_t* label, cmRpt_t* rpt ) } } } + +void cmDsvToString( const cmDspValue_t* vp, const cmChar_t* label, cmChar_t* s, unsigned sN ) +{ + vp = _vcptr(vp); + + const char* noLbl=""; + const char* lbl = label==NULL? noLbl : label; + + if( cmDsvIsMtx(vp) ) + { + unsigned i,j; + unsigned rn = cmDsvCols(vp); + unsigned cn = cmDsvRows(vp); + for(i=0; i2; ++j) + { + switch( cmDsvBasicType(vp) ) + { + case kCharDsvFl: snprintf(s,sN,"%s%c ",lbl,vp->u.m.u.cp[ (j*rn) + i ]); break; + case kUCharDsvFl: snprintf(s,sN,"%s%c ",lbl,vp->u.m.u.ucp[ (j*rn) + i ]); break; + case kShortDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.m.u.sp[ (j*rn) + i ]); break; + case kUShortDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.m.u.usp[ (j*rn) + i ]); break; + case kLongDsvFl: snprintf(s,sN,"%s%li ",lbl,vp->u.m.u.lp[ (j*rn) + i ]); break; + case kULongDsvFl: snprintf(s,sN,"%s%li ",lbl,vp->u.m.u.ulp[ (j*rn) + i ]); break; + case kIntDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.m.u.ip[ (j*rn) + i ]); break; + case kUIntDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.m.u.up[ (j*rn) + i ]); break; + case kFloatDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.m.u.fp[ (j*rn) + i ]); break; + case kDoubleDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.m.u.dp[ (j*rn) + i ]); break; + case kSampleDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.m.u.ap[ (j*rn) + i ]); break; + case kRealDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.m.u.rp[ (j*rn) + i ]); break; + case kStrzDsvFl: snprintf(s,sN,"%s%s ",lbl,vp->u.m.u.zp[ (j*rn) + i ]); break; + case kJsonDsvFl: cmJsonLeafToString(vp->u.m.u.jp[ (j*rn) + i ],s,sN); break; + default: + { assert(0); } + } + + unsigned n = strlen(s); + sN -= n; + s += n; + + + } + if( sN > 2 ) + snprintf(s,sN,"\n"); + } + } + else + { + switch( cmDsvBasicType(vp) ) + { + case kBoolDsvFl: snprintf(s,sN,"%s%s ",lbl,vp->u.b ? "true" : "false"); break; + case kCharDsvFl: snprintf(s,sN,"%s%c ",lbl,vp->u.c); break; + case kUCharDsvFl: snprintf(s,sN,"%s%c ",lbl,vp->u.uc); break; + case kShortDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.s); break; + case kUShortDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.us); break; + case kLongDsvFl: snprintf(s,sN,"%s%li ",lbl,vp->u.l); break; + case kULongDsvFl: snprintf(s,sN,"%s%li ",lbl,vp->u.ul); break; + case kIntDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.i); break; + case kUIntDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.u); break; + case kFloatDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.f); break; + case kDoubleDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.d); break; + case kSampleDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.a); break; + case kRealDsvFl: snprintf(s,sN,"%s%f ",lbl,vp->u.r); break; + case kPtrDsvFl: snprintf(s,sN,"%s%p ",lbl,vp->u.vp); break; + case kStrzDsvFl: snprintf(s,sN,"%s%s ",lbl,vp->u.z); break; + case kSymDsvFl: snprintf(s,sN,"%s%i ",lbl,vp->u.u); break; + case kJsonDsvFl: cmJsonLeafToString(vp->u.j,s,sN); break; + default: + { assert(0); } + } + } +} diff --git a/src/dsp/cmDspValue.h b/src/dsp/cmDspValue.h index dee73fd..4181339 100644 --- a/src/dsp/cmDspValue.h +++ b/src/dsp/cmDspValue.h @@ -331,6 +331,7 @@ extern "C" { cmDsvRC_t cmDsvDeserializeJson( cmDspValue_t* vp, cmJsonH_t jsH ); void cmDsvPrint( const cmDspValue_t* vp, const cmChar_t* label, cmRpt_t* rpt ); + void cmDsvToString( const cmDspValue_t* vp, const cmChar_t* label, cmChar_t* s, unsigned sN ); //)