Merge branch 'master' of klarke.webfactional.com:webapps/git/repos/libcm with

spat lab mac.
This commit is contained in:
kevin 2013-11-19 11:15:12 -08:00
commit c946234fde
17 changed files with 3319 additions and 1438 deletions

View File

@ -6,6 +6,7 @@
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmLinkedHeap.h"
#include "cmMidi.h"
#include "cmLex.h"
#include "cmCsv.h"
@ -13,6 +14,7 @@
#include "cmMidiFile.h"
#include "cmAudioFile.h"
#include "cmTimeLine.h"
#include "cmText.h"
#include "cmScore.h"
#include "cmVectOpsTemplateMain.h"
@ -41,7 +43,8 @@ enum
kFracColScIdx = 18,
kDynColScIdx = 19,
kSectionColScIdx = 20,
kRemarkColScIdx = 21
kRecdPlayColScIdx = 21,
kRemarkColScIdx = 22
};
@ -75,6 +78,15 @@ typedef struct cmScSet_str
struct cmScSet_str* link; //
} cmScSet_t;
typedef struct cmScMark_str
{
cmMarkScMId_t cmdId;
unsigned labelSymId;
unsigned scoreIdx;
unsigned csvRowIdx;
struct cmScMark_str* link;
} cmScMark_t;
typedef struct
{
cmErr_t err;
@ -94,11 +106,15 @@ typedef struct
cmScoreSection_t* sect;
unsigned sectCnt;
unsigned* markLabelArray; // one symId per unique cmScoreMarker_t.labelSymId;
unsigned markLabelCnt;
unsigned sciPitchLexTId; // sci pitch and section id lexer token id's
unsigned sectionLexTId;
cmScSect_t* sectList; // lists used during parsing
cmScSet_t* setList;
cmScMark_t* markList;
cmScoreSet_t* sets;
unsigned setCnt;
@ -313,6 +329,17 @@ unsigned _cmScLexSectionIdMatcher( const cmChar_t* cp, unsigned cn )
return 0;
}
void _cmScFreeMarkList( cmScMark_t* markList )
{
cmScMark_t* mp = markList;
while( mp!=NULL )
{
cmScMark_t* np = mp->link;
cmMemFree(mp);
mp = np;
}
}
void _cmScFreeSetList( cmScSet_t* setList )
{
cmScSet_t* tp = setList;
@ -366,6 +393,8 @@ cmScRC_t _cmScFinalize( cmSc_t* p )
_cmScFreeSetList(p->setList);
_cmScFreeMarkList(p->markList);
if( p->loc != NULL )
{
for(i=0; i<p->locCnt; ++i)
@ -373,12 +402,23 @@ cmScRC_t _cmScFinalize( cmSc_t* p )
cmMemFree(p->loc[i].evtArray);
if( p->loc[i].begSectPtr != NULL )
cmMemFree(p->loc[i].begSectPtr->setArray);
// free the marker list assoc'd with this location
cmScoreMarker_t* smp = p->loc[i].markList;
while( smp!=NULL )
{
cmScoreMarker_t* np = smp->link;
cmMemFree(smp);
smp = np;
}
}
cmMemFree(p->loc);
}
cmMemPtrFree(&p->dynRefArray);
cmMemPtrFree(&p->dynRefArray);
cmMemFree(p->markLabelArray);
cmMemFree(p->sect);
cmMemFree(p->fn);
cmMemFree(p->array);
@ -557,6 +597,79 @@ cmScRC_t _cmScParseAttr(cmSc_t* p, unsigned scoreIdx, const cmChar_t* text, unsi
return kOkScRC;
}
// Parse a record/playback string
cmScRC_t _cmScParseMarkers( cmSc_t* p, unsigned scoreIdx, const cmChar_t* text, unsigned rowIdx )
{
const cmChar_t* cp = text;
const cmChar_t* ip;
const cmChar_t* ep;
// if no symbol table has been registered then don't bother storing markers.
// (NOTE - THIS IS A HACK BECAUSE THE SCORE OBJECT USED IN THE cmdIf DOES NOT HAVE
// A SYMBOL TABLE - WE COULD EASILY ADD ONE IF IT EVENTUALLY NEEDS ACCESS TO THE MARKERS
// - OR A SYMBOL TABLE COULD BE ADDED TO THE SCORE ITSELF.)
if( cmSymTblIsValid(p->stH) == false )
return kOkScRC;
// go to command/id space
if((ip = cmTextNextWhiteOrEosC(text)) == NULL )
goto errLabel;
// goto label
if((ip = cmTextNextNonWhiteC(ip)) == NULL )
goto errLabel;
// goto end of label
if((ep = cmTextNextWhiteOrEosC(ip)) == NULL )
goto errLabel;
else
{
unsigned n = (ep-ip)+1;
cmChar_t markTextStr[n+1];
strncpy(markTextStr,ip,n);
// for each command code
// (there may be more than one character)
for(; *cp && !isspace(*cp); ++cp)
{
cmMarkScMId_t cmdId = kInvalidScMId;
switch( *cp )
{
case 'c': cmdId = kRecdBegScMId; break;
case 'e': cmdId = kRecdEndScMId; break;
case 'p': cmdId = kPlayBegScMId; break;
case 'd': cmdId = kPlayEndScMId; break;
case 'f': cmdId = kFadeScMId; break;
default:
return cmErrMsg(&p->err,kSyntaxErrScRC,"Unrecognized marker command character '%c' at row index %i.",*cp,rowIdx);
}
cmScMark_t* mp = cmMemAllocZ(cmScMark_t,1);
mp->cmdId = cmdId;
mp->labelSymId = cmSymTblRegisterSymbol(p->stH,markTextStr);
mp->scoreIdx = scoreIdx;
mp->csvRowIdx = rowIdx;
// insert the new mark at the end of the list
if( p->markList == NULL )
p->markList = mp;
else
{
cmScMark_t* ep = p->markList;
while( ep->link != NULL )
ep = ep->link;
ep->link = mp;
}
}
}
return kOkScRC;
errLabel:
return cmErrMsg(&p->err,kSyntaxErrScRC,"Invalid record/playback field ('%s') on row index:%i.",cmStringNullGuard(text),rowIdx);
}
void _cmScPrintSets( const cmChar_t* label, cmScSet_t* setList )
{
printf("%s\n",label);
@ -598,7 +711,7 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned
return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch)
return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
// it is possible that note delta-secs field is empty - so default to 0
if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
@ -658,6 +771,14 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned
durSecs = 0.25;
// parse the recd/play markers
if((attr = cmCsvCellText(p->cH,rowIdx,kRecdPlayColScIdx)) != NULL )
{
if((rc = _cmScParseMarkers(p,scoreIdx,attr,rowIdx)) != kOkScRC )
return rc;
}
s->type = kNonEvtScId;
s->secs = secs;
s->pitch = midiPitch;
@ -870,6 +991,8 @@ cmScRC_t _cmScProcSets( cmSc_t* p )
}
cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList )
{
cmScRC_t rc = kOkScRC;
@ -935,6 +1058,153 @@ cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList )
return rc;
}
const cmScoreLoc_t* _cmScFindMarkLoc( cmSc_t* p, cmMarkScMId_t cmdId, unsigned labelSymId, const cmScoreMarker_t** markRef )
{
unsigned i;
for(i=0; i<p->locCnt; ++i)
{
cmScoreMarker_t* smp = p->loc[i].markList;
for(; smp!=NULL; smp=smp->link)
{
if( smp->markTypeId==cmdId && smp->labelSymId==labelSymId )
return p->loc + i;
if( markRef != NULL )
*markRef = smp;
}
}
return NULL;
}
unsigned _cmScMarkerLabelIndex( cmSc_t* p, unsigned labelSymId )
{
unsigned i;
for(i=0; i<p->markLabelCnt; ++i)
if( p->markLabelArray[i] == labelSymId )
return i;
return cmInvalidIdx;
}
// Verify that the record/play begin/end and fade markers fall in the correct time order.
// (e.g. 'begin' must be before 'end' and 'fade' must be between and 'begin' and 'end').
cmScRC_t _cmScValidateMarkers( cmSc_t* p )
{
cmScRC_t rc = kOkScRC;
unsigned i;
for(i=0; i<p->locCnt; ++i)
{
cmScoreMarker_t* sm0p = p->loc[i].markList;
for(; sm0p!=NULL; sm0p=sm0p->link)
{
const cmScoreLoc_t* sl0p;
const cmScoreLoc_t* sl1p;
switch( sm0p->markTypeId )
{
case kRecdBegScMId:
if((sl0p = _cmScFindMarkLoc(p,kRecdEndScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record begin' marker at CSV row index %i does not have an associated 'record end' marker.",sm0p->csvRowIdx);
else
if( sl0p->index <= p->loc[i].index )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record end' marker comes before associated with the 'record begin' marker at CSV row index %i.",sm0p->csvRowIdx);
break;
case kRecdEndScMId:
if((sl0p = _cmScFindMarkLoc(p,kRecdBegScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record end' marker at CSV row index %i does not have an associated 'record begin' marker.",sm0p->csvRowIdx);
else
if( sl0p->index > p->loc[i].index )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record begin' marker comes after the associated with the 'record end' marker at CSV row index %i.",sm0p->csvRowIdx);
break;
case kFadeScMId:
if((sl0p = _cmScFindMarkLoc(p,kRecdBegScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i does not have an associated 'record begin' marker.",sm0p->csvRowIdx);
else
if((sl1p = _cmScFindMarkLoc(p,kRecdEndScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i does not have an associated 'record end' marker.",sm0p->csvRowIdx);
else
if( sl0p->index > p->loc[i].index || sl1p->index < p->loc[i].index )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i is not between it's associated 'record begin' and 'record end' markers.",sm0p->csvRowIdx);
break;
case kPlayBegScMId:
if((sl0p = _cmScFindMarkLoc(p,kPlayEndScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play begin' marker at CSV row index %i does not have an associated 'play end' marker.",sm0p->csvRowIdx);
else
if( sl0p->index <= p->loc[i].index )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play end' marker comes before associated with the 'play begin' marker at CSV row index %i.",sm0p->csvRowIdx);
break;
case kPlayEndScMId:
if((sl0p = _cmScFindMarkLoc(p,kPlayBegScMId, sm0p->labelSymId, NULL )) == NULL )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play end' marker at CSV row index %i does not have an associated 'play begin' marker.",sm0p->csvRowIdx);
else
if( sl0p->index > p->loc[i].index )
rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play begin' marker comes after the associated with the 'play end' marker at CSV row index %i.",sm0p->csvRowIdx);
break;
default:
break;
}
}
}
return rc;
}
cmScRC_t _cmScProcMarkers( cmSc_t* p )
{
// for each marker in the p->markList
// (p->markList is created by _cmScParseMarkers() during CSV file parsing.)
cmScMark_t* mp = p->markList;
for(; mp!=NULL; mp=mp->link)
{
assert( mp->scoreIdx < p->cnt );
// get the score location assoc'd with this marker
unsigned locIdx = p->array[ mp->scoreIdx ].locIdx;
assert( locIdx < p->locCnt );
cmScoreLoc_t* slp = p->loc + locIdx;
// create a cmScoreMarker record.
cmScoreMarker_t* smp = cmMemAllocZ(cmScoreMarker_t,1);
smp->markTypeId = mp->cmdId;
smp->labelSymId = mp->labelSymId;
smp->csvRowIdx = mp->csvRowIdx;
smp->scoreLocPtr = slp;
// attach the new scoreMarker record to the assoc'd score loc. recd
if( slp->markList == NULL )
slp->markList = smp;
else
{
cmScoreMarker_t* sm0p = slp->markList;
while( sm0p->link != NULL )
sm0p = sm0p->link;
sm0p->link = smp;
}
// if the id represented by this marker
if( _cmScMarkerLabelIndex(p,smp->labelSymId) == cmInvalidIdx )
{
p->markLabelArray = cmMemResizeP(unsigned,p->markLabelArray,p->markLabelCnt+1);
p->markLabelArray[p->markLabelCnt] = smp->labelSymId;
p->markLabelCnt += 1;
}
}
// validate the markers
return _cmScValidateMarkers(p);
}
cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
{
cmScRC_t rc = kOkScRC;
@ -1036,27 +1306,30 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
break;
}
if( secs != DBL_MAX )
cur_secs = secs;
// form the section list
if( j > 0 )
if((rc = _cmScParseSectionColumn(p,i,j-1,p->sectList)) != kOkScRC )
break;
// the bar lines don't have times so set the time of the bar line to the
// time of the first event in the bar.
if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
if( rc == kOkScRC )
{
assert( p->array[ barEvtIdx ].type == kBarEvtScId );
p->array[ barEvtIdx ].secs = secs;
if( secs != DBL_MAX )
cur_secs = secs;
// handle the case where the previous bar had no events
// BUG BUG BUG this is a hack which will fail if the first bar does not have events.
if( barEvtIdx>=1 && p->array[ barEvtIdx-1].type == kBarEvtScId )
p->array[ barEvtIdx-1].secs = secs;
// form the section list
if( j > 0 )
if((rc = _cmScParseSectionColumn(p,i,j-1,p->sectList)) != kOkScRC )
break;
barEvtIdx = cmInvalidIdx;
// the bar lines don't have times so set the time of the bar line to the
// time of the first event in the bar.
if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
{
assert( p->array[ barEvtIdx ].type == kBarEvtScId );
p->array[ barEvtIdx ].secs = secs;
// handle the case where the previous bar had no events
// BUG BUG BUG this is a hack which will fail if the first bar does not have events.
if( barEvtIdx>=1 && p->array[ barEvtIdx-1].type == kBarEvtScId )
p->array[ barEvtIdx-1].secs = secs;
barEvtIdx = cmInvalidIdx;
}
}
}
@ -1164,6 +1437,9 @@ cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, doubl
if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC )
goto errLabel;
if((rc = _cmScProcMarkers(p)) != kOkScRC )
goto errLabel;
// load the dynamic reference array
if( dynRefArray != NULL && dynRefCnt > 0)
{
@ -1409,6 +1685,30 @@ unsigned cmScoreSetCount( cmScH_t h )
return p->setCnt;
}
unsigned cmScoreMarkerLabelCount( cmScH_t h )
{
cmSc_t* p = _cmScHandleToPtr(h);
return p->markLabelCnt;
}
unsigned cmScoreMarkerLabelSymbolId( cmScH_t h, unsigned idx )
{
cmSc_t* p = _cmScHandleToPtr(h);
assert( idx < p->markLabelCnt );
return p->markLabelArray[idx];
}
const cmScoreMarker_t* cmScoreMarker( cmScH_t h, cmMarkScMId_t markMId, unsigned labelSymId )
{
cmSc_t* p = _cmScHandleToPtr(h);
const cmScoreMarker_t* smp = NULL;
if( _cmScFindMarkLoc(p, markMId, labelSymId, &smp ) == NULL )
return NULL;
return smp;
}
cmScRC_t cmScoreSeqNotify( cmScH_t h )
{
cmScRC_t rc = kOkScRC;
@ -1502,7 +1802,7 @@ void _cmScPerfSortTimes( unsigned *v, unsigned n )
fl = true;
}
}
--n;
--n;
}
}
@ -1568,13 +1868,13 @@ bool _cmScPerfEven(cmSc_t* p, cmScoreSet_t* stp, bool printMissFl)
if(printFl)
{
/*
for(i=0; i<stp->eleCnt; ++i)
{
for(i=0; i<stp->eleCnt; ++i)
{
printf("%i %i ",i,v[i]);
if( i > 0 )
printf("%i ", d[i-1]);
printf("%i ", d[i-1]);
printf("\n");
}
}
*/
printf("%s EVENESS:%f\n",sortFl?"SORTED ":"",stp->value);
}
@ -1955,6 +2255,214 @@ void cmScorePrint( cmScH_t h, cmRpt_t* rpt )
}
}
cmScRC_t cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn )
{
cmScRC_t rc = kOkScRC;
cmMidiFileH_t mfH = cmMidiFileNullHandle;
cmCsvH_t csvH = cmCsvNullHandle;
cmErr_t err;
cmChar_t* titles[] = {"id","trk","evt","opcode","dticks","micros","status","meta","ch","d0","d1","arg0","arg1","bar","skip","even","grace","tempo","t frac","dyn","section","remark", NULL };
cmErrSetup(&err,&ctx->rpt,"MIDI to Score");
if( cmMidiFileOpen(midiFn, &mfH, ctx ) != kOkMfRC )
return cmErrMsg(&err,kMidiFileFailScRC,"Unable to open the MIDI file '%s'.",midiFn);
if( cmCsvInitialize(&csvH,ctx) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Unable to initialize the CSV file: '%s'.",scoreFn);
goto errLabel;
}
// Convert the track message 'dtick' field to delta-microseconds.
cmMidiFileTickToMicros(mfH);
unsigned msgCnt = cmMidiFileMsgCount(mfH);
unsigned i;
const cmMidiTrackMsg_t** tmpp = cmMidiFileMsgArray(mfH);
double acc_secs = 0;
unsigned lexTId = 0;
cmCsvCell_t* cp = NULL;
if( cmCsvAppendRow(csvH, &cp, cmCsvInsertSymText(csvH,titles[0]), kStrCsvTFl, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'id' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
for(i=1; titles[i]!=NULL; ++i)
{
if( cmCsvInsertTextColAfter(csvH, cp, &cp, titles[i], lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting column index '%i' label in '%s'.",i,cmStringNullGuard(scoreFn));
goto errLabel;
}
}
for(i=0; i<msgCnt; ++i)
{
const cmMidiTrackMsg_t* tmp = tmpp[i];
const cmChar_t* opStr = NULL;
unsigned midiCh = 0;
unsigned d0 = 0;
unsigned d1 = 0;
unsigned metaId = 0;
double dsecs = (double)tmp->dtick / 1000000.0;
acc_secs += dsecs;
if( tmp->status == kMetaStId )
{
opStr = cmMidiMetaStatusToLabel(tmp->metaId);
metaId = tmp->metaId;
switch( tmp->metaId )
{
case kTempoMdId:
d0 = tmp->u.iVal;
}
}
else
{
opStr = cmMidiStatusToLabel(tmp->status);
if( cmMidiIsChStatus( tmp->status ) )
{
midiCh = tmp->u.chMsgPtr->ch;
d0 = tmp->u.chMsgPtr->d0;
d1 = tmp->u.chMsgPtr->d1;
}
}
cp = NULL;
// skip note-off messages
if( tmp->status == kNoteOffMdId )
continue;
if( cmCsvAppendRow(csvH, &cp, cmCsvInsertSymUInt(csvH,i), kIntCsvTFl, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'id' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->trkIdx, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'trk' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, 0, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'evt' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertTextColAfter(csvH, cp, &cp, opStr, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'opcode' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertDoubleColAfter(csvH, cp, &cp, dsecs, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'dticks' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertDoubleColAfter(csvH, cp, &cp, acc_secs, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'micros' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertHexColAfter(csvH, cp, &cp, tmp->status, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'status' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, metaId, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'meta' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, midiCh, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'ch' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, d0, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'd0' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, d1, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'd1' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
switch( tmp->status )
{
case kNoteOnMdId:
if( cmCsvInsertTextColAfter(csvH, cp, &cp, cmMidiToSciPitch(tmp->u.chMsgPtr->d0,NULL,0), lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'opcode' column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
case kMetaStId:
switch( tmp->metaId )
{
case kTimeSigMdId:
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->u.timeSigPtr->num, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting time sign. numerator column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->u.timeSigPtr->den, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting time sign. denominator column in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
break;
case kTempoMdId:
if( cmCsvInsertUIntColAfter(csvH, cp, &cp, 60000000/tmp->u.iVal, lexTId ) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"Error inserting 'tempo' in '%s'.",cmStringNullGuard(scoreFn));
goto errLabel;
}
break;
}
}
}
if( cmCsvWrite(csvH,scoreFn) != kOkCsvRC )
{
cmErrMsg(&err,kCsvFailScRC,"The score output file '%s' could not be written.",cmStringNullGuard(scoreFn));
goto errLabel;
}
errLabel:
cmMidiFileClose(&mfH);
cmCsvFinalize(&csvH);
return rc;
}
void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
{
cmScH_t h = cmScNullHandle;

View File

@ -12,8 +12,8 @@ extern "C" {
kSyntaxErrScRC,
kInvalidIdxScRC,
kTimeLineFailScRC,
kInvalidDynRefCntScRC
kInvalidDynRefCntScRC,
kMidiFileFailScRC
};
enum
@ -36,12 +36,12 @@ extern "C" {
// Flags used by cmScoreEvt_t.flags
enum
{
kEvenScFl = 0x01, // This note is marked for evenness measurement
kDynScFl = 0x02, // This note is marked for dynamics measurement
kTempoScFl = 0x04, // This note is marked for tempo measurement
kSkipScFl = 0x08, // This isn't a real event (e.g. tied note) skip over it
kGraceScFl = 0x10, // This is a grace note
kInvalidScFl = 0x20 // This note has a calculated time
kEvenScFl = 0x001, // This note is marked for evenness measurement
kDynScFl = 0x002, // This note is marked for dynamics measurement
kTempoScFl = 0x004, // This note is marked for tempo measurement
kSkipScFl = 0x008, // This isn't a real event (e.g. tied note) skip over it
kGraceScFl = 0x010, // This is a grace note
kInvalidScFl = 0x020 // This note has a calculated time
};
@ -104,6 +104,25 @@ extern "C" {
struct cmScoreSet_str* llink; // cmScoreLoc_t setList link
} cmScoreSet_t;
typedef enum
{
kInvalidScMId,
kRecdBegScMId,
kRecdEndScMId,
kFadeScMId,
kPlayBegScMId,
kPlayEndScMId
} cmMarkScMId_t;
// score markers
typedef struct cmScoreMarker_str
{
cmMarkScMId_t markTypeId; // marker type
unsigned labelSymId; // marker label
struct cmScoreLoc_str* scoreLocPtr; // score location of the marker
unsigned csvRowIdx; // score CSV file line assoc'd w/ this marker
struct cmScoreMarker_str* link; // cmScoreLoc_t.markList links
} cmScoreMarker_t;
// All events which are simultaneous are collected into a single
// cmScoreLoc_t record.
@ -116,6 +135,7 @@ extern "C" {
unsigned barNumb; // Bar number this event is contained by.
cmScoreSet_t* setList; // Set's which end on this time location (linked through cmScoreSet_t.llink)
cmScoreSection_t* begSectPtr; // NULL if this location does not start a section
cmScoreMarker_t* markList; // List of markers assigned to this location
} cmScoreLoc_t;
typedef void (*cmScCb_t)( void* arg, const void* data, unsigned byteCnt );
@ -170,6 +190,10 @@ extern "C" {
// Return the count of sets.
unsigned cmScoreSetCount( cmScH_t h );
unsigned cmScoreMarkerLabelCount( cmScH_t h );
unsigned cmScoreMarkerLabelSymbolId( cmScH_t h, unsigned idx );
const cmScoreMarker_t* cmScoreMarker( cmScH_t h, cmMarkScMId_t markMId, unsigned labelSymId );
// Make callbacks for all events in the score. The callbacks
// contain cmScMsg_t records serialized as a byte stream.
// Use cmScoreDecode() to convert the byte string to a
@ -235,6 +259,9 @@ extern "C" {
void cmScorePrint( cmScH_t h, cmRpt_t* rpt );
// Generate a new score file from a MIDI file.
cmScRC_t cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn );
void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );

58
cmCsv.c
View File

@ -729,6 +729,20 @@ unsigned cmCsvInsertSymUInt( cmCsvH_t h, unsigned v )
return cmInvalidId;
}
unsigned cmCsvInsertSymHex( cmCsvH_t h, unsigned v )
{
const char* fmt = "0x%x";
unsigned n = snprintf(NULL,0,fmt,v)+1;
char buf[n];
buf[0]= 0;
if( snprintf(buf,n,fmt,v) == n-1 )
return cmCsvInsertSymText(h,buf);
_cmCsvError(_cmCsvHandleToPtr(h),kDataCvtErrCsvRC,"The unsigned int 0x%x could not be converted to text.",v);
return cmInvalidId;
}
unsigned cmCsvInsertSymFloat( cmCsvH_t h, float v )
{
const char* fmt = "%f";
@ -812,6 +826,24 @@ cmCsvRC_t cmCsvSetCellUInt( cmCsvH_t h, unsigned row, unsigned col, unsigned
return kOkCsvRC;
}
cmCsvRC_t cmCsvSetCellHex( cmCsvH_t h, unsigned row, unsigned col, unsigned v )
{
cmCsvCell_t* cp;
unsigned symId;
if((cp = _cmCsvCellPtr(h,row,col)) == NULL )
return cmErrLastRC(&_cmCsvHandleToPtr(h)->err);
if((symId = cmCsvInsertSymHex(h,v)) == cmInvalidId )
return cmErrLastRC(&_cmCsvHandleToPtr(h)->err);
cp->symId = symId;
cp->flags &= !kTypeTMask;
cp->flags |= kIntCsvTFl;
return kOkCsvRC;
}
cmCsvRC_t cmCsvSetCellFloat( cmCsvH_t h, unsigned row, unsigned col, float v )
{
cmCsvCell_t* cp;
@ -985,7 +1017,7 @@ cmCsvRC_t cmCsvInsertTextColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
cellPtrPtr = NULL;
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellText(h, ncp->row, ncp->col, text )) == kOkCsvRC )
@ -1001,7 +1033,7 @@ cmCsvRC_t cmCsvInsertIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
cellPtrPtr = NULL;
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellInt(h, ncp->row, ncp->col, val )) == kOkCsvRC )
@ -1017,7 +1049,7 @@ cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
cellPtrPtr = NULL;
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellUInt(h, ncp->row, ncp->col, val )) == kOkCsvRC )
@ -1027,13 +1059,29 @@ cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs
return rc;
}
cmCsvRC_t cmCsvInsertHexColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId )
{
cmCsvRC_t rc;
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellHex(h, ncp->row, ncp->col, val )) == kOkCsvRC )
if( cellPtrPtr != NULL )
*cellPtrPtr = ncp;
return rc;
}
cmCsvRC_t cmCsvInsertFloatColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, float val, unsigned lexTId )
{
cmCsvRC_t rc;
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
cellPtrPtr = NULL;
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellFloat(h, ncp->row, ncp->col, val )) == kOkCsvRC )
@ -1049,7 +1097,7 @@ cmCsvRC_t cmCsvInsertDoubleColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs
cmCsvCell_t* ncp;
if( cellPtrPtr != NULL )
cellPtrPtr = NULL;
*cellPtrPtr = NULL;
if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC )
if((rc = cmCsvSetCellDouble(h, ncp->row, ncp->col, val )) == kOkCsvRC )

View File

@ -109,13 +109,16 @@ extern "C" {
unsigned cmCsvInsertSymText( cmCsvH_t h, const char* text );
unsigned cmCsvInsertSymInt( cmCsvH_t h, int v );
unsigned cmCsvInsertSymUInt( cmCsvH_t h, unsigned v );
unsigned cmCsvInsertSymHex( cmCsvH_t h, unsigned v );
unsigned cmCsvInsertSymFloat( cmCsvH_t h, float v );
unsigned cmCsvInsertSymDouble( cmCsvH_t h, double v );
// Set the value associated with a cell.
cmCsvRC_t cmCsvSetCellText( cmCsvH_t h, unsigned row, unsigned col, const char* text );
cmCsvRC_t cmCsvSetCellInt( cmCsvH_t h, unsigned row, unsigned col, int v );
cmCsvRC_t cmCsvSetCellUInt( cmCsvH_t h, unsigned row, unsigned col, unsigned v );
cmCsvRC_t cmCsvSetCellHex( cmCsvH_t h, unsigned row, unsigned col, unsigned v );
cmCsvRC_t cmCsvSetCellFloat( cmCsvH_t h, unsigned row, unsigned col, float v );
cmCsvRC_t cmCsvSetCellDouble( cmCsvH_t h, unsigned row, unsigned col, double v );
@ -134,6 +137,7 @@ extern "C" {
cmCsvRC_t cmCsvInsertTextColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, const char* val, unsigned lexTId );
cmCsvRC_t cmCsvInsertIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, int val, unsigned lexTId );
cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId );
cmCsvRC_t cmCsvInsertHexColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId );
cmCsvRC_t cmCsvInsertFloatColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, float val, unsigned lexTId );
cmCsvRC_t cmCsvInsertDoubleColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, double val, unsigned lexTId );

2588
cmData.c

File diff suppressed because it is too large Load Diff

600
cmData.h
View File

@ -5,129 +5,6 @@
extern "C" {
#endif
enum
{
kOkDtRC = cmOkRC,
kCvtErrDtRC,
kVarArgErrDtRC,
kMissingFieldDtRC,
kEolDtRC
};
enum
{
kInvalidDtChar = 0xff,
kInvalidDtUChar = 0xff,
kInvalidDtShort = 0xffff,
kInvalidDtUShort = 0xffff,
kInvalidDtInt = 0xffffffff,
kInvalidDtUInt = 0xffffffff,
kInvalidDtLong = 0xffffffff,
kInvalidDtULong = 0xffffffff,
};
typedef enum
{
kInvalidDtId,
kMinValDtId,
kNullDtId = kMinValDtId,
kUCharDtId,
kCharDtId,
kUShortDtId,
kShortDtId,
kUIntDtId,
kIntDtId,
kULongDtId,
kLongDtId,
kFloatDtId,
kDoubleDtId,
kStrDtId,
kConstStrDtId,
kMaxValDtId = kConstStrDtId,
kMinPtrDtId,
kUCharPtrDtId = kMinPtrDtId, // cnt=array element count
kCharPtrDtId,
kUShortPtrDtId,
kShortPtrDtId,
kUIntPtrDtId,
kIntPtrDtId,
kULongPtrDtId,
kLongPtrDtId,
kFloatPtrDtId,
kDoublePtrDtId,
kVoidPtrDtId,
kMaxPtrDtId = kVoidPtrDtId,
kMinStructDtId,
kListDtId = kMinStructDtId, // children nodes are array elements, cnt=child count
kPairDtId, // key/value pairs, cnt=2, first child is key, second is value
kRecordDtId, // children nodes are pairs, cnt=pair count
kMaxStructDtId,
kOptArgDtFl = 0x80000000
} cmDataFmtId_t;
enum
{
kDynObjDtFl = 0x01, // object was dynamically allocated
kDynPtrDtFl = 0x02 // ptr array was dynamically allocated
};
typedef struct cmData_str
{
cmDataFmtId_t tid; // data format id
unsigned flags; //
struct cmData_str* parent; // this childs parent
struct cmData_str* sibling; // this childs left sibling
unsigned cnt; // array ele count
union
{
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
cmChar_t* z;
const cmChar_t* cz;
void* vp;
char* cp;
unsigned char* ucp;
short* sp;
unsigned short* usp;
int* ip;
unsigned int* uip;
long* lp;
unsigned long* ulp;
float* fp;
double* dp;
struct cmData_str* child; // first child (array,record,pair)
} u;
} cmData_t;
typedef unsigned cmDtRC_t;
extern cmData_t cmDataNull;
bool cmDataIsValue( const cmData_t* p );
bool cmDataIsPtr( const cmData_t* p );
bool cmDataIsStruct( const cmData_t* p ); // is a pair,list or record
/*
TODO:
0) Figure out a error handling scheme that does not rely on
@ -144,7 +21,7 @@ extern "C" {
the array space. This will allow dynamic allocattion to
occur at runtime. Make var args functions for list and
record objects which also take this flag.
Where ever a function may be implemented using
Whereever a function may be implemented using
static/dynamic allocation this flag should be present.
(e.g. string allocation for pair labels)
This choice is common enough that it may be worth
@ -170,40 +47,227 @@ extern "C" {
*/
bool canConvertType( cmDataFmtId_t srcId, cmDataFmtId_t dstId );
bool willTruncate( cmDataFmtId_t srcId, cmDataFmtId_t dstId );
bool canConvertObj( const cmData_t* srcObj, cmData_t* dstObj );
bool willTruncateObj(const cmData_t* srcObj, cmData_t* dstObj );
enum
{
kOkDtRC = cmOkRC,
kAssertErrDtRC,
kConstErrDtRC,
kCvtErrDtRC,
kInvalidContDtRC,
kInvalidTypeDtRC,
kEolDtRC
};
typedef unsigned cmDtRC_t;
typedef enum
{
kInvalidTypeDtId,// 0
kNullDtId, // 1 the data object exists but it has no data
kUCharDtId, // 2
kCharDtId, // 3
kUShortDtId, // 4
kShortDtId, // 5
kUIntDtId, // 6
kIntDtId, // 7
kULongDtId, // 8
kLongDtId, // 9
kFloatDtId, // 10
kDoubleDtId, // 11
kStrDtId, // 12 zero terminated string
kBlobDtId, // 13 application defined raw memory object
kStructDtId // 14 node is a pair,list, or recd
} cmDataTypeId_t;
typedef enum
{
kInvalidCntDtId, // 0
kScalarDtId, // 1
kArrayDtId, // 2
kPairDtId, // 3
kListDtId, // 4
kRecordDtId // 5
} cmDataContainerId_t;
enum
{
kNoFlagsDtFl = 0x00,
// Indicate that the memory used by the data object
// was dynamically allocated and should be released
// by cmDataFree().
kFreeObjDtFl = 0x01,
// Indicate that the memory used by strings, blobs
// and arrays should be freed by cmDataFree().
kFreeValueDtFl = 0x02,
// Indicate that the value of the object cannot be changed.
// (but the object could be reassigned as a new type).
kConstValueDtFl = 0x04,
// Indicate that the type of the object cannot be changed.
// (but the value may be changed).
kConstObjDtFl = 0x08,
// Indicate that the array or string should not be
// internally reallocated but rather the source pointer
// should be taken as the new value of the object.
kNoCopyDtFl = 0x10,
};
typedef struct cmData_str
{
cmDataTypeId_t tid; // data format id
cmDataContainerId_t cid; // container id
unsigned flags; //
struct cmData_str* parent; // this childs parent
struct cmData_str* sibling; // this childs left sibling
unsigned cnt; // byte cnt for strings/blobs and ele count for arrays
union
{
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
cmChar_t* z;
void* vp;
/*
char* cp;
unsigned char* ucp;
short* sp;
unsigned short* usp;
int* ip;
unsigned int* uip;
long* lp;
unsigned long* ulp;
float* fp;
double* dp;
*/
struct cmData_str* child; // first child (list,record,pair)
} u;
} cmData_t;
extern cmData_t cmDataNull;
const cmChar_t* cmDataTypeToLabel( cmDataTypeId_t tid );
cmDataTypeId_t cmDataLabelToType( const cmChar_t* typeLabelStr );
// Returns 1 for kStrDtId.
// Returns cmInvalidCnt if tid is not recognized.
unsigned dmDataByteWidth( cmDataTypeId_t tid );
const cmChar_t* cmDataContainerIdToLabel( cmDataContainerId_t tid );
cmDataContainerId_t cmDataLabelToContainerId( const cmChar_t* contLabelStr );
bool cmDataIsConstObj( const cmData_t* d );
void cmDataEnableConstObj( cmData_t* d, bool enaFl );
bool cmDataIsConstValue( const cmData_t* d );
void cmDataEnableConstValue( cmData_t* d, bool enaFl );
bool cmDataIsFreeValue( const cmData_t* d );
void cmDataEnableFreeValue( cmData_t* d, bool enaFl );
// Returns true if this is a scalar or array node.
bool cmDataIsLeaf( const cmData_t* d);
// Return true if this is NOT a scalar or array node.
bool cmDataIsStruct( const cmData_t* d );
// Get the value of an object without conversion.
// The data type id must match the return type or the
// conversion must be an automatic C conversion.
char cmDataChar( const cmData_t* p );
unsigned char cmDataUChar( const cmData_t* p );
short cmDataShort( const cmData_t* p );
unsigned short cmDataUShort( const cmData_t* p );
int cmDataInt( const cmData_t* p );
unsigned int cmDataUInt( const cmData_t* p );
long cmDataLong( const cmData_t* p );
unsigned long cmDataULong( const cmData_t* p );
float cmDataFloat( const cmData_t* p );
double cmDataDouble( const cmData_t* p );
cmChar_t* cmDataStr( const cmData_t* p );
const cmChar_t* cmDataConstStr( const cmData_t* p );
void* cmDataVoidPtr( const cmData_t* p );
char* cmDataCharPtr( const cmData_t* p );
unsigned char* cmDataUCharPtr( const cmData_t* p );
short* cmDataShortPtr( const cmData_t* p );
unsigned short* cmDataUShortPtr( const cmData_t* p );
int* cmDataIntPtr( const cmData_t* p );
unsigned int* cmDataUIntPtr( const cmData_t* p );
long* cmDataLongPtr( const cmData_t* p );
unsigned long* cmDataULongPtr( const cmData_t* p );
float* cmDataFloatPtr( const cmData_t* p );
double* cmDataDoublePtr( const cmData_t* p );
//----------------------------------------------------------------------------
// Scalar related functions
//
// Dynamically allocate a scalar object and set it's value.
// The 'flags' argument may include kConstValueDtFl and kConstObjDtFl.
// The string and blob constructors may also use the
// kNoCopyDtFl and the kFreeValueDtFl.
// Generic:
// 'byteCnt' is ignored for all types other than strings and blobs.
cmDtRC_t cmDataNewScalar( cmData_t* parent, cmDataTypeId_t tid, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref );
// Type specific
cmDtRC_t cmDataNewNull( cmData_t* parent, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewChar( cmData_t* parent, unsigned flags, char v, cmData_t** ref );
cmDtRC_t cmDataNewUChar( cmData_t* parent, unsigned flags, unsigned char v, cmData_t** ref );
cmDtRC_t cmDataNewShort( cmData_t* parent, unsigned flags, short v, cmData_t** ref );
cmDtRC_t cmDataNewUShort( cmData_t* parent, unsigned flags, unsigned short v, cmData_t** ref );
cmDtRC_t cmDataNewInt( cmData_t* parent, unsigned flags, int v, cmData_t** ref );
cmDtRC_t cmDataNewUInt( cmData_t* parent, unsigned flags, unsigned int v, cmData_t** ref );
cmDtRC_t cmDataNewLong( cmData_t* parent, unsigned flags, long v, cmData_t** ref );
cmDtRC_t cmDataNewULong( cmData_t* parent, unsigned flags, unsigned long v, cmData_t** ref );
cmDtRC_t cmDataNewFloat( cmData_t* parent, unsigned flags, float v, cmData_t** ref );
cmDtRC_t cmDataNewDouble( cmData_t* parent, unsigned flags, double v, cmData_t** ref );
cmDtRC_t cmDataNewStr( cmData_t* parent, unsigned flags, cmChar_t* str, cmData_t** ref );
cmDtRC_t cmDataNewConstStr( cmData_t* parent, unsigned flags, const cmChar_t* str, cmData_t** ref );
cmDtRC_t cmDataNewStrN( cmData_t* parent, unsigned flags, cmChar_t* str, unsigned charCnt, cmData_t** ref );
cmDtRC_t cmDataNewConstStrN(cmData_t* parent, unsigned flags, const cmChar_t* str, unsigned charCnt, cmData_t** ref );
cmDtRC_t cmDataNewBlob( cmData_t* parent, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref );
cmDtRC_t cmDataNewConstBlob(cmData_t* parent, unsigned flags, const void* vp, unsigned byteCnt, cmData_t** ref );
// Set the value and type of an existing scalar object.
// These functions begin by releasing any resources held by *p
// prior to resetting the type and value of the object.
// The 'flags' argument to cmDataSetStr() and cmDataSetConstStr()
// may use the kNoCopyDtFl and the kFreeValueDtFl
cmDtRC_t cmDataSetScalarValue( cmData_t* d, cmDataTypeId_t tid, void* vp, unsigned byteCnt, unsigned flags );
cmDtRC_t cmDataSetNull( cmData_t* p );
cmDtRC_t cmDataSetChar( cmData_t* p, char v );
cmDtRC_t cmDataSetUChar( cmData_t* p, unsigned char v );
cmDtRC_t cmDataSetShort( cmData_t* p, short v );
cmDtRC_t cmDataSetUShort( cmData_t* p, unsigned short v );
cmDtRC_t cmDataSetInt( cmData_t* p, int v );
cmDtRC_t cmDataSetUInt( cmData_t* p, unsigned int v );
cmDtRC_t cmDataSetLong( cmData_t* p, long v );
cmDtRC_t cmDataSetULong( cmData_t* p, unsigned long v );
cmDtRC_t cmDataSetFloat( cmData_t* p, float v );
cmDtRC_t cmDataSetDouble( cmData_t* p, double v );
cmDtRC_t cmDataSetStr( cmData_t* p, unsigned flags, cmChar_t* s );
cmDtRC_t cmDataSetConstStr( cmData_t* p, unsigned flags, const cmChar_t* s );
cmDtRC_t cmDataSetStrN( cmData_t* p, unsigned flags, cmChar_t* s, unsigned charCnt );
cmDtRC_t cmDataSetConstStrN( cmData_t* p, unsigned flags, const cmChar_t* s, unsigned charCnt );
cmDtRC_t cmDataSetBlob( cmData_t* p, unsigned flags, void* v, unsigned byteCnt );
cmDtRC_t cmDataSetConstBlob( cmData_t* p, unsigned flags, const void* v, unsigned byteCnt );
// Get the value of an object. No conversion is applied the
// type must match exactly or an error is generated.
cmDtRC_t cmDataChar( const cmData_t* p, char* v );
cmDtRC_t cmDataUChar( const cmData_t* p, unsigned char* v );
cmDtRC_t cmDataShort( const cmData_t* p, short* v );
cmDtRC_t cmDataUShort( const cmData_t* p, unsigned short* v );
cmDtRC_t cmDataInt( const cmData_t* p, int* v );
cmDtRC_t cmDataUInt( const cmData_t* p, unsigned int* v );
cmDtRC_t cmDataLong( const cmData_t* p, long* v );
cmDtRC_t cmDataULong( const cmData_t* p, unsigned long* v );
cmDtRC_t cmDataFloat( const cmData_t* p, float* v );
cmDtRC_t cmDataDouble( const cmData_t* p, double* v );
cmDtRC_t cmDataStr( const cmData_t* p, cmChar_t** v );
cmDtRC_t cmDataConstStr( const cmData_t* p, const cmChar_t** v );
cmDtRC_t cmDataBlob( const cmData_t* p, cmChar_t** v, unsigned* byteCntRef );
cmDtRC_t cmDataConstBlob( const cmData_t* p, const cmChar_t** v, unsigned* byteCntRef );
// Get the value of an object with conversion.
cmDtRC_t cmDataGetChar( const cmData_t* p, char* v );
@ -217,124 +281,95 @@ extern "C" {
cmDtRC_t cmDataGetFloat( const cmData_t* p, float* v );
cmDtRC_t cmDataGetDouble( const cmData_t* p, double* v );
// Returns the pointer - does not copy the data.
cmDtRC_t cmDataGetStr( const cmData_t* p, char** v );
cmDtRC_t cmDataGetConstStr( const cmData_t* p, const char** v );
cmDtRC_t cmDataGetVoidPtr( const cmData_t* p, void** v );
cmDtRC_t cmDataGetCharPtr( const cmData_t* p, char** v );
cmDtRC_t cmDataGetUCharPtr( const cmData_t* p, unsigned char** v );
cmDtRC_t cmDataGetShortPtr( const cmData_t* p, short** v );
cmDtRC_t cmDataGetUShortPtr( const cmData_t* p, unsigned short** v );
cmDtRC_t cmDataGetIntPtr( const cmData_t* p, int** v );
cmDtRC_t cmDataGetUIntPtr( const cmData_t* p, unsigned int** v );
cmDtRC_t cmDataGetLongPtr( const cmData_t* p, long** v );
cmDtRC_t cmDataGetULongPtr( const cmData_t* p, unsigned long** v );
cmDtRC_t cmDataGetFloatPtr( const cmData_t* p, float** v );
cmDtRC_t cmDataGetDoublePtr( const cmData_t* p, double** v );
//----------------------------------------------------------------------------
// Array related functions
//
// Notes:
// 1) string arrays are arrays of string pointers.
// 2) blob arrays (array of void pointers) are not supported because
// there is no direct way to determine the length of each blob
// and therefore they cannot be internally duplicated - a special scheme
// could be devised (length goes in first 4 bytes) to make this
// work but we will defer that until the need arises.
//
// Dynamically allocate a new array data object.
//
// eleCnt referes to the number of elements in the array pointed
// to by 'vp'. The number of bytes pointed to by 'vp' is then
// cmDataByteWidth(tid)*eleCnt.
//
// If no flags are set then the array pointed to by 'vp' is reallocated
// and kDataFreeDtFl is set.
//
// If kFreeValueDtFl is set then the object will take responsibility for
// releasing the memory pointed to by 'vp' when the object is destroyed
// or the array is reassigned.
//
// If kNoCopyDtFl is set then 'vp' becomes the internal array
// value (vp[cnt]) is NOT reallocated). In this case the client is
// responsibile for eventually releasing the associated memory - when
// the data object is no longer valid.
cmDtRC_t cmDataNewArray( cmData_t* parent, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewCharArray( cmData_t* parent, char* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUCharArray( cmData_t* parent, unsigned char* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewShortArray( cmData_t* parent, short* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUShortArray( cmData_t* parent, unsigned short* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewIntArray( cmData_t* parent, int* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewUIntArray( cmData_t* parent, unsigned int* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewLongArray( cmData_t* parent, long* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewULongArray( cmData_t* parent, unsigned long* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewFloatArray( cmData_t* parent, float* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewDoubleArray( cmData_t* parent, double* v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewStrArray( cmData_t* parent, cmChar_t** v, unsigned eleCnt, unsigned flags, cmData_t** ref );
cmDtRC_t cmDataNewConstStrArray( cmData_t* parent, const cmChar_t** v,unsigned eleCnt, unsigned flags, cmData_t** ref );
// Set the value and type of an existing scalar object.
//
// These functions begin by releasing any resources held by *p
// prior to resetting the type and value of the object.
cmData_t* cmDataSetNull( cmData_t* p );
cmData_t* cmDataSetChar( cmData_t* p, char v );
cmData_t* cmDataSetUChar( cmData_t* p, unsigned char v );
cmData_t* cmDataSetShort( cmData_t* p, short v );
cmData_t* cmDataSetUShort( cmData_t* p, unsigned short v );
cmData_t* cmDataSetInt( cmData_t* p, int v );
cmData_t* cmDataSetUInt( cmData_t* p, unsigned int v );
cmData_t* cmDataSetLong( cmData_t* p, long v );
cmData_t* cmDataSetULong( cmData_t* p, unsigned long v );
cmData_t* cmDataSetFloat( cmData_t* p, float v );
cmData_t* cmDataSetDouble( cmData_t* p, double v );
cmData_t* cmDataSetStr( cmData_t* p, cmChar_t* s );
cmData_t* cmDataSetConstStr( cmData_t* p, const cmChar_t* s );
// The 'flags' argument may include kConstValueDtFl, kConstObjDtFl,
// kNoCopyDtFl and the kFreeValueDtFl.
// Set the type and value of an existing data object to an external array.
// These functions begin by releasing any resources help by *p.
// The array pointed to by 'vp' is not copied or duplicated.
// 'vp' is simply assigned as the data space for the object and therefore must remain
// valid for the life of the object.
cmData_t* cmDataSetVoidPtr( cmData_t* p, void* vp, unsigned cnt );
cmData_t* cmDataSetCharPtr( cmData_t* p, char* vp, unsigned cnt );
cmData_t* cmDataSetUCharPtr( cmData_t* p, unsigned char* vp, unsigned cnt );
cmData_t* cmDataSetShortPtr( cmData_t* p, short* vp, unsigned cnt );
cmData_t* cmDataSetUShortPtr( cmData_t* p, unsigned short* vp, unsigned cnt );
cmData_t* cmDataSetIntPtr( cmData_t* p, int* vp, unsigned cnt );
cmData_t* cmDataSetUIntPtr( cmData_t* p, unsigned int* vp, unsigned cnt );
cmData_t* cmDataSetLongPtr( cmData_t* p, long* vp, unsigned cnt );
cmData_t* cmDataSetULongPtr( cmData_t* p, unsigned long* vp, unsigned cnt );
cmData_t* cmDataSetFloatPtr( cmData_t* p, float* vp, unsigned cnt );
cmData_t* cmDataSetDoublePtr( cmData_t* p, double* vp, unsigned cnt );
// Generic set array functions. 'vp' is assumed to point to an array
// of the type defined by 'tid'.
cmDtRC_t cmDataSetArrayValue( cmData_t* dt, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags );
// Set the value of an existing array based data object.
// These functions begin by releasing any resources help by *p
// and then dynamically allocate the internal array and copy
// the array data into it.
cmData_t* cmDataSetStrAlloc( cmData_t* p, const cmChar_t* s );
cmData_t* cmDataSetConstStrAlloc( cmData_t* p, const cmChar_t* s );
cmData_t* cmDataSetVoidAllocPtr( cmData_t* p, const void* vp, unsigned cnt );
cmData_t* cmDataSetCharAllocPtr( cmData_t* p, const char* vp, unsigned cnt );
cmData_t* cmDataSetUCharAllocPtr( cmData_t* p, const unsigned char* vp, unsigned cnt );
cmData_t* cmDataSetShortAllocPtr( cmData_t* p, const short* vp, unsigned cnt );
cmData_t* cmDataSetUShortAllocPtr( cmData_t* p, const unsigned short* vp, unsigned cnt );
cmData_t* cmDataSetIntAllocPtr( cmData_t* p, const int* vp, unsigned cnt );
cmData_t* cmDataSetUIntAllocPtr( cmData_t* p, const unsigned int* vp, unsigned cnt );
cmData_t* cmDataSetLongAllocPtr( cmData_t* p, const long* vp, unsigned cnt );
cmData_t* cmDataSetULongAllocPtr( cmData_t* p, const unsigned long* vp, unsigned cnt );
cmData_t* cmDataSetFloatAllocPtr( cmData_t* p, const float* vp, unsigned cnt );
cmData_t* cmDataSetDoubleAllocPtr( cmData_t* p, const double* vp, unsigned cnt );
// Type sepctific set array functions.
cmDtRC_t cmDataSetCharArray( cmData_t* d, char* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUCharArray( cmData_t* d, unsigned char* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetShortArray( cmData_t* d, short* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUShortArray( cmData_t* d, unsigned short* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetIntArray( cmData_t* d, int* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetUIntArray( cmData_t* d, unsigned int* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetLongArray( cmData_t* d, long* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetULongArray( cmData_t* d, unsigned long* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetFloatArray( cmData_t* d, float* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetDoubleArray( cmData_t* d, double* v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetStrArray( cmData_t* d, cmChar_t** v, unsigned eleCnt, unsigned flags );
cmDtRC_t cmDataSetConstStrArray(cmData_t* d,const cmChar_t** v,unsigned eleCnt, unsigned flags );
// Return the count of elements in a n array.
unsigned cmDataArrayEleCount( const cmData_t* d );
// Dynamically allocate a data object and set it's value.
cmData_t* cmDataAllocNull( cmData_t* parent );
cmData_t* cmDataAllocChar( cmData_t* parent, char v );
cmData_t* cmDataAllocUChar( cmData_t* parent, unsigned char v );
cmData_t* cmDataAllocShort( cmData_t* parent, short v );
cmData_t* cmDataAllocUShort( cmData_t* parent, unsigned short v );
cmData_t* cmDataAllocInt( cmData_t* parent, int v );
cmData_t* cmDataAllocUInt( cmData_t* parent, unsigned int v );
cmData_t* cmDataAllocLong( cmData_t* parent, long v );
cmData_t* cmDataAllocULong( cmData_t* parent, unsigned long v );
cmData_t* cmDataAllocFloat( cmData_t* parent, float v );
cmData_t* cmDataAllocDouble( cmData_t* parent, double v );
// Dynamically allocate a data object and set its array value to an external
// array. v[cnt] is assigned as the internal data space for the object and
// therefore must remain valid for the life of the object.
// See the cmDataXXXAlocPtr() for equivalent functions which dynamically
// allocate the intenal data space.
cmData_t* cmDataAllocStr( cmData_t* parent, cmChar_t* str );
cmData_t* cmDataAllocConstStr( cmData_t* parent, const cmChar_t* str );
cmData_t* cmDataAllocCharPtr( cmData_t* parent, char* v, unsigned cnt );
cmData_t* cmDataAllocUCharPtr( cmData_t* parent, unsigned char* v, unsigned cnt );
cmData_t* cmDataAllocShortPtr( cmData_t* parent, short* v, unsigned cnt );
cmData_t* cmDataAllocUShortPtr( cmData_t* parent, unsigned short* v, unsigned cnt );
cmData_t* cmDataAllocIntPtr( cmData_t* parent, int* v, unsigned cnt );
cmData_t* cmDataAllocUIntPtr( cmData_t* parent, unsigned int* v, unsigned cnt );
cmData_t* cmDataAllocLongPtr( cmData_t* parent, long* v, unsigned cnt );
cmData_t* cmDataAllocULongPtr( cmData_t* parent, unsigned long* v, unsigned cnt );
cmData_t* cmDataAllocFloatPtr( cmData_t* parent, float* v, unsigned cnt );
cmData_t* cmDataAllocDoublePtr( cmData_t* parent, double* v, unsigned cnt );
cmData_t* cmDataAllocVoidPtr( cmData_t* parent, void* v, unsigned cnt );
// Dynamically allocate a data object and its array value.
// These functions dynamically allocate the internal array data space
// and copy v[cnt] into it.
cmData_t* cmDataStrAlloc( cmData_t* parent, cmChar_t* str );
cmData_t* cmDataConstStrAlloc( cmData_t* parent, const cmChar_t* str );
cmData_t* cmDataCharAllocPtr( cmData_t* parent, const char* v, unsigned cnt );
cmData_t* cmDataUCharAllocPtr( cmData_t* parent, const unsigned char* v, unsigned cnt );
cmData_t* cmDataShortAllocPtr( cmData_t* parent, const short* v, unsigned cnt );
cmData_t* cmDataUShortAllocPtr( cmData_t* parent, const unsigned short* v, unsigned cnt );
cmData_t* cmDataIntAllocPtr( cmData_t* parent, const int* v, unsigned cnt );
cmData_t* cmDataUIntAllocPtr( cmData_t* parent, const unsigned int* v, unsigned cnt );
cmData_t* cmDataLongAllocPtr( cmData_t* parent, const long* v, unsigned cnt );
cmData_t* cmDataULongAllocPtr( cmData_t* parent, const unsigned long* v, unsigned cnt );
cmData_t* cmDataFloatAllocPtr( cmData_t* parent, const float* v, unsigned cnt );
cmData_t* cmDataDoubleAllocPtr( cmData_t* parent, const double* v, unsigned cnt );
cmData_t* cmDataVoidAllocPtr( cmData_t* parent, const void* v, unsigned cnt );
// Get a pointer to the base of an array.
// The type must match exactly or an error is generated.
// Use cmDataEleCount() to determine the number of elements in the array.
cmDtRC_t cmDataCharArray( const cmData_t* d, char** v );
cmDtRC_t cmDataUCharArray( const cmData_t* d, unsigned char** v );
cmDtRC_t cmDataShortArray( const cmData_t* d, short** v );
cmDtRC_t cmDataUShortArray( const cmData_t* d, unsigned short** v );
cmDtRC_t cmDataIntArray( const cmData_t* d, int** v );
cmDtRC_t cmDataUIntArray( const cmData_t* d, unsigned int** v );
cmDtRC_t cmDataLongArray( const cmData_t* d, long** v );
cmDtRC_t cmDataULongArray( const cmData_t* d, unsigned long** v );
cmDtRC_t cmDataFloatArray( const cmData_t* d, float** v );
cmDtRC_t cmDataDoubleArray( const cmData_t* d, double** v );
cmDtRC_t cmDataStrArray( const cmData_t* d, cmChar_t*** v );
cmDtRC_t cmDataConstStrArray( const cmData_t* d, const cmChar_t*** v );
//----------------------------------------------------------------------------
// Structure related functions
@ -428,6 +463,7 @@ extern "C" {
cmData_t* cmDataAllocPairId( cmData_t* parent, unsigned keyId, cmData_t* value );
// Dynamically allocate the label but link (w/o realloc) the value.
cmData_t* cmDataAllocPairLabelN(cmData_t* parent, const cmChar_t* label, unsigned charCnt, cmData_t* value);
cmData_t* cmDataAllocPairLabel( cmData_t* parent, const cmChar_t* label, cmData_t* value );
//----------------------------------------------------------------------------
@ -445,15 +481,15 @@ extern "C" {
// Var-args fmt:
// <typeId> <value> {<cnt>}
// <contId> {<typeId>} <value> {<cnt>}
// scalar types: <value> is literal,<cnt> is not included
// null has no <value> or <cnt>
// ptr types: <value> is pointer,<cnt> is element count
// struct types: <value> is cmData_t, <cnt> is not included
// array types: <value> is pointer,<cnt> is element count
// struct types: <value> is cmData_t, <typeId> and <cnt> is not included
// Indicate the end of argument list by setting <typeId> to kInvalidDtId.
// The memory for array based data types is dynamically allocated.
cmData_t* cmDataListAllocV(cmData_t* parent, va_list vl );
cmData_t* cmDataListAllocA(cmData_t* parent, ... );
cmRC_t cmDataListAllocV(cmData_t* parent, cmData_t** ref, va_list vl );
cmRC_t cmDataListAllocA(cmData_t* parent, cmData_t** ref, ... );
// Returns a ptr to 'ele'.
cmData_t* cmDataListAppendEle( cmData_t* p, cmData_t* ele );
@ -464,9 +500,6 @@ extern "C" {
cmData_t* cmDataListInsertEle( cmData_t* p, unsigned index, cmData_t* ele );
cmData_t* cmDataListInsertEleN(cmData_t* p, unsigned index, cmData_t* ele[], unsigned n );
cmData_t* cmDataListUnlink( cmData_t* p, unsigned index );
cmData_t* cmDataListFree( cmData_t* p, unsigned index );
//----------------------------------------------------------------------------
// Record related functions
//
@ -487,17 +520,17 @@ extern "C" {
unsigned cmDataRecdKeyId( cmData_t* p, unsigned index );
const cmChar_t* cmDataRecdKeyLabel( cmData_t* p, unsigned index );
cmData_t* cmRecdMake( cmData_t* parent, cmData_t* p );
cmData_t* cmRecdAlloc( cmData_t* parent );
cmData_t* cmDataRecdMake( cmData_t* parent, cmData_t* p );
cmData_t* cmDataRecdAlloc( cmData_t* parent );
// Append a pair node by linking the pair node 'pair' to the record node 'p'.
// 'pair' is simply linked to 'p' via cmDataAppendChild() no
// reallocation or duplicattion takes place.
cmData_t* cmRecdAppendPair( cmData_t* p, cmData_t* pair );
cmData_t* cmDataRecdAppendPair( cmData_t* p, cmData_t* pair );
// Var-args format:
// <label|id> <typeId> <value> {<cnt>}
// <label|id> {<cid>} <typeId> <value> {<cnt>}
// scalar types: <value> is literal,<cnt> is not included
// null type: has no <value> or <cnt>
// ptr types: <value> is pointer, <cnt> is element count
@ -530,12 +563,27 @@ extern "C" {
cmDtRC_t cmDataSerialize( const cmData_t* p, void* buf, unsigned bufByteCnt );
cmDtRC_t cmDataDeserialize( const void* buf, unsigned bufByteCnt, cmData_t** pp );
//-----------------------------------------------------------------------------
typedef cmHandle_t cmDataParserH_t;
//static cmDataParserH_t cmDataParserNullHandle;
cmDtRC_t cmDataParserCreate( cmCtx_t* ctx, cmDataParserH_t* hp );
cmDtRC_t cmDataParserDestroy( cmDataParserH_t* hp );
bool cmDataParserIsValid( cmDataParserH_t h );
// Parse a text representation into a 'record' type.
// Note that the text is wrapped with implied curly braces
// (e.g. "{ text }"). The contents of the text should therefore
// fit the record syntax (e.g. the first token should be a
// 'pair' label.
cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** pp );
//-----------------------------------------------------------------------------
void cmDataPrint( const cmData_t* p, cmRpt_t* rpt );
void cmDataTest( cmCtx_t* ctx );
#ifdef __cplusplus
}
#endif

View File

@ -60,7 +60,11 @@ extern "C" {
// Draw the page.
void cmGrPageDraw( cmGrPgH_t h, cmGrDcH_t dcH );
// Label callback functions are used to translate numeric axis values to
// text strings. Multiple label callback functions can be registered with
// a page and then assigned to a given view axis via cmGrViewSetLabelFunc().
typedef void (*cmGrLabelFunc_t)( void* arg, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value );
// Returns id of the new page label function.
unsigned cmGrPageLabelFuncRegister( cmGrPgH_t h, cmGrLabelFunc_t func, void* arg, const cmChar_t* label );
unsigned cmGrPageLabelFuncCount( cmGrPgH_t h );

171
cmLex.c
View File

@ -7,6 +7,12 @@
#include "cmMallocDebug.h"
#include "cmFile.h"
enum
{
kRealFloatLexFl = 0x01,
kIntUnsignedLexFl = 0x02
};
typedef struct
{
unsigned code;
@ -29,6 +35,7 @@ cmLexErrorRecd cmLexErrorArray[] =
{ kMemAllocErrLexRC, "An attempted memory allocation failed"},
{ kEofRC, "The end of the input text was encountered (this is a normal condition not an error)"},
{ kInvalidLexTIdLexRC, "An invalid token id was encountered."},
{ kSignErrorLexRC, "A signed integer has a 'u' or 'U' suffix."},
{ kInvalidLexRC, "Unknown lexer error code." }
};
@ -75,6 +82,7 @@ typedef struct cmLex_str
cmChar_t* textBuf; // text buf used by cmLexSetFile()
unsigned attrFlags; // used to store the int and real suffix type flags
} cmLex;
@ -148,7 +156,7 @@ unsigned _cmLexRealMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm
unsigned i = 0;
unsigned n = 0; // decimal point counter
unsigned d = 0; // digit counter
bool fl = false; // true if this real includes an exponent
bool fl = false; // expo flag
for(; i<cn && n<=1; ++i)
{
@ -170,10 +178,12 @@ unsigned _cmLexRealMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm
// if there was at least one digit and the next char is an 'e'
if( d>0 && i<cn && (cp[i] == 'e' || cp[i] == 'E') )
{
d=0;
unsigned e=0;
++i;
unsigned j = i;
fl = false;
for(; i<cn; ++i)
{
if( i==j && cp[i]=='-' ) // allow the char following the e to be '-'
@ -181,6 +191,7 @@ unsigned _cmLexRealMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm
if( isdigit(cp[i]) )
{
++e;
++d;
continue;
}
@ -190,17 +201,42 @@ unsigned _cmLexRealMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm
}
// an exp exists if digits follwed the 'e'
fl = d > 0;
fl = e > 0;
}
return i>1 && (n==1 || fl) ? i : 0;
// if at least one digit was found
if( d>0 )
{
// Note that this path allows a string w/o a decimal pt to trigger a match.
if(i<cn)
{
// if the real has a suffix
switch(cp[i])
{
case 'F':
case 'f':
p->attrFlags = cmSetFlag(p->attrFlags,kRealFloatLexFl);
++i;
break;
}
}
// match w/o suffix return
if( d>0 && (fl || n==1 || cmIsFlag(p->attrFlags,kRealFloatLexFl)) )
return i;
}
return 0; // no-match return
}
unsigned _cmLexIntMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cmChar_t* keyStr )
{
unsigned i = 0;
bool signFl = false;
for(; i<cn; ++i)
{
if( i==0 && cp[i]=='-' )
@ -223,8 +259,34 @@ unsigned _cmLexIntMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm
// The current implementation recognizes all numeric strings
// containing a decimal point as reals.
// if no integer was found
if( (signFl && i==0) || i==0 )
return 0;
return signFl && i==1 ? 0 : i;
// check for suffix
if(i<cn )
{
switch(cp[i])
{
case 'u':
case 'U':
if( signFl )
_cmLexError(p,kSignErrorLexRC,"A signed integer has a 'u' or 'U' suffix.");
else
{
p->attrFlags = cmSetFlag(p->attrFlags,kIntUnsignedLexFl);
++i;
}
break;
default:
break;
}
}
return i;
}
unsigned _cmLexHexMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cmChar_t* keyStr )
@ -387,23 +449,6 @@ cmLexH cmLexInit( const cmChar_t* cp, unsigned cn, unsigned flags, cmRpt_t* rpt
_cmLexSetTextBuffer( p, cp, cn );
/*
p->cp = (cn==0) ? NULL : cp;
p->cn = (cp==NULL) ? 0 : cn;
p->ci = 0;
p->curTokenId = kErrorLexTId;
p->curTokenCharIdx = cmInvalidIdx;
p->curTokenCharCnt = 0;
p->curLine = 0;
p->curCol = 0;
p->nextLine = 0;
p->nextCol = 0;
*/
int init_mfn = 10;
p->mfp = cmMemAllocZ( cmLexMatcher, init_mfn );
p->mfn = init_mfn;
@ -537,70 +582,6 @@ cmRC_t cmLexSetFile( cmLexH h, const cmChar_t* fn )
return rc;
}
/*
cmRC_t cmLexSetFile( cmLexH h, const cmChar_t* fn )
{
cmRC_t rc = kOkLexRC;
FILE* fp = NULL;
cmLex* p = _cmLexHandleToPtr(h);
unsigned n = 0;
assert( fn != NULL && p != NULL );
// open the file
if((fp = fopen(fn,"rb")) == NULL )
return _cmLexError(p,kFileOpenErrLexRC,"Unable to open the file:'%s'.",fn);
// seek to the end
if( fseek(fp,0,SEEK_END) != 0 )
{
rc= _cmLexError(p,kFileSeekErrLexRC,"Unable to seek to the end of '%s'.",fn);
goto errLabel;
}
// get the length of the file
if( (n=ftell(fp)) == 0 )
{
rc = _cmLexError(p,kFileOpenErrLexRC,"The file '%s' appears to be empty.",fn);
goto errLabel;
}
// rewind the file
if( fseek(fp,0,SEEK_SET) != 0 )
{
rc = _cmLexError(p,kFileSeekErrLexRC,"Unable to seek to the beginning of '%s'.",fn);
goto errLabel;
}
// allocate the text buffer
if((p->textBuf = cmMemResizeZ( char, p->textBuf, n+1)) == NULL )
{
rc = _cmLexError(p,kMemAllocErrLexRC,"Unable to allocate the text file buffer for:'%s'.",fn);
goto errLabel;
}
// read the file into the text buffer
if( fread(p->textBuf,n,1,fp) != 1 )
{
rc = _cmLexError(p,kFileReadErrLexRC,"File read failed on:'%s'.",fn);
goto errLabel;
}
if((rc = _cmLexSetTextBuffer( p, p->textBuf, n )) != kOkLexRC )
goto errLabel;
errLabel:
// close the file
if( fclose(fp) != 0 )
{
rc = _cmLexError(p,kFileCloseErrLexRC,"File close failed on:'%s'.",fn);
goto errLabel;
}
return rc;
}
*/
cmLexMatcher* _cmLexFindUserToken( cmLex* p, unsigned id, const cmChar_t* tokenStr )
{
@ -689,9 +670,9 @@ unsigned cmLexGetNextToken( cmLexH h )
p->curTokenId = kErrorLexTId;
p->curTokenCharIdx = cmInvalidIdx;
p->curTokenCharCnt = 0;
p->attrFlags = 0;
// try each mater
// try each matcher
for(; mi<p->mfi; ++mi)
if( p->mfp[mi].enableFl )
{
@ -701,6 +682,7 @@ unsigned cmLexGetNextToken( cmLexH h )
else
charCnt = p->mfp[mi].userPtr( p->cp + p->ci, p->cn - p->ci);
// notice if the matcher set the error code
if( cmErrLastRC(&p->err) != kOkLexRC )
return kErrorLexTId;
@ -823,6 +805,19 @@ float cmLexTokenFloat( cmLexH h )
double cmLexTokenDouble( cmLexH h )
{ return strtod( cmLexTokenText(h),NULL ); }
bool cmLexTokenIsUnsigned( cmLexH h )
{
cmLex* p = _cmLexHandleToPtr(h);
return p->curTokenId == kIntLexTId && cmIsFlag(p->attrFlags,kIntUnsignedLexFl);
}
bool cmLexTokenIsSinglePrecision( cmLexH h )
{
cmLex* p = _cmLexHandleToPtr(h);
return p->curTokenId == kRealLexTId && cmIsFlag(p->attrFlags,kRealFloatLexFl);
}
unsigned cmLexCurrentLineNumber( cmLexH h )
{
cmLex* p = _cmLexHandleToPtr(h);

15
cmLex.h
View File

@ -50,7 +50,8 @@ enum
kMemAllocErrLexRC, //< 10 An attempted memory allocation failed
kEofRC, //< 11 The end of the input text was encountered (this is a normal condition not an error)
kInvalidLexTIdLexRC, //< 12 An invalid lex token id was encountered.
kInvalidLexRC //< 13 Sentinal value.
kSignErrorLexRC, //< 13 An signed integer has a 'u' or 'U' suffix."
kInvalidLexRC //< 1r Sentinal value.
};
@ -119,15 +120,23 @@ unsigned cmLexTokenCharCount( cmLexH h );
// Return the value of the current token as an integer.
int cmLexTokenInt( cmLexH h );
// Return the value of the current token as an integer.
// Return the value of the current token as an unsigned integer.
unsigned cmLexTokenUInt( cmLexH h );
// Return the value of the current token as an integer.
// Return the value of the current token as a float.
float cmLexTokenFloat( cmLexH h );
// Return the value of the current token as a double.
double cmLexTokenDouble( cmLexH h );
// Return true if the current token is an int and it was suffixed
// with 'u' to indicate that it is unsigned.
bool cmLexTokenIsUnsigned( cmLexH h );
// Return true if the current token is a real and it was suffexed
// with 'f' to indicate that it is a single precision float.
bool cmLexTokenIsSinglePrecision( cmLexH h );
// Return the line number associated with the current token
unsigned cmLexCurrentLineNumber( cmLexH h );

View File

@ -64,7 +64,7 @@ extern "C" {
{
unsigned uid; // uid's are unique among all msg's in the file
unsigned dtick; // delta ticks
unsigned atick;
unsigned atick; // accumulated ticks
cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
cmMidiByte_t metaId; //
unsigned short trkIdx; //

353
cmProc4.c
View File

@ -4135,3 +4135,356 @@ cmRC_t cmScModulatorDump( cmScModulator* p )
return rc;
}
//=======================================================================================================================
cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs )
{
cmRecdPlay* op = cmObjAlloc(cmRecdPlay,c,p);
if( cmRecdPlayInit(op,srate,fragCnt,chCnt,initFragSecs,maxLaSecs,curLaSecs) != cmOkRC )
cmRecdPlayFree(&op);
return op;
}
cmRC_t cmRecdPlayFree( cmRecdPlay** pp )
{
cmRC_t rc = cmOkRC;
if( pp==NULL || *pp==NULL )
return rc;
cmRecdPlay* p = *pp;
if((rc = cmRecdPlayFinal(p)) != cmOkRC )
return rc;
cmObjFree(pp);
return rc;
}
cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs )
{
cmRC_t rc;
unsigned i;
if( curLaSecs > maxLaSecs )
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial look-ahead time %f is greater than the maximum look-ahead time %f.",curLaSecs,maxLaSecs);
if((rc = cmRecdPlayFinal(p)) != cmOkRC )
return rc;
if( chCnt == 0 )
return cmOkRC;
p->frags = cmMemAllocZ(cmRecdPlayFrag,fragCnt);
p->fragCnt = fragCnt;
p->srate = srate;
p->chCnt = chCnt;
p->initFragSecs = initFragSecs;
p->maxLaSmpCnt = floor(maxLaSecs*srate);
p->curLaSmpCnt = floor(curLaSecs*srate);
p->laChs = cmMemAllocZ(cmSample_t*,chCnt);
p->laSmpIdx = 0;
for(i=0; i<chCnt; ++i)
p->laChs[i] = cmMemAllocZ(cmSample_t,p->maxLaSmpCnt);
return rc;
}
cmRC_t cmRecdPlayFinal( cmRecdPlay* p )
{
unsigned i,j;
// free the fragments
for(i=0; i<p->fragCnt; ++i)
{
for(j=0; j<p->chCnt; ++j)
cmMemFree(p->frags[i].chArray[j]);
cmMemFree(p->frags[i].chArray);
}
// free the look-ahead buffers
for(i=0; i<p->chCnt; ++i)
cmMemFree(p->laChs[i]);
cmMemPtrFree(&p->laChs);
cmMemPtrFree(&p->frags);
p->fragCnt = 0;
p->chCnt = 0;
p->rlist = NULL;
p->plist = NULL;
return cmOkRC;
}
cmRC_t cmRecdPlayRegisterFrag( cmRecdPlay* p, unsigned fragIdx, unsigned labelSymId )
{
assert( fragIdx < p->fragCnt );
unsigned i;
p->frags[ fragIdx ].labelSymId = labelSymId;
p->frags[ fragIdx ].chArray = cmMemResizeZ(cmSample_t*,p->frags[fragIdx].chArray,p->chCnt);
for(i=0; i<p->chCnt; ++i)
{
p->frags[ fragIdx ].allocCnt = floor(p->initFragSecs * p->srate);
p->frags[ fragIdx ].chArray[i] = cmMemResizeZ(cmSample_t,p->frags[ fragIdx ].chArray[i],p->frags[fragIdx].allocCnt);
}
return cmOkRC;
}
cmRC_t cmRecdPlayRewind( cmRecdPlay* p )
{
unsigned i;
p->laSmpIdx = 0;
while( p->plist != NULL )
cmRecdPlayEndPlay(p,p->plist->labelSymId);
while( p->rlist != NULL )
cmRecdPlayEndRecord(p,p->plist->labelSymId);
for(i=0; i<p->fragCnt; ++i)
p->frags[i].playIdx = 0;
return cmOkRC;
}
cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId )
{
unsigned i;
for(i=0; i<p->fragCnt; ++i)
if( p->frags[i].labelSymId == labelSymId )
{
// if the frag is not already on the recd list
if( p->frags[i].rlink == NULL )
{
p->frags[i].recdIdx = 0;
p->frags[i].playIdx = 0;
p->frags[i].rlink = p->rlist;
p->rlist = p->frags + i;
// handle LA buf longer than frag buf.
int cpyCnt = cmMin(p->curLaSmpCnt,p->frags[i].allocCnt);
// go backwards in LA buf from newest sample to find init src offset
int srcOffs = p->laSmpIdx - cpyCnt;
// if the src is before the first sample in the LA buf then wrap to end of buf
if( srcOffs < 0 )
srcOffs += p->maxLaSmpCnt;
assert( 0 <= srcOffs && srcOffs < p->maxLaSmpCnt );
// cnt of samples to copy from LA buf (limited by end of LA buf)
int n0 = cmMin(cpyCnt,p->maxLaSmpCnt - srcOffs);
// if necessary wrap to begin of LA buf for remaining samples
int n1 = cpyCnt>n0 ? n1 = cpyCnt-n0 : 0;
int j;
assert(n0+n1 == cpyCnt );
for(j=0; j<p->chCnt; ++j)
cmVOS_Copy(p->frags[i].chArray[j],n0,p->laChs[j]+srcOffs);
if( n1 > 0 )
{
for(j=0; j<p->chCnt; ++j)
cmVOS_Copy(p->frags[i].chArray[j]+n0,n1,p->laChs[j]);
}
p->frags[i].recdIdx = cpyCnt;
}
return cmOkRC;
}
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin record'.",labelSymId);
}
cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId )
{
cmRecdPlayFrag* fp = p->rlist;
cmRecdPlayFrag* pp = NULL;
for(; fp != NULL; fp=fp->rlink )
{
if( fp->labelSymId == labelSymId )
{
if( pp == NULL )
p->rlist = fp->rlink;
else
pp->rlink = fp->rlink;
fp->rlink = NULL;
return cmOkRC;
}
pp = fp;
}
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end record'.",labelSymId);
}
cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId )
{
unsigned i;
for(i=0; i<p->fragCnt; ++i)
if( p->frags[i].labelSymId == labelSymId )
{
// if the frag is not already on the play list
if( p->frags[i].plink == NULL )
{
p->frags[i].playIdx = 0;
p->frags[i].fadeSmpIdx = 0;
p->frags[i].fadeDbPerSec = 0.0;
p->frags[i].plink = p->plist;
p->plist = p->frags + i;
}
return cmOkRC;
}
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin play'.",labelSymId);
}
cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId )
{
cmRecdPlayFrag* fp = p->plist;
cmRecdPlayFrag* pp = NULL;
for(; fp != NULL; fp=fp->plink )
{
if( fp->labelSymId == labelSymId )
{
if( pp == NULL )
p->plist = fp->plink;
else
pp->plink = fp->plink;
fp->plink = NULL;
return cmOkRC;
}
pp = fp;
}
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end play'.",labelSymId);
}
cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec )
{
cmRecdPlayFrag* fp = p->plist;
for(; fp != NULL; fp=fp->plink )
if( fp->labelSymId == labelSymId )
{
fp->fadeDbPerSec = -fabs(fadeDbPerSec);
return cmOkRC;
}
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'fade begin'.",labelSymId);
}
cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt )
{
unsigned i;
chCnt = cmMin(chCnt, p->chCnt);
//-------------------------------------------------------------------
// copy incoming audio into the look-head buffers
//
// if the number of incoming samples is longer than the look-head buffer
// then copy exactly maxLaSmpCnt samples from the end of the incoming sample
// buffer to the look-ahead buffer.
unsigned srcOffs = 0;
unsigned srcSmpCnt = smpCnt;
if( srcSmpCnt > p->maxLaSmpCnt )
{
// advance incoming sample buffer so that there are maxLaSmpCnt samples remaining
srcOffs = smpCnt-p->maxLaSmpCnt;
srcSmpCnt = p->maxLaSmpCnt; // decrease the total samples to copy
}
// count of samples from cur posn to end of the LA buffer.
unsigned n0 = cmMin(srcSmpCnt, p->maxLaSmpCnt - p->laSmpIdx );
// count of samples past the end of the LA buffer to be wrapped into begin of buffer
unsigned n1 = srcSmpCnt>n0 ? srcSmpCnt-n0 : 0;
assert(n0+n1 == srcSmpCnt);
// copy first block to end of LA buffer
for(i=0; i<chCnt; ++i)
cmVOS_Copy(p->laChs[i]+p->laSmpIdx,n0,iChs[i] + srcOffs);
p->laSmpIdx += n0;
if( n1!=0)
{
// copy second block to begin of LA buffer
for(i=0; i<chCnt; ++i)
cmVOS_Copy(p->laChs[i],n1,iChs[i] + srcOffs + n0);
p->laSmpIdx = n1;
}
//-------------------------------------------------------------------
// copy incoming audio into the active record buffers
//
cmRecdPlayFrag* fp = p->rlist;
for(; fp!=NULL; fp=fp->rlink)
{
assert( fp->recdIdx <= fp->allocCnt);
unsigned n = cmMin(fp->allocCnt - fp->recdIdx,smpCnt);
unsigned i;
for(i=0; i<p->chCnt; ++i)
{
cmVOS_Copy(fp->chArray[i] + fp->recdIdx, n, iChs[i] );
fp->recdIdx += n;
}
}
//-------------------------------------------------------------------
// copy outgoing audio out of the active play buffers
//
fp = p->plist;
for(; fp!=NULL; fp=fp->rlink)
{
assert( fp->playIdx <= fp->recdIdx);
double gain = pow(10.0,((fp->fadeSmpIdx / p->srate) * fp->fadeDbPerSec)/20.0);
unsigned n = cmMin(fp->recdIdx - fp->playIdx,smpCnt);
unsigned i;
for(i=0; i<p->chCnt; ++i)
{
cmVOS_MultVVS(oChs[i],n,fp->chArray[i] + fp->playIdx,gain);
fp->playIdx += n;
}
// if a fade rate has been set then advance the fade phase
if(fp->fadeDbPerSec!=0.0)
fp->fadeSmpIdx += smpCnt;
}
return cmOkRC;
}

View File

@ -626,6 +626,55 @@ extern "C" {
cmRC_t cmScModulatorExec( cmScModulator* p, unsigned scLocIdx );
cmRC_t cmScModulatorDump( cmScModulator* p );
//=======================================================================================================================
typedef struct cmRecdPlayFrag_str
{
unsigned labelSymId; // this fragments label
cmSample_t** chArray; // record buffer chArray[cmRecdPlay.chCnt][allocCnt]
unsigned allocCnt; // count of samples allocated to each channel
unsigned playIdx; // index of next sample to play
unsigned recdIdx; // index of next sample to receieve audio (count of full samples)
double fadeDbPerSec; // fade rate in dB per second
unsigned fadeSmpIdx;
struct cmRecdPlayFrag_str* rlink; // cmRecdPlay.rlist link
struct cmRecdPlayFrag_str* plink; // cmRecdPlay.plist link
} cmRecdPlayFrag;
typedef struct
{
cmObj obj;
cmRecdPlayFrag* frags; // frags[fragCnt] fragment array
unsigned fragCnt; // count of fragments
double srate; // system sample rate
unsigned chCnt; // count of input and output audio channels
double initFragSecs; // size initial memory allocated to each frag in seconds
unsigned maxLaSmpCnt; // samples allocated to each channel of the look-ahead buffers.
unsigned curLaSmpCnt; // current look-ahead time in samples (curLaSmpCnt<=maxLaSmpCnt)
cmSample_t** laChs; // laChs[chCnt][maxLaSmpCnt] - look-ahead buffers
int laSmpIdx; // next look-ahead buffer index to receive a sample
cmRecdPlayFrag* plist; // currently playing frags
cmRecdPlayFrag* rlist; // currently recording frags
} cmRecdPlay;
cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs );
cmRC_t cmRecdPlayFree( cmRecdPlay** pp );
cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned flagCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs );
cmRC_t cmRecdPlayFinal( cmRecdPlay* p );
cmRC_t cmRecdPlayRegisterFrag( cmRecdPlay* p, unsigned fragIdx, unsigned labelSymId );
cmRC_t cmRecdPlayRewind( cmRecdPlay* p );
cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId );
cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId );
cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId );
cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId );
cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec );
cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt );
#ifdef __cplusplus
}
#endif

View File

@ -42,12 +42,15 @@ extern "C" {
const void* cmStackTop( cmStackH_t h );
// Set the value of 'dataEleCnt' elements on the stack.
// The top element is at index cmStackCount() - 1.
cmStRC_t cmStackSet( cmStackH_t h, unsigned index, const void* data, unsigned dataEleCnt );
// Copy 'dataEleCnt' elements into the buffer pointed to by 'data'.
// The top element is at index cmStackCount() - 1.
cmStRC_t cmStackGetN( cmStackH_t h, unsigned index, void* data, unsigned dataEleCnt );
// Return a pointer to a single element on the stack.
// The top element is at index cmStackCount() - 1.
const void* cmStackGet( cmStackH_t h, unsigned index );
// Convert the internal representation of the stack to a linear array and return

View File

@ -5418,6 +5418,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] =
cmActiveMeasClassCons,
cmAmSyncClassCons,
cmNanoMapClassCons,
cmRecdPlayClassCons,
NULL,
};

View File

@ -572,7 +572,7 @@ cmDspRC_t _cmDspScoreReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t*
}
if((tlFn = cmDspStrcz(inst, kFnScId )) != NULL )
if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, cmDspSampleRate(ctx), dynRefArray, dynRefCnt, _cmDspScoreCb, p, cmSymTblNullHandle ) != kOkTlRC )
if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, cmDspSampleRate(ctx), dynRefArray, dynRefCnt, _cmDspScoreCb, p, ctx->stH ) != kOkTlRC )
rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Score file open failed.");
errLabel:
@ -2264,3 +2264,262 @@ struct cmDspClass_str* cmNanoMapClassCons( cmDspCtx_t* ctx )
return &_cmNanoMapDC;
}
//==========================================================================================================================================
enum
{
kChCntPrId,
kFnPrId,
kSecsPrId,
kMaxLaSecsPrId,
kCurLaSecsPrId,
kFadeRatePrId,
kScLocIdxPrId,
kCmdPrId,
kInAudioBasePrId
};
cmDspClass_t _cmRecdPlayDC;
typedef struct
{
cmDspInst_t inst;
cmRecdPlay* rcdply;
cmScH_t scH;
unsigned onSymId;
unsigned offSymId;
unsigned audioOutBaseId;
unsigned chCnt;
unsigned scLocIdx;
} cmDspRecdPlay_t;
cmDspRC_t _cmDspRecdPlayOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst )
{
cmDspRC_t rc =kOkDspRC;
const cmChar_t* fn;
cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst;
p->scLocIdx = 0;
if((fn = cmDspStrcz(inst,kFnPrId)) == NULL || strlen(fn)==0 )
return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied.");
if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, cmDspSampleRate(ctx), NULL, 0, NULL, NULL, ctx->stH ) != kOkScRC )
return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn);
if( cmScoreIsValid(p->scH) )
{
unsigned i;
unsigned markerCnt = cmScoreMarkerLabelCount(p->scH);
double initFragSecs = cmDspDouble(inst,kSecsPrId);
double maxLaSecs = cmDspDouble(inst,kMaxLaSecsPrId);
double curLaSecs = cmDspDouble(inst,kCurLaSecsPrId);
if((p->rcdply = cmRecdPlayAlloc(ctx->cmProcCtx, NULL, cmDspSampleRate(ctx), markerCnt, p->chCnt, initFragSecs, maxLaSecs, curLaSecs)) == NULL)
return cmErrMsg(&inst->classPtr->err,kSubSysFailDspRC,"Unable to create the internal recorder-player object.");
for(i=0; i<markerCnt; ++i)
cmRecdPlayRegisterFrag(p->rcdply,i, cmScoreMarkerLabelSymbolId(p->scH,i ));
}
return rc;
}
cmDspInst_t* _cmDspRecdPlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
{
if( va_cnt < 1 )
{
cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'RecdPlay' constructor must have a count of input ports.");
return NULL;
}
va_list vl1;
va_copy(vl1,vl);
int chCnt = va_arg(vl,int);
unsigned audioOutBase = kInAudioBasePrId + chCnt;
cmDspRecdPlay_t* p = cmDspInstAllocV(cmDspRecdPlay_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
1, "chs", kChCntPrId, 0,0, kUIntDsvFl | kReqArgDsvFl, "channel count.",
1, "fn", kFnPrId, 0,0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." ,
1, "secs", kSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Initial fragment allocation in seconds.",
1, "maxla", kMaxLaSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl, "Maximum look-ahead buffer in seconds.",
1, "curla", kCurLaSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl, "Current look-head buffer in seconds.",
1, "frate", kFadeRatePrId, 0,0, kInDsvFl | kDoubleDsvFl, "Fade rate in dB per second.",
1, "index", kScLocIdxPrId, 0,0, kInDsvFl | kUIntDsvFl, "Score follower location index.",
1, "cmd", kCmdPrId, 0,0, kInDsvFl | kSymDsvFl, "on=reset off=stop.",
chCnt, "in", kInAudioBasePrId,0,1, kInDsvFl | kAudioBufDsvFl, "Audio input",
chCnt, "out", audioOutBase, 0,1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
0 );
va_end(vl1);
p->onSymId = cmSymTblId(ctx->stH,"on");
p->offSymId = cmSymTblId(ctx->stH,"off");
p->audioOutBaseId = audioOutBase;
p->chCnt = chCnt;
p->scLocIdx = 0;
cmDspSetDefaultDouble(ctx,&p->inst, kSecsPrId, 0, 10.0 );
cmDspSetDefaultDouble(ctx,&p->inst, kMaxLaSecsPrId,0, 2.0);
cmDspSetDefaultDouble(ctx,&p->inst, kCurLaSecsPrId,0, 0.5);
cmDspSetDefaultDouble(ctx,&p->inst, kFadeRatePrId, 0, 1.0);
return &p->inst;
}
cmDspRC_t _cmDspRecdPlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
{
cmDspRC_t rc = kOkDspRC;
cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst;
cmRecdPlayFree(&p->rcdply);
cmScoreFinalize(&p->scH);
return rc;
}
cmDspRC_t _cmDspRecdPlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
{
cmDspApplyAllDefaults(ctx,inst);
return _cmDspRecdPlayOpenScore(ctx,inst);
}
cmDspRC_t _cmDspRecdPlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
{
cmDspRC_t rc = kOkDspRC;
cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst;
const cmSample_t* x[ p->chCnt ];
cmSample_t* y[ p->chCnt ];
unsigned n;
unsigned i;
unsigned actChCnt = 0;
for(i=0; i<p->chCnt; ++i)
{
if( i==0 )
n = cmDspAudioBufSmpCount(ctx,inst,kInAudioBasePrId+i,0);
else
{ assert( n == cmDspAudioBufSmpCount(ctx,inst,kInAudioBasePrId+i,0)); }
x[i] = cmDspAudioBuf(ctx,inst,kInAudioBasePrId+i,0);
if( x[i] != NULL )
{
y[i] = cmDspAudioBuf(ctx,inst,p->audioOutBaseId+i,0);
if( y[i] != NULL )
{
assert( n == cmDspAudioBufSmpCount(ctx,inst,p->audioOutBaseId+i,0));
cmVOS_Zero(y[i],n);
actChCnt += 1;
}
}
}
cmRecdPlayExec(p->rcdply,x,y,actChCnt,n);
return rc;
}
cmDspRC_t _cmDspRecdPlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
{
cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst;
cmDspSetEvent(ctx,inst,evt);
switch( evt->dstVarId )
{
case kCmdPrId:
if( cmDspSymbol(inst,kCmdPrId) == p->onSymId )
{
printf("rewind\n");
cmRecdPlayRewind(p->rcdply);
p->scLocIdx = 0;
}
else
if( cmDspSymbol(inst,kCmdPrId) == p->offSymId )
{
}
break;
case kCurLaSecsPrId:
break;
case kScLocIdxPrId:
{
unsigned endScLocIdx = cmDspUInt(inst,kScLocIdxPrId) ;
for(; p->scLocIdx<=endScLocIdx; p->scLocIdx+=1)
{
cmScoreLoc_t* loc = cmScoreLoc(p->scH, p->scLocIdx );
cmScoreMarker_t* mp = loc->markList;
for(; mp!=NULL; mp=mp->link)
switch( mp->markTypeId )
{
case kRecdBegScMId:
printf("recd-beg\n");
cmRecdPlayBeginRecord(p->rcdply, mp->labelSymId );
break;
case kRecdEndScMId:
printf("recd-end\n");
cmRecdPlayEndRecord(p->rcdply, mp->labelSymId );
break;
case kPlayBegScMId:
printf("play-beg\n");
cmRecdPlayBeginPlay(p->rcdply, mp->labelSymId );
break;
case kPlayEndScMId:
printf("play-end\n");
cmRecdPlayEndPlay(p->rcdply, mp->labelSymId );
break;
case kFadeScMId:
printf("fade-beg\n");
cmRecdPlayBeginFade(p->rcdply, mp->labelSymId, cmDspDouble(inst,kFadeRatePrId) );
break;
default:
break;
}
}
p->scLocIdx = endScLocIdx+1;
}
break;
}
return kOkDspRC;
}
struct cmDspClass_str* cmRecdPlayClassCons( cmDspCtx_t* ctx )
{
cmDspClassSetup(&_cmRecdPlayDC,ctx,"RecdPlay",
NULL,
_cmDspRecdPlayAlloc,
_cmDspRecdPlayFree,
_cmDspRecdPlayReset,
_cmDspRecdPlayExec,
_cmDspRecdPlayRecv,
NULL,
NULL,
"Score controlled live recorder/player");
return &_cmRecdPlayDC;
}

View File

@ -16,6 +16,7 @@ extern "C" {
struct cmDspClass_str* cmActiveMeasClassCons( cmDspCtx_t* ctx );
struct cmDspClass_str* cmAmSyncClassCons( cmDspCtx_t* ctx );
struct cmDspClass_str* cmNanoMapClassCons( cmDspCtx_t* ctx );
struct cmDspClass_str* cmRecdPlayClassCons( cmDspCtx_t* ctx );
#ifdef __cplusplus
}

View File

@ -97,7 +97,10 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
double cmpWndMaxMs = 1000.0;
double cmpWndMs = 200.0;
double recdPlayInitAllocSecs = 10.0;
double recdPlayMaxLaSecs = 2.0;
double recdPlayCurLaSecs = 0.1;
double recdPlayFadeRateDbPerSec = 4.0;
memset(&r,0,sizeof(r));
cmErrSetup(&err,&cmCtx->rpt,"Kr Timeline");
@ -122,6 +125,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspInst_t* mop = cmDspSysAllocInst(h,"MidiOut", NULL, 2, r.midiDevice,r.midiOutPort);
cmDspInst_t* sfp = cmDspSysAllocInst(h,"ScFol", NULL, 1, r.scFn );
cmDspInst_t* amp = cmDspSysAllocInst(h,"ActiveMeas", NULL, 1, 100 );
cmDspInst_t* rpp = cmDspSysAllocInst(h,"RecdPlay", NULL, 4, 2, r.scFn, recdPlayInitAllocSecs, recdPlayMaxLaSecs, recdPlayCurLaSecs, recdPlayFadeRateDbPerSec );
cmDspInst_t* modp = cmDspSysAllocInst(h,"ScMod", NULL, 2, r.modFn, "m1" );
cmDspInst_t* asp = cmDspSysAllocInst(h,"AmSync", NULL, 0 );
@ -173,14 +177,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspInst_t* kr00 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact );
cmDspInst_t* kr01 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact );
cmDspInst_t* fad0 = cmDspSysAllocInst(h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl );
cmDspInst_t* mix0 = cmDspSysAllocInst(h, "AMix", NULL, 3, xfadeChCnt, mixGain, mixGain );
cmDspInst_t* mix0 = cmDspSysAllocInst(h, "AMix", NULL, 4, xfadeChCnt+1, mixGain, mixGain, mixGain );
cmDspInst_t* cmp0 = cmDspSysAllocInst(h,"Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs );
cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 );
cmDspInst_t* kr10 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact );
cmDspInst_t* kr11 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact );
cmDspInst_t* fad1 = cmDspSysAllocInst(h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl );
cmDspInst_t* mix1 = cmDspSysAllocInst(h, "AMix", NULL, 3, xfadeChCnt, mixGain, mixGain );
cmDspInst_t* mix1 = cmDspSysAllocInst(h, "AMix", NULL, 4, xfadeChCnt+1, mixGain, mixGain, mixGain );
cmDspInst_t* cmp1 = cmDspSysAllocInst(h,"Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs );
cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 );
@ -378,12 +382,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspSysConnectAudio(h, wtp, "out", au0Sw, "a-in-0" ); // wt -> sw
cmDspSysConnectAudio(h, ai0p, "out", au0Sw, "a-in-1" ); // ain -> sw
cmDspSysConnectAudio(h, ai0p, "out", mi0p, "in" );
cmDspSysConnectAudio(h, au0Sw,"a-out", rpp, "in-0"); // sw -> rcdply
cmDspSysConnectAudio(h, au0Sw,"a-out", kr00, "in" ); // sw -> kr
cmDspSysConnectAudio(h, kr00, "out", fad0, "in-0"); // kr -> fad
cmDspSysConnectAudio(h, fad0, "out-0", mix0, "in-0"); // fad -> mix
cmDspSysConnectAudio(h, au0Sw,"a-out", kr01, "in" ); // sw -> kr
cmDspSysConnectAudio(h, kr01, "out", fad0, "in-1"); // kr -> fad
cmDspSysConnectAudio(h, fad0, "out-1", mix0, "in-1"); // fad -> mix
cmDspSysConnectAudio(h, rpp, "out-0", mix0, "in-2");
cmDspSysConnectAudio(h, mix0, "out", cmp0, "in"); // mix -> cmp
cmDspSysConnectAudio(h, cmp0, "out", ao0p, "in" ); // cmp -> aout
@ -391,12 +397,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspSysConnectAudio(h, wtp, "out", au1Sw, "a-in-0" ); // wt -> kr
cmDspSysConnectAudio(h, ai1p, "out", au1Sw, "a-in-1" );
cmDspSysConnectAudio(h, ai1p, "out", mi1p, "in" );
cmDspSysConnectAudio(h, au1Sw,"a-out", rpp, "in-1"); // sw -> rcdply
cmDspSysConnectAudio(h, au1Sw,"a-out", kr10, "in" );
cmDspSysConnectAudio(h, kr10, "out", fad1, "in-0");
cmDspSysConnectAudio(h, fad1, "out-0", mix1, "in-0");
cmDspSysConnectAudio(h, au1Sw,"a-out", kr11, "in" ); // wt -> kr
cmDspSysConnectAudio(h, kr11, "out", fad1, "in-1");
cmDspSysConnectAudio(h, fad1, "out-1", mix1, "in-1");
cmDspSysConnectAudio(h, rpp, "out-0", mix1, "in-2");
cmDspSysConnectAudio(h, mix1, "out", cmp1, "in");
cmDspSysConnectAudio(h, cmp1, "out", ao1p, "in" ); // comp -> aout
@ -437,6 +445,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspSysInstallCb(h, pts, "on", wtRt, "s-in", NULL );
cmDspSysInstallCb(h, wtRt,"s-out-0", wtp, "cmd", NULL );
cmDspSysInstallCb(h, pts, "on", modp, "cmd", NULL );
cmDspSysInstallCb(h, pts, "on", rpp, "cmd", NULL );
cmDspSysInstallCb(h, onb, "sym", amCmd, "rewind",NULL );
cmDspSysInstallCb(h, onb, "out", achan0,"reset", NULL );
cmDspSysInstallCb(h, onb, "out", achan1,"reset", NULL );
@ -493,7 +502,8 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
cmDspSysInstallCb(h, mip, "d0", sfp, "d0", NULL );
cmDspSysInstallCb(h, mip, "status", sfp, "status", NULL );
// score follower to modulator and printers
// score follower to recd_play,modulator and printers
cmDspSysInstallCb(h, sfp, "out", rpp, "index", NULL );
cmDspSysInstallCb(h, sfp, "out", modp, "index", NULL );
cmDspSysInstallCb(h, sfp, "recent", prp, "in", NULL ); // report 'recent' but only act on 'max' loc index