Merge branch 'master' of klarke.webfactional.com:webapps/git/repos/libcm
This commit is contained in:
commit
6d317d54ca
10
Makefile.am
10
Makefile.am
@ -6,8 +6,11 @@ cmSRC =
|
||||
cmHDR += src/libcm/cmErr.h src/libcm/cmCtx.h src/libcm/cmRpt.h src/libcm/cmGlobal.h src/libcm/cmComplexTypes.h src/libcm/cmFloatTypes.h src/libcm/cmPrefix.h
|
||||
cmSRC += src/libcm/cmErr.c src/libcm/cmCtx.c src/libcm/cmRpt.c src/libcm/cmGlobal.c
|
||||
|
||||
cmHDR += src/libcm/cmSerialize.h src/libcm/cmSymTbl.h src/libcm/cmFileSys.h src/libcm/cmFile.h src/libcm/cmMem.h src/libcm/cmTime.h src/libcm/cmPgmOpts.h
|
||||
cmSRC += src/libcm/cmSerialize.c src/libcm/cmSymTbl.c src/libcm/cmFileSys.c src/libcm/cmFile.c src/libcm/cmMem.c src/libcm/cmTime.c src/libcm/cmPgmOpts.c
|
||||
cmHDR += src/libcm/cmSerialize.h src/libcm/cmSymTbl.h src/libcm/cmHashTbl.h src/libcm/cmFileSys.h src/libcm/cmFile.h
|
||||
cmSRC += src/libcm/cmSerialize.c src/libcm/cmSymTbl.c src/libcm/cmHashTbl.c src/libcm/cmFileSys.c src/libcm/cmFile.c
|
||||
|
||||
cmHDR += src/libcm/cmMem.h src/libcm/cmTime.h src/libcm/cmPgmOpts.h
|
||||
cmSRC += src/libcm/cmMem.c src/libcm/cmTime.c src/libcm/cmPgmOpts.c
|
||||
|
||||
cmHDR += src/libcm/cmData.h src/libcm/cmLib.h src/libcm/cmText.h src/libcm/cmTextTemplate.h
|
||||
cmSRC += src/libcm/cmData.c src/libcm/cmLib.c src/libcm/cmText.c src/libcm/cmTextTemplate.c
|
||||
@ -71,6 +74,9 @@ cmSRC += src/libcm/cmProcObj.c src/libcm/cmProc.c src/libcm/cmProc2.c src/libcm/
|
||||
cmHDR += src/libcm/app/cmOnset.h src/libcm/app/cmTimeLine.h src/libcm/app/cmScore.h src/libcm/app/cmScoreProc.h
|
||||
cmSRC += src/libcm/app/cmOnset.c src/libcm/app/cmTimeLine.c src/libcm/app/cmScore.c src/libcm/app/cmScoreProc.c
|
||||
|
||||
cmHDR += src/libcm/app/cmSdb.h
|
||||
cmSRC += src/libcm/app/cmSdb.c
|
||||
|
||||
cmHDR += src/libcm/app/cmPickup.h src/libcm/cmRbm.h src/libcm/cmTaskMgr.h src/libcm/cmSyncRecd.h
|
||||
cmSRC += src/libcm/app/cmPickup.c src/libcm/cmRbm.c src/libcm/cmTaskMgr.c src/libcm/cmSyncRecd.c
|
||||
|
||||
|
724
app/cmSdb.c
Normal file
724
app/cmSdb.c
Normal file
@ -0,0 +1,724 @@
|
||||
#include "cmGlobal.h"
|
||||
#include "cmRpt.h"
|
||||
#include "cmErr.h"
|
||||
#include "cmCtx.h"
|
||||
#include "cmMem.h"
|
||||
#include "cmMallocDebug.h"
|
||||
#include "cmLinkedHeap.h"
|
||||
#include "cmLex.h"
|
||||
#include "cmCsv.h"
|
||||
#include "cmSdb.h"
|
||||
#include "cmText.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kUuidColIdx,
|
||||
kBaseUuidColIdx,
|
||||
kChIdxColIdx,
|
||||
kObiColIdx,
|
||||
kIbiColIdx,
|
||||
kIeiColIdx,
|
||||
kOeiColIdx,
|
||||
kSrcColIdx,
|
||||
kMidiColIdx,
|
||||
kInstrColIdx,
|
||||
kSrateColIdx,
|
||||
kChCntColIdx,
|
||||
kNotesColIdx,
|
||||
kAfnColIdx,
|
||||
kInvalidColIdx
|
||||
} cmSdbColIdx_t;
|
||||
|
||||
struct cmSdb_str;
|
||||
|
||||
typedef struct cmSdbRspBlk_str
|
||||
{
|
||||
unsigned* indexV; // indexV[ cmSdb_t.blkIdxAllocCnt ]
|
||||
unsigned cnt; // count of indexes used
|
||||
struct cmSdbRspBlk_str* link; // cmSdbRsp_t.blocks link
|
||||
} cmSdbRspBlk_t;
|
||||
|
||||
typedef struct cmSdbRsp_str
|
||||
{
|
||||
struct cmSdb_str* p; //
|
||||
cmSdbRspBlk_t* blocks; // first block ptr
|
||||
cmSdbRspBlk_t* ebp; // end block ptr
|
||||
unsigned cnt; // total count of indexes
|
||||
struct cmSdbRsp_str* link; // cmSdb_t.responses link
|
||||
} cmSdbRsp_t;
|
||||
|
||||
typedef struct cmSdb_str
|
||||
{
|
||||
cmCtx_t ctx;
|
||||
cmLHeapH_t lhH;
|
||||
cmCsvH_t csvH;
|
||||
cmSdbEvent_t* eV;
|
||||
unsigned eN;
|
||||
unsigned blkIdxAllocCnt;
|
||||
struct cmSdbRsp_str* responses;
|
||||
} cmSdb_t;
|
||||
|
||||
cmSdbH_t cmSdbNullHandle = cmSTATIC_NULL_HANDLE;
|
||||
cmSdbResponseH_t cmSdbResponseNullHandle = cmSTATIC_NULL_HANDLE;
|
||||
|
||||
cmSdb_t* _cmSdbHandleToPtr( cmSdbH_t h )
|
||||
{
|
||||
cmSdb_t* p = (cmSdb_t*)h.h;
|
||||
assert( p != NULL );
|
||||
return p;
|
||||
}
|
||||
|
||||
cmSdbRsp_t* _cmSdbRspHandleToPtr( cmSdbResponseH_t h )
|
||||
{
|
||||
cmSdbRsp_t* p = (cmSdbRsp_t*)h.h;
|
||||
assert( p != NULL );
|
||||
return p;
|
||||
}
|
||||
|
||||
void _cmSdbRspBlkFree( cmSdb_t* p, cmSdbRspBlk_t* bp )
|
||||
{
|
||||
cmLhFree(p->lhH, bp->indexV);
|
||||
cmLhFree(p->lhH, bp);
|
||||
}
|
||||
|
||||
|
||||
cmSdbRspBlk_t* _cmSdbRspBlkUnlink( cmSdbRsp_t* rp, cmSdbRspBlk_t* bp )
|
||||
{
|
||||
cmSdbRspBlk_t* dp = rp->blocks;
|
||||
cmSdbRspBlk_t* pp = NULL;
|
||||
for(; dp!=NULL; dp=dp->link)
|
||||
{
|
||||
if( dp == bp )
|
||||
{
|
||||
if( pp == NULL )
|
||||
rp->blocks = dp->link;
|
||||
else
|
||||
pp->link = dp->link;
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
pp = dp;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _cmSdbRspInsertIndex( cmSdb_t* p, cmSdbRsp_t* rp, unsigned evtIndex )
|
||||
{
|
||||
|
||||
if( rp->ebp == NULL || rp->ebp->cnt == p->blkIdxAllocCnt )
|
||||
{
|
||||
cmSdbRspBlk_t* bp = cmLhAllocZ(p->lhH,cmSdbRspBlk_t,1);
|
||||
bp->indexV = cmLhAllocZ(p->lhH,unsigned,p->blkIdxAllocCnt);
|
||||
|
||||
if( rp->ebp != NULL )
|
||||
rp->ebp->link = bp;
|
||||
|
||||
if( rp->blocks == NULL )
|
||||
rp->blocks = bp;
|
||||
|
||||
rp->ebp = bp;
|
||||
|
||||
}
|
||||
|
||||
assert( rp->ebp!=NULL && rp->ebp->cnt < p->blkIdxAllocCnt );
|
||||
|
||||
rp->ebp->indexV[ rp->ebp->cnt++ ] = evtIndex;
|
||||
rp->cnt += 1;
|
||||
}
|
||||
|
||||
void _cmSdbRspRelease( cmSdbRsp_t* rp )
|
||||
{
|
||||
while( rp->blocks != NULL )
|
||||
{
|
||||
cmSdbRspBlk_t* np = rp->blocks->link;
|
||||
cmSdbRspBlk_t* bp;
|
||||
|
||||
if((bp = _cmSdbRspBlkUnlink(rp,rp->blocks)) != NULL )
|
||||
_cmSdbRspBlkFree(rp->p,bp);
|
||||
|
||||
rp->blocks = np;
|
||||
}
|
||||
|
||||
cmLhFree(rp->p->lhH,rp);
|
||||
}
|
||||
|
||||
cmSdbRsp_t* _cmSdbRspUnlink( cmSdbRsp_t* rp )
|
||||
{
|
||||
cmSdb_t* p = rp->p;
|
||||
cmSdbRsp_t* dp = p->responses;
|
||||
cmSdbRsp_t* pp = NULL;
|
||||
|
||||
for(; dp!=NULL; dp=dp->link)
|
||||
{
|
||||
if( dp == rp )
|
||||
{
|
||||
if( pp == NULL )
|
||||
p->responses = dp->link;
|
||||
else
|
||||
pp->link = dp->link;
|
||||
|
||||
return rp;
|
||||
}
|
||||
|
||||
pp = dp;
|
||||
}
|
||||
|
||||
assert( 0 );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void _cmSdbRspFree( cmSdbRsp_t* rp )
|
||||
{
|
||||
_cmSdbRspUnlink(rp);
|
||||
_cmSdbRspRelease(rp);
|
||||
}
|
||||
|
||||
cmSdbRsp_t* _cmSdbRspAlloc( cmSdb_t* p, cmSdbResponseH_t* rhp )
|
||||
{
|
||||
if( cmSdbResponseFree(rhp) != kOkSdbRC )
|
||||
return NULL;
|
||||
|
||||
cmSdbRsp_t* rp = cmLhAllocZ(p->lhH,cmSdbRsp_t,1);
|
||||
rp->p = p;
|
||||
rp->link = p->responses;
|
||||
p->responses = rp;
|
||||
|
||||
rhp->h = rp;
|
||||
|
||||
return rp;
|
||||
}
|
||||
|
||||
cmSdbRC_t _cmSdbDestroy( cmSdb_t* p )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
|
||||
if( cmCsvFinalize(&p->csvH) != kOkCsvRC )
|
||||
rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file finalize failed.");
|
||||
|
||||
while( p->responses != NULL )
|
||||
_cmSdbRspRelease(p->responses);
|
||||
|
||||
cmLHeapDestroy(&p->lhH);
|
||||
cmMemFree(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSdbRC_t cmSdbCreate( cmCtx_t* ctx, cmSdbH_t* hp, const cmChar_t* audioDir, const cmChar_t* csvFn )
|
||||
{
|
||||
cmSdbRC_t rc;
|
||||
if((rc = cmSdbDestroy(hp)) != kOkSdbRC )
|
||||
return rc;
|
||||
|
||||
cmSdb_t* p = cmMemAllocZ(cmSdb_t,1);
|
||||
p->ctx = *ctx;
|
||||
p->blkIdxAllocCnt = 1024;
|
||||
|
||||
cmErrSetup(&p->ctx.err,&ctx->rpt,"sdb");
|
||||
|
||||
if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8192,ctx)) == false )
|
||||
{
|
||||
rc = cmErrMsg(&p->ctx.err,kLHeapFailSdbRC,"Linked heap mgr. allocation failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
hp->h = p;
|
||||
|
||||
if( csvFn != NULL )
|
||||
if((rc = cmSdbLoad(*hp,csvFn)) != kOkSdbRC )
|
||||
goto errLabel;
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkSdbRC )
|
||||
_cmSdbDestroy(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSdbRC_t cmSdbDestroy( cmSdbH_t* hp )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
|
||||
if( hp==NULL || cmSdbIsValid(*hp)==false )
|
||||
return rc;
|
||||
|
||||
cmSdb_t* p = _cmSdbHandleToPtr(*hp);
|
||||
|
||||
if((rc = _cmSdbDestroy(p)) != kOkSdbRC )
|
||||
return rc;
|
||||
|
||||
hp->h = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool cmSdbIsValid( cmSdbH_t h )
|
||||
{ return h.h != NULL; }
|
||||
|
||||
|
||||
cmSdbRC_t _cmSdbSyntaxError(cmSdb_t* p, const cmChar_t* csvFn, unsigned rowIdx, unsigned colIdx, const cmChar_t* colLabel )
|
||||
{
|
||||
return cmErrMsg(&p->ctx.err,kSyntaxErrSdbRC,"A syntax error was found at row %i col %i (label:%s) in '%s'.",rowIdx+1,colIdx+1,cmStringNullGuard(colLabel),cmStringNullGuard(csvFn));
|
||||
}
|
||||
|
||||
|
||||
cmSdbRC_t cmSdbLoad( cmSdbH_t h, const cmChar_t* csvFn )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
unsigned i;
|
||||
|
||||
cmSdb_t* p = _cmSdbHandleToPtr(h);
|
||||
|
||||
if( cmCsvInitializeFromFile(&p->csvH, csvFn, 0, &p->ctx ) != kOkCsvRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->ctx.err,kCsvFailSdbRC,"CSV file load fail on '%s'.",cmStringNullGuard(csvFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
p->eN = cmCsvRowCount(p->csvH)-1;
|
||||
|
||||
// release all the memory held by the linked heap
|
||||
cmLHeapClear(p->lhH,true);
|
||||
|
||||
p->eV = cmLhAllocZ(p->lhH,cmSdbEvent_t,p->eN);
|
||||
|
||||
|
||||
for(i=0; rc==kOkSdbRC && i<p->eN; ++i)
|
||||
{
|
||||
unsigned rowIdx = i+1;
|
||||
|
||||
if((p->eV[i].uuid = cmCsvCellUInt(p->csvH,rowIdx,kUuidColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kUuidColIdx,"uuid");
|
||||
|
||||
if((p->eV[i].baseUuid = cmCsvCellUInt(p->csvH,rowIdx,kBaseUuidColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kBaseUuidColIdx,"baseUuid");
|
||||
|
||||
if((p->eV[i].chIdx = cmCsvCellUInt(p->csvH,rowIdx,kChIdxColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChIdxColIdx,"chIdx");
|
||||
else
|
||||
p->eV[i].chIdx -= 1; // CSV channel index is 1 based
|
||||
|
||||
if((p->eV[i].obi = cmCsvCellUInt(p->csvH,rowIdx,kObiColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kObiColIdx,"obi");
|
||||
else
|
||||
p->eV[i].obi -= 1;
|
||||
|
||||
if((p->eV[i].ibi = cmCsvCellUInt(p->csvH,rowIdx,kIbiColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIbiColIdx,"ibi");
|
||||
else
|
||||
p->eV[i].ibi -= 1;
|
||||
|
||||
if((p->eV[i].iei = cmCsvCellUInt(p->csvH,rowIdx,kIeiColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kIeiColIdx,"obi");
|
||||
else
|
||||
p->eV[i].iei -= 1;
|
||||
|
||||
if((p->eV[i].oei = cmCsvCellUInt(p->csvH,rowIdx,kOeiColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kOeiColIdx,"ibi");
|
||||
else
|
||||
p->eV[i].oei -= 1;
|
||||
|
||||
if((p->eV[i].src = cmCsvCellText(p->csvH,rowIdx,kSrcColIdx)) == NULL )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrcColIdx,"src");
|
||||
|
||||
if((p->eV[i].midi = cmCsvCellInt(p->csvH,rowIdx,kMidiColIdx)) == INT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kMidiColIdx,"midi");
|
||||
|
||||
if((p->eV[i].instr = cmCsvCellText(p->csvH,rowIdx,kInstrColIdx)) == NULL )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kInstrColIdx,"instr");
|
||||
|
||||
if((p->eV[i].srate = cmCsvCellUInt(p->csvH,rowIdx,kSrateColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kSrateColIdx,"srate");
|
||||
|
||||
if((p->eV[i].chCnt = cmCsvCellUInt(p->csvH,rowIdx,kChCntColIdx)) == UINT_MAX )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kChCntColIdx,"chCnt");
|
||||
|
||||
|
||||
cmCsvCell_t* c;
|
||||
if((c = cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx)) == NULL )
|
||||
{
|
||||
rc = cmErrMsg(&p->ctx.err,kSyntaxErrSdbRC,"Syntax Error: No 'notes' or 'audio file name' field for row %i in '%s'.",rowIdx+1,cmStringNullGuard(csvFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// count the number of 'notes'
|
||||
unsigned nn = 0;
|
||||
for(; c->rowPtr != NULL; c=c->rowPtr)
|
||||
++nn;
|
||||
|
||||
if( nn > 0 )
|
||||
{
|
||||
unsigned k = 0;
|
||||
|
||||
// allocate the 'notes' ptr array - the last entry is set to NULL.
|
||||
p->eV[i].notesV = cmLhAllocZ(p->lhH,const cmChar_t*,nn+1);
|
||||
|
||||
// read each note
|
||||
for(c=cmCsvCellPtr(p->csvH,rowIdx,kNotesColIdx); c!=NULL&&c->rowPtr!=NULL; c=c->rowPtr,++k)
|
||||
if(( p->eV[i].notesV[k] = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+k)) == NULL )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+k,"notes");
|
||||
|
||||
assert(k==nn);
|
||||
}
|
||||
|
||||
// read the audio file name
|
||||
if((p->eV[i].afn = cmCsvCellText(p->csvH,rowIdx,kNotesColIdx+nn)) == NULL )
|
||||
rc = _cmSdbSyntaxError(p,csvFn,rowIdx,kNotesColIdx+nn,"afn");
|
||||
|
||||
}
|
||||
|
||||
errLabel:
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
// Compare 'label' to every string in tV[i] and return true if any comparision is a match.
|
||||
// If 'subFlV[i]' is set then 'label' must only contain tV[i] as a substring to match.
|
||||
// If 'negFlV[i]' is set then return true if any comparision is a mismatch.
|
||||
bool _cmSdbSelectText( const cmSdbEvent_t* r, const cmChar_t** tV, const bool* subFlV, const bool* negFlV, const cmChar_t* label )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if( label == NULL )
|
||||
return false;
|
||||
|
||||
if( tV == NULL )
|
||||
return true;
|
||||
|
||||
for(i=0; tV[i]!=NULL; ++i)
|
||||
{
|
||||
bool matchFl = false;
|
||||
if( subFlV[i] )
|
||||
matchFl = strstr(label,tV[i]) != NULL;
|
||||
else
|
||||
matchFl = strcmp(tV[i],label)==0;
|
||||
|
||||
if( negFlV[i] )
|
||||
matchFl = !matchFl;
|
||||
|
||||
if(matchFl)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned _cmSdbStrVectCnt( const cmChar_t** v )
|
||||
{
|
||||
unsigned n = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
if( v == NULL )
|
||||
return 0;
|
||||
|
||||
for(i=0; v[i]!=NULL; ++i)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
void _cmSdbStrVectFlags( const cmChar_t** v, bool* sV, bool* nV )
|
||||
{
|
||||
unsigned i = 0;
|
||||
if( v == NULL )
|
||||
return;
|
||||
|
||||
for(i=0; v[i]!=NULL; ++i)
|
||||
{
|
||||
nV[i] = false;
|
||||
sV[i] = false;
|
||||
|
||||
if( strncmp(v[i],"*!",2)==0 || strncmp(v[i],"!*",2)==0)
|
||||
{
|
||||
sV[i] = nV[i] = true;
|
||||
v[i] += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( strncmp(v[i],"!",1)==0 )
|
||||
{
|
||||
nV[i] = true;
|
||||
v[i] += 1;
|
||||
}
|
||||
|
||||
if( strncmp(v[i],"*",1)==0 )
|
||||
{
|
||||
sV[i] = true;
|
||||
v[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
cmSdbRC_t cmSdbSelect(
|
||||
cmSdbH_t h,
|
||||
double srate,
|
||||
const cmChar_t** instrV,
|
||||
const cmChar_t** srcV,
|
||||
const cmChar_t** notesV,
|
||||
double minDurSec,
|
||||
double maxDurSec,
|
||||
unsigned minChCnt,
|
||||
cmSdbResponseH_t* rhp )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
cmSdb_t* p = _cmSdbHandleToPtr(h);
|
||||
unsigned i;
|
||||
|
||||
cmSdbRsp_t* rp = _cmSdbRspAlloc(p,rhp);
|
||||
|
||||
// get the length of each string vector
|
||||
unsigned srcN = _cmSdbStrVectCnt(srcV);
|
||||
unsigned insN = _cmSdbStrVectCnt(instrV);
|
||||
unsigned notN = _cmSdbStrVectCnt(notesV);
|
||||
|
||||
// allocate flag vectors
|
||||
bool srcSubFlV[ srcN ];
|
||||
bool srcNegFlV[ srcN ];
|
||||
bool insSubFlV[ insN ];
|
||||
bool insNegFlV[ insN ];
|
||||
bool notSubFlV[ notN ];
|
||||
bool notNegFlV[ notN ];
|
||||
|
||||
// fill the flag vectors
|
||||
_cmSdbStrVectFlags(srcV, srcSubFlV,srcNegFlV);
|
||||
_cmSdbStrVectFlags(instrV,insSubFlV,insNegFlV);
|
||||
_cmSdbStrVectFlags(notesV,notSubFlV,notNegFlV);
|
||||
|
||||
for(i=0; i<p->eN; ++i)
|
||||
{
|
||||
const cmSdbEvent_t* r = p->eV + i;
|
||||
double durSec = (double)r->srate * (r->oei - r->obi);
|
||||
unsigned j;
|
||||
|
||||
if( srate!=0 && srate!=r->srate )
|
||||
continue;
|
||||
|
||||
if( durSec < minDurSec || (maxDurSec!=0 && maxDurSec < durSec) )
|
||||
continue;
|
||||
|
||||
if( minChCnt!=0 && r->chCnt > minChCnt )
|
||||
continue;
|
||||
|
||||
if( !_cmSdbSelectText(r,srcV,srcSubFlV,srcNegFlV,r->src) )
|
||||
continue;
|
||||
|
||||
if( !_cmSdbSelectText(r,instrV,insSubFlV,insNegFlV,r->instr) )
|
||||
continue;
|
||||
|
||||
if( r->notesV != NULL )
|
||||
for(j=0; r->notesV[j]!=NULL; ++j)
|
||||
if( _cmSdbSelectText(r,notesV,notSubFlV,notNegFlV,r->notesV[j]) == true )
|
||||
break;
|
||||
|
||||
if( r->notesV[j]==NULL )
|
||||
continue;
|
||||
|
||||
|
||||
_cmSdbRspInsertIndex(p,rp,i);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSdbRC_t cmSdbSelectChPairs( cmSdbH_t h, const cmSdbEvent_t* ep, cmSdbResponseH_t* rhp )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
cmSdb_t* p = _cmSdbHandleToPtr(h);
|
||||
cmSdbRsp_t* rp = _cmSdbRspAlloc(p,rhp);
|
||||
unsigned i;
|
||||
|
||||
// for each channel of this event
|
||||
for(i=0; i<ep->chCnt; ++i)
|
||||
{
|
||||
// if i channel is not the known events channel
|
||||
if( ep->chIdx != i )
|
||||
{
|
||||
unsigned j;
|
||||
|
||||
// examine each record
|
||||
for(j=0; j<p->eN; ++j)
|
||||
// if eV[j] shares a baseUuid but is on a different channel than *ep ...
|
||||
if( p->eV[j].baseUuid == ep->baseUuid && p->eV[j].chIdx==i )
|
||||
{
|
||||
// .. then a match has been found
|
||||
_cmSdbRspInsertIndex(p,rp,j);
|
||||
break;
|
||||
}
|
||||
|
||||
if( j== p->eN )
|
||||
{
|
||||
rc = cmErrMsg(&p->ctx.err,kChPairNotFoundSdbRC,"The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found.",ep->uuid,cmStringNullGuard(ep->instr),cmStringNullGuard(ep->src),ep->chIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
unsigned cmSdbResponseCount( cmSdbResponseH_t rh )
|
||||
{
|
||||
cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
|
||||
return rp->cnt;
|
||||
}
|
||||
|
||||
const cmSdbEvent_t* cmSdbResponseEvent( cmSdbResponseH_t rh, unsigned index )
|
||||
{
|
||||
cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(rh);
|
||||
|
||||
if( index >= rp->cnt )
|
||||
return NULL;
|
||||
|
||||
cmSdbRspBlk_t* bp = rp->blocks;
|
||||
unsigned i;
|
||||
for(i=0; bp!=NULL; i+=bp->cnt,bp=bp->link)
|
||||
if( i <= index && index < (i + bp->cnt) )
|
||||
return rp->p->eV + bp->indexV[index-i];
|
||||
|
||||
cmErrMsg(&rp->p->ctx.err,kInvalidRspIdxSdbRC,"Invalid query response index=%i.",index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cmSdbResponseIsValid( cmSdbResponseH_t rh )
|
||||
{ return rh.h != NULL; }
|
||||
|
||||
cmSdbRC_t cmSdbResponseFree( cmSdbResponseH_t* rhp )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
|
||||
if( rhp == NULL || cmSdbResponseIsValid(*rhp)==false )
|
||||
return rc;
|
||||
|
||||
cmSdbRsp_t* rp = _cmSdbRspHandleToPtr(*rhp);
|
||||
|
||||
_cmSdbRspFree(rp);
|
||||
|
||||
rhp->h = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cmSdbResponsePrint( cmSdbResponseH_t rh, cmRpt_t* rpt )
|
||||
{
|
||||
unsigned n = cmSdbResponseCount(rh);
|
||||
unsigned i;
|
||||
for(i=0; i<n; ++i)
|
||||
{
|
||||
const cmSdbEvent_t* e = cmSdbResponseEvent(rh,i);
|
||||
if( e != NULL )
|
||||
cmRptPrintf(rpt,"%6i %6i %2i %12i %12i %12i %12i %2i %6i %2i %10s %15s\n",
|
||||
e->uuid,e->baseUuid,e->chIdx,e->obi,e->ibi,e->iei,e->oei,e->midi,e->srate,e->chCnt,
|
||||
cmStringNullGuard(e->src), cmStringNullGuard(e->instr) );
|
||||
}
|
||||
}
|
||||
|
||||
cmSdbRC_t cmSdbSyncChPairs( cmSdbH_t h )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
cmSdb_t* p = _cmSdbHandleToPtr(h);
|
||||
unsigned i;
|
||||
// for each multi-channel event
|
||||
for(i=0; i<p->eN; ++i)
|
||||
if(p->eV[i].chCnt > 1 )
|
||||
{
|
||||
const cmSdbEvent_t* ep = p->eV + i;
|
||||
unsigned iV[ep->chCnt];
|
||||
unsigned j,k;
|
||||
|
||||
// load iV[] with the event indexes of the channel pairs
|
||||
for(j=0,k=0; j<p->eN && k<ep->chCnt; ++j)
|
||||
if( p->eV[j].baseUuid == ep->baseUuid )
|
||||
{
|
||||
assert( p->eV[j].chIdx < ep->chCnt );
|
||||
|
||||
iV[p->eV[j].chIdx] = j;
|
||||
++k;
|
||||
}
|
||||
|
||||
if( k != ep->chCnt )
|
||||
rc = cmErrMsg(&p->ctx.err,kChPairNotFoundSdbRC,"The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found.",ep->uuid,cmStringNullGuard(ep->instr),cmStringNullGuard(ep->src),ep->chIdx);
|
||||
else
|
||||
{
|
||||
unsigned mobi = ep->obi;
|
||||
unsigned mibi = ep->ibi;
|
||||
unsigned miei = ep->iei;
|
||||
unsigned moei = ep->oei;
|
||||
|
||||
// get the min onsets and max offsets
|
||||
for(j=0; j<ep->chCnt; ++j)
|
||||
{
|
||||
mobi = cmMin(mobi,p->eV[ iV[j] ].obi);
|
||||
mibi = cmMin(mibi,p->eV[ iV[j] ].ibi);
|
||||
miei = cmMax(miei,p->eV[ iV[j] ].iei);
|
||||
moei = cmMax(moei,p->eV[ iV[j] ].oei);
|
||||
}
|
||||
|
||||
// set the onsets to the min onset / offsets to max offsets
|
||||
for(j=0; j<ep->chCnt; ++j)
|
||||
{
|
||||
p->eV[ iV[j] ].obi = mobi;
|
||||
p->eV[ iV[j] ].ibi = mibi;
|
||||
p->eV[ iV[j] ].iei = miei;
|
||||
p->eV[ iV[j] ].oei = moei;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
cmSdbRC_t cmSdbTest( cmCtx_t* ctx )
|
||||
{
|
||||
cmSdbRC_t rc = kOkSdbRC;
|
||||
cmSdbH_t h = cmSdbNullHandle;
|
||||
const cmChar_t* audioDir = "/home/kevin/media/audio";
|
||||
const cmChar_t* csvFn = "/home/kevin/temp/sdb0/sdb_master.csv";
|
||||
cmErr_t err;
|
||||
|
||||
cmErrSetup(&err,&ctx->rpt,"sdb test");
|
||||
|
||||
if((rc = cmSdbCreate(ctx, &h, audioDir, csvFn )) != kOkSdbRC )
|
||||
{
|
||||
rc = cmErrMsg(&err,rc,"sdb create failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = cmSdbSyncChPairs(h)) != kOkSdbRC )
|
||||
{
|
||||
rc = cmErrMsg(&err,rc,"sdb sync-ch-pairs failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if(0)
|
||||
{
|
||||
cmSdbResponseH_t rH = cmSdbResponseNullHandle;
|
||||
|
||||
const cmChar_t* instrV[] = { "*viol", NULL };
|
||||
|
||||
if((rc = cmSdbSelect(h,0,instrV,NULL,NULL,0,0,0,&rH)) != kOkSdbRC )
|
||||
{
|
||||
rc = cmErrMsg(&err,rc,"sdb query failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
cmSdbResponsePrint(rH,&ctx->rpt);
|
||||
|
||||
cmSdbResponseFree(&rH);
|
||||
}
|
||||
|
||||
errLabel:
|
||||
if((rc = cmSdbDestroy(&h)) != kOkSdbRC )
|
||||
rc = cmErrMsg(&err,rc,"sdb destroy failed.");
|
||||
|
||||
return rc;
|
||||
}
|
169
app/cmSdb.h
Normal file
169
app/cmSdb.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef cmSdb_h
|
||||
#define cmSdb_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
The data for this object is stored in a CSV file with the following column syntax.
|
||||
|
||||
Column Name Type Description
|
||||
------ -------- ----- -----------------------------------------------------
|
||||
1 uuid uint Unique integer identifier for this event
|
||||
2 baseUuid uint uuid of channel 0 for this event
|
||||
3 chIdx uint Channel index (stereo: 1=left 2=right)
|
||||
4 obi uint Outer onset sample index into 'afn'.
|
||||
5 ibi uint Inner onset sample index into 'afn'.
|
||||
6 iei uint Inner offset sample index into 'afn'.
|
||||
7 oei uint Outer offset sample index into 'afn'.
|
||||
8 src text Source label for this event (e.g. mcgill, ui )
|
||||
9 midi uint MIDI pitch number or -1 if the sample is not pitched
|
||||
10 instr text Instrument label.
|
||||
11 srate uint Sample rate of audio file reference by 'afn'.
|
||||
10 chCnt uint Count of channels for this event.
|
||||
* notes text 0 or more free form double quoted text notes.
|
||||
* afn text File name of the audio file this event occurs in.
|
||||
|
||||
Notes:
|
||||
#. Each event represents a mono audio signal. If the event is drawn
|
||||
from a multi-channel audio file then the 'chCnt' field will be
|
||||
greater than one. If 'chCnt' is greater than one then the associated
|
||||
samples can be found by collecting all events that share the
|
||||
same 'baseUuid'.
|
||||
|
||||
#. There may be zero or more columns of 'notes'. If there are no
|
||||
notes then the 'afn' field is in column 11.
|
||||
|
||||
#. The index values (chIdx,obi,ibi,iei,oei) as stored in the CSV file
|
||||
are 1 based. These values are decreased by 1 by the cmSdb CSV reader
|
||||
so that their cmSdb value is zero based. See cmSdbLoad().
|
||||
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
kOkSdbRC,
|
||||
kLHeapFailSdbRC,
|
||||
kCsvFailSdbRC,
|
||||
kSyntaxErrSdbRC,
|
||||
kInvalidRspIdxSdbRC,
|
||||
kChPairNotFoundSdbRC
|
||||
};
|
||||
|
||||
typedef cmHandle_t cmSdbH_t;
|
||||
typedef cmHandle_t cmSdbResponseH_t;
|
||||
|
||||
typedef cmRC_t cmSdbRC_t;
|
||||
extern cmSdbH_t cmSdbNullHandle_t;
|
||||
extern cmSdbResponseH_t cmSdbResponseNullHandle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned uuid; // unique id of this sample
|
||||
unsigned baseUuid; // uuid of channel 0
|
||||
unsigned chIdx; // channel index (0=left,1=right)
|
||||
unsigned obi; // outer onset
|
||||
unsigned ibi; // inner onset
|
||||
unsigned iei; // inner offset
|
||||
unsigned oei; // outer offset
|
||||
unsigned midi; // MIDI pitch or -1 for unpitched instruments
|
||||
unsigned srate; // sample rate
|
||||
unsigned chCnt; // source channel count
|
||||
const cmChar_t* src; // sample source (e.g. mcgill, ui )
|
||||
const cmChar_t* instr; // instrument label
|
||||
const cmChar_t* afn; // audio file name
|
||||
const cmChar_t** notesV; // NULL terminated list of terms describing the event.
|
||||
} cmSdbEvent_t;
|
||||
|
||||
|
||||
cmSdbRC_t cmSdbCreate( cmCtx_t* ctx, cmSdbH_t* hp, const cmChar_t* audioDir, const cmChar_t* csvFn );
|
||||
cmSdbRC_t cmSdbDestroy( cmSdbH_t* hp );
|
||||
|
||||
bool cmSdbIsValid( cmSdbH_t h );
|
||||
|
||||
cmSdbRC_t cmSdbLoad( cmSdbH_t h, const cmChar_t* csvFn );
|
||||
|
||||
// Select a set of events from the sample database.
|
||||
//
|
||||
// The possible selection criteria are:
|
||||
// sample rate
|
||||
// instrument label
|
||||
// source label
|
||||
// notes labels
|
||||
// event duration
|
||||
//
|
||||
// In order to match an event all active criteria
|
||||
// must match. In other words the match implies a
|
||||
// logical AND operation on each match criteria.
|
||||
// Each of the criteria can be made inactive by
|
||||
// specifying particular key values.
|
||||
// sample rate = 0
|
||||
// instrument label = NULL
|
||||
// source label = NULL
|
||||
// notes labels = NULL
|
||||
// event duration = minDurSec=0 maxDurSec=0
|
||||
//
|
||||
// For the text array arguments (instrV,srcV,notesV)
|
||||
// each element of the array is a key which is attempts to
|
||||
// match the associated field in each event record.
|
||||
// By default a match is triggered if the key text is identical to the
|
||||
// event field text. The match algorithm can be modified by
|
||||
// specifying a '*' as the first character in the key field.
|
||||
// In this case a the key need only be a substring of the
|
||||
// event field to trigger a match. For example "*viol"
|
||||
// will return events that match both "violin" and "viola".
|
||||
//
|
||||
// To specify a mismatch as a successful match
|
||||
// (i.e. to return events which do not match the key text)
|
||||
// prefix the key with a '!' character.
|
||||
//
|
||||
// Note that it is legal to specify both '!' and '*'. In
|
||||
// which case a match will be triggered by fields where
|
||||
// the key text is not a substring of the field text.
|
||||
//
|
||||
// All query response handles returned from this function
|
||||
// should eventualy be released by the application via a call to
|
||||
// cmSdbResponseFree().
|
||||
cmSdbRC_t cmSdbSelect(
|
||||
cmSdbH_t h,
|
||||
double srate, // event sample rate or 0 to ignore
|
||||
const cmChar_t** instrV, // array of instrument labels to match
|
||||
const cmChar_t** srcV, // array of 'src' labels to match
|
||||
const cmChar_t** notesV, // array of text 'notes' to match
|
||||
double minDurSec, // min event duration
|
||||
double maxDurSec, // max event duration or 0 to ignore
|
||||
unsigned minChCnt, // min ch cnt or 0 to ignore
|
||||
cmSdbResponseH_t* rhp );
|
||||
|
||||
// Given the event 'ep' locate the channel pairs associated with that event.
|
||||
// The response handle returned from this function must be released
|
||||
// by a call to cmSdbResponseFree().
|
||||
cmSdbRC_t cmSdbSelectChPairs( cmSdbH_t h, const cmSdbEvent_t* ep, cmSdbResponseH_t* rhp );
|
||||
|
||||
// Return the count of events in a query response.
|
||||
unsigned cmSdbResponseCount( cmSdbResponseH_t rh );
|
||||
|
||||
// Return the event at 'index' in from a query response.
|
||||
// Legal 'index' range: 0<=index<=cmSdbResponseCount().
|
||||
const cmSdbEvent_t* cmSdbResponseEvent( cmSdbResponseH_t rh, unsigned index );
|
||||
|
||||
// Return true if the 'rh' is a non-NULL query response handle.
|
||||
bool cmSdbResponseIsValid( cmSdbResponseH_t rh );
|
||||
|
||||
// Release the resource held by a query response.
|
||||
cmSdbRC_t cmSdbResponseFree( cmSdbResponseH_t* rhp );
|
||||
void cmSdbResponsePrint( cmSdbResponseH_t rh, cmRpt_t* rpt );
|
||||
|
||||
// Time align all channel pairs by setting the onset times to
|
||||
// the minimum time among all the pairs and the offset times to
|
||||
// the maximum among all the pairs.
|
||||
cmSdbRC_t cmSdbSyncChPairs( cmSdbH_t h );
|
||||
|
||||
cmSdbRC_t cmSdbTest( cmCtx_t* ctx );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
48
cmCsv.c
48
cmCsv.c
@ -7,7 +7,7 @@
|
||||
#include "cmMallocDebug.h"
|
||||
#include "cmLex.h"
|
||||
#include "cmLinkedHeap.h"
|
||||
#include "cmSymTbl.h"
|
||||
#include "cmHashTbl.h"
|
||||
#include "cmCsv.h"
|
||||
#include "cmText.h"
|
||||
|
||||
@ -48,9 +48,9 @@ typedef struct cmCsvUdef_str
|
||||
typedef struct
|
||||
{
|
||||
cmErr_t err;
|
||||
void* rptDataPtr; //
|
||||
cmLexH lexH; // parsing lexer
|
||||
cmSymTblH_t symTblH; // all XML identifiers and data is stored as a symbol in this table
|
||||
void* rptDataPtr; //
|
||||
cmLexH lexH; // parsing lexer
|
||||
cmHashTblH_t htH; // hash table handle
|
||||
cmLHeapH_t heapH;
|
||||
cmCsvBind_t* bindPtr; // base of the binder linked list
|
||||
cmCsvCell_t* curRowPtr; // used by the parser to track the row being filled
|
||||
@ -95,15 +95,15 @@ cmCsvRC_t cmCsvInitialize( cmCsvH_t *hp, cmCtx_t* ctx )
|
||||
|
||||
cmErrSetup(&p->err,&ctx->rpt,"CSV");
|
||||
|
||||
// create the symbol table
|
||||
if( cmSymTblIsValid(p->symTblH = cmSymTblCreate(cmSymTblNullHandle,0,ctx)) == false )
|
||||
// create the hash table
|
||||
if( cmHashTblCreate(ctx,&p->htH,8192) != kOkHtRC )
|
||||
{
|
||||
rc = _cmCsvError(p,kSymTblErrCsvRC,"Symbol table creation failed.");
|
||||
rc = _cmCsvError(p,kHashTblErrCsvRC,"Hash table creation failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// allocate the linked heap mgr
|
||||
if( cmLHeapIsValid(p->heapH = cmLHeapCreate(1024,ctx)) == false )
|
||||
if( cmLHeapIsValid(p->heapH = cmLHeapCreate(8192,ctx)) == false )
|
||||
{
|
||||
rc = _cmCsvError(p,kMemAllocErrCsvRC,"Linked heap object allocation failed.");
|
||||
goto errLabel;
|
||||
@ -161,8 +161,8 @@ cmCsvRC_t cmCsvFinalize( cmCsvH_t *hp )
|
||||
if((lexRC = cmLexFinal(&p->lexH)) != kOkLexRC )
|
||||
return _cmCsvError(p,kLexErrCsvRC,"Lexer finalization failed.\nLexer Error:%s",cmLexRcToMsg(lexRC));
|
||||
|
||||
// free the symbol table
|
||||
cmSymTblDestroy(&p->symTblH);
|
||||
// free the hash table
|
||||
cmHashTblDestroy(&p->htH);
|
||||
|
||||
// free the handle
|
||||
cmMemPtrFree(&hp->h);
|
||||
@ -352,8 +352,8 @@ cmCsvRC_t _cmCsvCreateCell( cmCsv_t* p, const char* tokenText, unsigned flags, u
|
||||
cmCsvRC_t rc = kOkCsvRC;
|
||||
|
||||
// register the token text as a symbol
|
||||
if((symId = cmSymTblRegisterSymbol(p->symTblH,tokenText)) == cmInvalidId )
|
||||
return _cmCsvError(p,kSymTblErrCsvRC,"Symbol registration failed. for '%s' on line %i column %i.",tokenText,lexRow,lexCol);
|
||||
if((symId = cmHashTblStoreStr(p->htH,tokenText)) == cmInvalidId )
|
||||
return _cmCsvError(p,kHashTblErrCsvRC,"Symbol registration failed. for '%s' on line %i column %i.",tokenText,lexRow,lexCol);
|
||||
|
||||
// allocate a cell
|
||||
if((rc = _cmCsvAllocCell(p,symId,flags,cellRow,cellCol,&cp,lexTId)) != kOkCsvRC )
|
||||
@ -561,8 +561,8 @@ const char* cmCsvCellSymText( cmCsvH_t h, unsigned symId )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
const char* cp;
|
||||
|
||||
if((cp = cmSymTblLabel(p->symTblH,symId)) == NULL )
|
||||
_cmCsvError(p,kSymTblErrCsvRC,"The text associated with the symbol '%i' was not found.",symId);
|
||||
if((cp = cmHashTblStr(p->htH,symId)) == NULL )
|
||||
_cmCsvError(p,kHashTblErrCsvRC,"The text associated with the symbol '%i' was not found.",symId);
|
||||
|
||||
return cp;
|
||||
}
|
||||
@ -573,7 +573,7 @@ cmCsvRC_t cmCsvCellSymInt( cmCsvH_t h, unsigned symId, int* vp )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
|
||||
if((cp = cmCsvCellSymText(h,symId)) == NULL )
|
||||
return kSymTblErrCsvRC;
|
||||
return kHashTblErrCsvRC;
|
||||
|
||||
if( cmTextToInt(cp,vp,&p->err) != kOkTxRC )
|
||||
return _cmCsvError(p,kDataCvtErrCsvRC,"CSV text to int value failed.");
|
||||
@ -587,7 +587,7 @@ cmCsvRC_t cmCsvCellSymUInt( cmCsvH_t h, unsigned symId, unsigned* vp )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
|
||||
if((cp = cmCsvCellSymText(h,symId)) == NULL )
|
||||
return kSymTblErrCsvRC;
|
||||
return kHashTblErrCsvRC;
|
||||
|
||||
if( cmTextToUInt(cp,vp,&p->err) != kOkTxRC )
|
||||
return _cmCsvError(p,kDataCvtErrCsvRC,"CSV text to uint value failed.");
|
||||
@ -601,7 +601,7 @@ cmCsvRC_t cmCsvCellSymFloat( cmCsvH_t h, unsigned symId, float* vp )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
|
||||
if((cp = cmCsvCellSymText(h,symId)) == NULL )
|
||||
return kSymTblErrCsvRC;
|
||||
return kHashTblErrCsvRC;
|
||||
|
||||
if( cmTextToFloat(cp,vp,&p->err) != kOkTxRC )
|
||||
return _cmCsvError(p,kDataCvtErrCsvRC,"CSV text to float value failed.");
|
||||
@ -615,7 +615,7 @@ cmCsvRC_t cmCsvCellSymDouble( cmCsvH_t h, unsigned symId, double* vp )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
|
||||
if((cp = cmCsvCellSymText(h,symId)) == NULL )
|
||||
return kSymTblErrCsvRC;
|
||||
return kHashTblErrCsvRC;
|
||||
|
||||
if( cmTextToDouble(cp,vp,&p->err) != kOkTxRC )
|
||||
return _cmCsvError(p,kDataCvtErrCsvRC,"CSV text to double value failed.");
|
||||
@ -695,8 +695,8 @@ unsigned cmCsvInsertSymText( cmCsvH_t h, const char* text )
|
||||
cmCsv_t* p = _cmCsvHandleToPtr(h);
|
||||
unsigned symId;
|
||||
|
||||
if((symId = cmSymTblRegisterSymbol(p->symTblH,text)) == cmInvalidId )
|
||||
_cmCsvError(p,kSymTblErrCsvRC,"'%s' could not be inserted into the symbol table.",text);
|
||||
if((symId = cmHashTblStoreStr(p->htH,text)) == cmInvalidId )
|
||||
_cmCsvError(p,kHashTblErrCsvRC,"'%s' could not be inserted into the symbol table.",text);
|
||||
|
||||
return symId;
|
||||
}
|
||||
@ -1134,8 +1134,8 @@ cmCsvRC_t cmCsvWrite( cmCsvH_t h, const char* fn )
|
||||
{
|
||||
const char* tp;
|
||||
|
||||
if((tp = cmSymTblLabel(p->symTblH,cp->symId)) == NULL )
|
||||
return _cmCsvError(p,kSymTblErrCsvRC,"Unable to locate the symbol text for cell at row:%i col:%i.",cp->row,cp->col);
|
||||
if((tp = cmHashTblStr(p->htH,cp->symId)) == NULL )
|
||||
return _cmCsvError(p,kHashTblErrCsvRC,"Unable to locate the symbol text for cell at row:%i col:%i.",cp->row,cp->col);
|
||||
|
||||
if( cmIsFlag(cp->flags,kTextTMask) )
|
||||
fprintf(fp,"\"");
|
||||
@ -1179,8 +1179,8 @@ cmCsvRC_t cmCsvPrint( cmCsvH_t h, unsigned rowCnt )
|
||||
{
|
||||
const char* tp;
|
||||
|
||||
if((tp = cmSymTblLabel(p->symTblH,cp->symId)) == NULL )
|
||||
_cmCsvError(p,kSymTblErrCsvRC,"The text associated with the symbol '%i' was not found.",cp->symId);
|
||||
if((tp = cmHashTblStr(p->htH,cp->symId)) == NULL )
|
||||
_cmCsvError(p,kHashTblErrCsvRC,"The text associated with the symbol '%i' was not found.",cp->symId);
|
||||
|
||||
fputs(tp,stdin);
|
||||
}
|
||||
|
2
cmCsv.h
2
cmCsv.h
@ -11,7 +11,7 @@ extern "C" {
|
||||
kOkCsvRC = 0,
|
||||
kMemAllocErrCsvRC,
|
||||
kLexErrCsvRC,
|
||||
kSymTblErrCsvRC,
|
||||
kHashTblErrCsvRC,
|
||||
kSyntaxErrCsvRC,
|
||||
kFileOpenErrCsvRC,
|
||||
kFileCreateErrCsvRC,
|
||||
|
464
cmHashTbl.c
Normal file
464
cmHashTbl.c
Normal file
@ -0,0 +1,464 @@
|
||||
#include "cmGlobal.h"
|
||||
#include "cmFloatTypes.h"
|
||||
#include "cmRpt.h"
|
||||
#include "cmErr.h"
|
||||
#include "cmCtx.h"
|
||||
#include "cmMem.h"
|
||||
#include "cmLinkedHeap.h"
|
||||
#include "cmMallocDebug.h"
|
||||
#include "cmMath.h"
|
||||
#include "cmHashTbl.h"
|
||||
#include "cmText.h"
|
||||
|
||||
enum
|
||||
{
|
||||
kFreeHtFl = 0x01,
|
||||
};
|
||||
|
||||
typedef struct cmHtValue_str
|
||||
{
|
||||
unsigned flags; // See kXXXHtFl above.
|
||||
unsigned id; // unique id associated with this value
|
||||
void* value; // value blob
|
||||
unsigned byteCnt; // size of value blob in bytes
|
||||
struct cmHtValue_str* link; // cmHtBucket_t.list link
|
||||
} cmHtValue_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cmHtValue_t* list; // value list
|
||||
cmHtValue_t* avail; // available value slots - formed from cmHashTblRemoved() values.
|
||||
unsigned nextIdx; // next unused index for this bucket
|
||||
} cmHtBucket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cmErr_t err;
|
||||
cmLHeapH_t lhH; // memory for hash table buckets, values, value blobs.
|
||||
unsigned bucketCnt; // hash table bucket cnt
|
||||
unsigned linkCnt; // max length of collision list for each bucket
|
||||
unsigned mask; // hash id bucket index mask (masks the MSB's of the hash-id)
|
||||
unsigned maskShift; // shift required to move the lowest 'mask' bit to the LSB.
|
||||
cmHtBucket_t* b; // b[bucketCnt] bucket array
|
||||
} cmHt_t;
|
||||
|
||||
cmHashTblH_t cmHashTblNullHandle = cmSTATIC_NULL_HANDLE;
|
||||
|
||||
#define _cmHtBucketIndex( p, id ) (((id) & (p)->mask) >> (p)->maskShift)
|
||||
|
||||
cmHt_t* _cmHtHandleToPtr( cmHashTblH_t h )
|
||||
{
|
||||
cmHt_t* p = (cmHt_t*)h.h;
|
||||
assert(p!=NULL);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Return the bucket index portion of the hash id.
|
||||
unsigned _cmHtGenId( cmHt_t* p, const void* v, unsigned byteCnt )
|
||||
{
|
||||
unsigned i,j;
|
||||
const char* cv = v;
|
||||
unsigned h = 0;
|
||||
|
||||
for(i=0,j=3; i<byteCnt; ++i,++j)
|
||||
h += ((unsigned)cv[i]) << ((j&0x3)*8);
|
||||
|
||||
return h & p->mask;
|
||||
}
|
||||
|
||||
|
||||
// Given an id find the value.
|
||||
cmHtValue_t* _cmHtIdToValue( cmHt_t* p, unsigned id )
|
||||
{
|
||||
if( id == cmInvalidId )
|
||||
return NULL;
|
||||
|
||||
unsigned bi = _cmHtBucketIndex(p,id);
|
||||
|
||||
assert(bi < p->bucketCnt);
|
||||
|
||||
cmHtValue_t* v = p->b[bi].list;
|
||||
for(; v!=NULL; v=v->link)
|
||||
if( v->id == id )
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Given a value find the id
|
||||
cmHtValue_t* _cmHtValueToId( cmHt_t* p, const void* value, unsigned byteCnt, unsigned id )
|
||||
{
|
||||
if( id == cmInvalidId )
|
||||
id = _cmHtGenId(p,value,byteCnt);
|
||||
|
||||
unsigned bi = _cmHtBucketIndex(p,id);
|
||||
|
||||
assert(bi < p->bucketCnt);
|
||||
|
||||
cmHtValue_t* v = p->b[bi].list;
|
||||
for(; v!=NULL; v=v->link)
|
||||
if( v->byteCnt==byteCnt && memcmp(value,v->value,byteCnt)==0 )
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmHtRC_t _cmHtDestroy( cmHt_t* p )
|
||||
{
|
||||
cmHtRC_t rc = kOkHtRC;
|
||||
cmLHeapDestroy(&p->lhH);
|
||||
cmMemFree(p->b);
|
||||
cmMemFree(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmHtRC_t cmHashTblCreate( cmCtx_t* ctx, cmHashTblH_t* hp, unsigned bucketCnt )
|
||||
{
|
||||
cmHtRC_t rc;
|
||||
if((rc = cmHashTblDestroy(hp)) != kOkHtRC )
|
||||
return rc;
|
||||
|
||||
cmHt_t* p = cmMemAllocZ(cmHt_t,1);
|
||||
|
||||
cmErrSetup(&p->err,&ctx->rpt,"hash table");
|
||||
|
||||
if(cmLHeapIsValid(p->lhH = cmLHeapCreate(8192,ctx)) == false )
|
||||
{
|
||||
cmErrMsg(&p->err,kLHeapFailHtRC,"Internal linked heap mgr. create failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// force the bucket count to be a power of two
|
||||
p->bucketCnt = cmNextPowerOfTwo(bucketCnt);
|
||||
p->mask = p->bucketCnt - 1;
|
||||
|
||||
// calcluate the hash-id bucket mask
|
||||
for(p->maskShift=0; (0x80000000 & p->mask) == 0; ++p->maskShift )
|
||||
p->mask <<= 1;
|
||||
|
||||
// calculate the maximum collisions per bucket mask
|
||||
p->linkCnt = ~p->mask;
|
||||
|
||||
// allocate the bucket array
|
||||
p->b = cmMemAllocZ(cmHtBucket_t,p->bucketCnt);
|
||||
|
||||
hp->h = p;
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkHtRC )
|
||||
_cmHtDestroy(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmHtRC_t cmHashTblDestroy( cmHashTblH_t* hp )
|
||||
{
|
||||
cmHtRC_t rc = kOkHtRC;
|
||||
if(hp==NULL || cmHashTblIsValid(*hp)==false )
|
||||
return rc;
|
||||
|
||||
cmHt_t* p = _cmHtHandleToPtr(*hp);
|
||||
|
||||
if((rc = _cmHtDestroy(p)) != kOkHtRC )
|
||||
return rc;
|
||||
|
||||
hp->h = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool cmHashTblIsValid( cmHashTblH_t h )
|
||||
{ return h.h!=NULL; }
|
||||
|
||||
unsigned cmHashTblStoreBase( cmHashTblH_t h, void* v, unsigned byteCnt, bool staticFl )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
cmHtValue_t* vp = NULL;
|
||||
unsigned id = _cmHtGenId(p, v, byteCnt );
|
||||
|
||||
// if the value is already stored then there is nothing else to do
|
||||
if((vp = _cmHtValueToId(p,v,byteCnt,id)) != NULL )
|
||||
return vp->id;
|
||||
|
||||
unsigned bi = _cmHtBucketIndex(p,id);
|
||||
|
||||
assert(bi < p->bucketCnt );
|
||||
|
||||
cmHtBucket_t* b = p->b + bi;
|
||||
|
||||
if( b->avail != NULL )
|
||||
{
|
||||
vp = b->avail;
|
||||
b->avail = b->avail->link;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( b->nextIdx == p->linkCnt || (id + b->nextIdx) == cmInvalidId )
|
||||
{
|
||||
cmErrMsg(&p->err,kHashFaultHtRC,"The hash table bucket at index %i is exhaused.",bi);
|
||||
return cmInvalidId;
|
||||
}
|
||||
|
||||
vp = cmLhAllocZ(p->lhH,cmHtValue_t,1);
|
||||
vp->id = id + b->nextIdx++;
|
||||
}
|
||||
|
||||
|
||||
assert( vp->id != cmInvalidId );
|
||||
|
||||
vp->link = b->list;
|
||||
b->list = vp;
|
||||
vp->byteCnt = byteCnt;
|
||||
|
||||
if( staticFl )
|
||||
vp->value = v;
|
||||
else
|
||||
{
|
||||
vp->value = cmLhAlloc(p->lhH,char,byteCnt);
|
||||
memcpy(vp->value,v,byteCnt);
|
||||
vp->flags = cmSetFlag(vp->flags,kFreeHtFl);
|
||||
}
|
||||
|
||||
return vp->id;
|
||||
}
|
||||
|
||||
unsigned cmHashTblStore( cmHashTblH_t h, void* v, unsigned byteCnt )
|
||||
{ return cmHashTblStoreBase(h,v,byteCnt,false); }
|
||||
|
||||
unsigned cmHashTblStoreStatic( cmHashTblH_t h, void* v, unsigned byteCnt )
|
||||
{ return cmHashTblStoreBase(h,v,byteCnt,true); }
|
||||
|
||||
unsigned _cmHashTblStoreStr( cmHashTblH_t h, const cmChar_t* s, bool staticFl )
|
||||
{
|
||||
unsigned n = cmTextLength(s);
|
||||
if( n == 0 )
|
||||
{
|
||||
s = "";
|
||||
n = 1;
|
||||
}
|
||||
|
||||
return cmHashTblStoreBase(h,(void*)s,n+1,staticFl);
|
||||
}
|
||||
|
||||
unsigned cmHashTblStoreStr( cmHashTblH_t h, const cmChar_t* s )
|
||||
{ return _cmHashTblStoreStr(h,s,false); }
|
||||
|
||||
unsigned cmhashTblStoreStaticStr( cmHashTblH_t h, const cmChar_t* s )
|
||||
{ return _cmHashTblStoreStr(h,s,true); }
|
||||
|
||||
unsigned cmHashTblStoreV( cmHashTblH_t h, const cmChar_t* fmt, va_list vl )
|
||||
{
|
||||
cmChar_t* s = NULL;
|
||||
s = cmTsVPrintfP(s,fmt,vl);
|
||||
unsigned id = _cmHashTblStoreStr(h,s,false);
|
||||
cmMemFree(s);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned cmHashTblStoreF( cmHashTblH_t h, const cmChar_t* fmt, ... )
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
unsigned id = cmHashTblStoreV(h,fmt,vl);
|
||||
va_end(vl);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned cmHashTblId( cmHashTblH_t h, const void* value, unsigned byteCnt )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
cmHtValue_t* vp;
|
||||
|
||||
if((vp = _cmHtValueToId(p,value,byteCnt,cmInvalidId)) == NULL )
|
||||
return cmInvalidId;
|
||||
|
||||
return vp->id;
|
||||
}
|
||||
|
||||
unsigned cmHashTblStrToId( cmHashTblH_t h, const cmChar_t* str )
|
||||
{
|
||||
if( str == NULL )
|
||||
return cmInvalidId;
|
||||
|
||||
return cmHashTblId(h,str,cmTextLength(str)+1);
|
||||
}
|
||||
|
||||
|
||||
const void* cmHashTblValue( cmHashTblH_t h, unsigned id, unsigned* byteCntRef )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
cmHtValue_t* vp;
|
||||
|
||||
if((vp = _cmHtIdToValue(p, id)) != NULL )
|
||||
{
|
||||
if( byteCntRef != NULL )
|
||||
*byteCntRef = vp->byteCnt;
|
||||
|
||||
return vp->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const cmChar_t* cmHashTblStr( cmHashTblH_t h, unsigned id )
|
||||
{ return (const cmChar_t*)cmHashTblValue(h,id,NULL); }
|
||||
|
||||
|
||||
cmHtRC_t cmHashTblRemove( cmHashTblH_t h, unsigned id )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
unsigned bi = _cmHtBucketIndex(p,id);
|
||||
|
||||
|
||||
|
||||
assert(bi < p->bucketCnt);
|
||||
|
||||
cmHtBucket_t* b = p->b + bi;
|
||||
|
||||
cmHtValue_t* vp = b->list;
|
||||
cmHtValue_t* pp = NULL;
|
||||
|
||||
for(; vp!=NULL; vp=vp->link)
|
||||
{
|
||||
if( vp->id == id )
|
||||
{
|
||||
if( pp == NULL )
|
||||
b->list = vp->link;
|
||||
else
|
||||
pp->link = vp->link;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pp = vp;
|
||||
}
|
||||
|
||||
if( vp == NULL )
|
||||
return cmErrMsg(&p->err,kInvalidIdHtRC,"A value could not be found for the hash id 0x%x.",id);
|
||||
|
||||
if( cmIsFlag(vp->flags,kFreeHtFl ) )
|
||||
cmLhFree(p->lhH,vp->value);
|
||||
|
||||
|
||||
vp->flags = 0;
|
||||
vp->value = NULL;
|
||||
vp->byteCnt = 0;
|
||||
|
||||
// Note: Do not set the id to zero since we want to consert id's
|
||||
// and this recd will be reused by the next call to cmHashTblStoreBase().
|
||||
|
||||
return kOkHtRC;
|
||||
|
||||
}
|
||||
|
||||
|
||||
cmHtRC_t cmHashTblLastRC( cmHashTblH_t h )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
return cmErrLastRC(&p->err);
|
||||
}
|
||||
|
||||
void _cmHashTblBucketReport( cmHtBucket_t* b, cmRpt_t* rpt )
|
||||
{
|
||||
cmHtValue_t* vp = b->list;
|
||||
unsigned i;
|
||||
for(i=0; vp!=NULL && i<10; vp=vp->link,++i)
|
||||
cmRptPrintf(rpt,"0x%x : %s\n",vp->id,((const cmChar_t*)vp->value));
|
||||
|
||||
cmRptPrintf(rpt,"\n");
|
||||
}
|
||||
|
||||
void cmHashTblReport( cmHashTblH_t h, cmRpt_t* rpt )
|
||||
{
|
||||
cmHt_t* p = _cmHtHandleToPtr(h);
|
||||
unsigned i;
|
||||
for(i=0; i<p->bucketCnt; ++i)
|
||||
{
|
||||
//if( p->b[i].nextIdx > 0 )
|
||||
// cmRptPrintf(rpt,"%i,%i\n",i,p->b[i].nextIdx);
|
||||
|
||||
if( p->b[i].nextIdx > 100 )
|
||||
_cmHashTblBucketReport(p->b + i,rpt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cmHtRC_t cmHashTblTest( cmCtx_t* ctx )
|
||||
{
|
||||
cmHtRC_t rc = kOkHtRC;
|
||||
cmHashTblH_t h = cmHashTblNullHandle;
|
||||
cmErr_t err;
|
||||
cmErrSetup(&err,&ctx->rpt,"hash table test");
|
||||
|
||||
if((rc = cmHashTblCreate(ctx,&h,8192)) != kOkHtRC )
|
||||
return cmErrMsg(&err,rc,"Hash table create failed.");
|
||||
|
||||
const cmChar_t* arr[] =
|
||||
{
|
||||
"1",
|
||||
"12",
|
||||
"123",
|
||||
"1234",
|
||||
"12345",
|
||||
"123456",
|
||||
"123456",
|
||||
"123456",
|
||||
NULL
|
||||
};
|
||||
|
||||
unsigned n = sizeof(arr)/sizeof(arr[0]);
|
||||
unsigned ids[ n ];
|
||||
int i = 0;
|
||||
|
||||
// store the values from arr[]
|
||||
for(; arr[i]!=NULL; ++i)
|
||||
if((ids[i] = cmHashTblStoreStr(h,arr[i])) == cmInvalidId )
|
||||
{
|
||||
rc = cmErrMsg(&err,cmHashTblLastRC(h),"Hash store failed on: '%s.",cmStringNullGuard(arr[i]));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
/*
|
||||
// remove a value
|
||||
unsigned rem_idx = 3;
|
||||
if((rc = cmHashTblRemove(h, ids[rem_idx] )) != kOkHtRC )
|
||||
{
|
||||
rc = cmErrMsg(&err,rc,"Hash removed failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// insert the same value - which should restore the removed value
|
||||
if((ids[rem_idx] = cmHashTblStoreStr(h,arr[rem_idx])) == cmInvalidId )
|
||||
{
|
||||
rc = cmErrMsg(&err,cmHashTblLastRC(h),"Hash store failed on: '%s.",cmStringNullGuard(arr[rem_idx]));
|
||||
goto errLabel;
|
||||
}
|
||||
*/
|
||||
|
||||
// lookup all the stored values by id
|
||||
for(--i; i>=0; --i)
|
||||
{
|
||||
const cmChar_t* s;
|
||||
|
||||
if((s = cmHashTblStr(h,ids[i])) == NULL )
|
||||
rc = cmErrMsg(&err,kInvalidIdHtRC,"The value associated with hash-id:0x%x could not be found.",ids[i]);
|
||||
else
|
||||
printf("%i : %s\n",i,cmStringNullGuard(s));
|
||||
}
|
||||
|
||||
|
||||
for(i=0; arr[i]!=NULL; ++i)
|
||||
{
|
||||
unsigned id = cmHashTblStrToId(h, arr[i]);
|
||||
printf("%i : 0x%x : %s\n",i, id, cmStringNullGuard(cmHashTblStr(h, id)));
|
||||
}
|
||||
|
||||
|
||||
cmHashTblReport(h, &ctx->rpt );
|
||||
|
||||
|
||||
errLabel:
|
||||
cmHashTblDestroy(&h);
|
||||
return rc;
|
||||
|
||||
}
|
67
cmHashTbl.h
Normal file
67
cmHashTbl.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef cmHashTbl_h
|
||||
#define cmHashTbl_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
kOkHtRC,
|
||||
kLHeapFailHtRC,
|
||||
kHashFaultHtRC,
|
||||
kInvalidIdHtRC
|
||||
};
|
||||
|
||||
typedef cmRC_t cmHtRC_t;
|
||||
typedef cmHandle_t cmHashTblH_t;
|
||||
extern cmHashTblH_t cmHashTblNullHandle;
|
||||
|
||||
cmHtRC_t cmHashTblCreate( cmCtx_t* ctx, cmHashTblH_t* hp, unsigned bucketCnt );
|
||||
|
||||
cmHtRC_t cmHashTblDestroy( cmHashTblH_t* hp );
|
||||
|
||||
bool cmHashTblIsValid( cmHashTblH_t h );
|
||||
|
||||
// cmhashTblStoreBase() is the canonical store function.
|
||||
// Set 'staticFl' to true if the value does not need to be reallocated
|
||||
// and copied into the internal storage space.
|
||||
// Returns a value which uniquely identifies the value. If a unique
|
||||
// identifier cannot be generated then the function returns cmInvalidId
|
||||
// and sets the hash table error code to kHashFaultRC.
|
||||
unsigned cmHashTblStoreBase( cmHashTblH_t h, void* v, unsigned byteCnt, bool staticFl );
|
||||
|
||||
unsigned cmHashTblStore( cmHashTblH_t h, void* v, unsigned byteCnt );
|
||||
unsigned cmHashTblStoreStatic( cmHashTblH_t h, void* v, unsigned byteCnt );
|
||||
unsigned cmHashTblStoreStr( cmHashTblH_t h, const cmChar_t* s );
|
||||
unsigned cmhashTblStoreStaticStr( cmHashTblH_t h, const cmChar_t* s );
|
||||
unsigned cmHashTblStoreV( cmHashTblH_t h, const cmChar_t* fmt, va_list vl );
|
||||
unsigned cmHashTblStoreF( cmHashTblH_t h, const cmChar_t* fmt, ... );
|
||||
|
||||
// Given a value find an id.
|
||||
unsigned cmHashTblId( cmHashTblH_t h, const void* value, unsigned byteCnt );
|
||||
unsigned cmHashTblStrToId( cmHashTblH_t h, const cmChar_t* str );
|
||||
|
||||
// Returns NULL if no value is associated with 'id'.
|
||||
// 'byteCntRef' is optional.
|
||||
const void* cmHashTblValue( cmHashTblH_t h, unsigned id, unsigned* byteCntRef );
|
||||
|
||||
// Wrapper around cmHashTblValue() which assumes that the stored value is a
|
||||
// zero terminated string.
|
||||
const cmChar_t* cmHashTblStr( cmHashTblH_t h, unsigned id );
|
||||
|
||||
// Remove a value.
|
||||
cmHtRC_t cmHashTblRemove( cmHashTblH_t h, unsigned id );
|
||||
|
||||
// Return the last error id generated by the cmHashTbl object.
|
||||
cmHtRC_t cmHashTblLastRC( cmHashTblH_t h );
|
||||
|
||||
void cmHashTblReport( cmHashTblH_t h, cmRpt_t* rpt );
|
||||
|
||||
cmHtRC_t cmHashTblTest( cmCtx_t* ctx );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
123
cmSyncRecd.c
123
cmSyncRecd.c
@ -11,6 +11,7 @@
|
||||
#include "cmSyncRecd.h"
|
||||
#include "cmVectOpsTemplateMain.h"
|
||||
#include "cmMidi.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kInvalidSrId,
|
||||
@ -76,44 +77,44 @@ cmSr_t* _cmSrHtoP( cmSyncRecdH_t h )
|
||||
return p;
|
||||
}
|
||||
|
||||
cmSrRC_t _cmSrWriteCache( cmSr_t* p )
|
||||
cmSyRC_t _cmSrWriteCache( cmSr_t* p )
|
||||
{
|
||||
if( cmFileWrite(p->fH,p->cache,p->ci * sizeof(cmSrRecd_t)) != kOkFileRC )
|
||||
return cmErrMsg(&p->err,kFileFailSrRC,"File write failed.");
|
||||
return cmErrMsg(&p->err,kFileFailSyRC,"File write failed.");
|
||||
|
||||
p->fn += p->ci;
|
||||
p->ci = 0;
|
||||
|
||||
return kOkSrRC;
|
||||
return kOkSyRC;
|
||||
}
|
||||
|
||||
|
||||
cmSrRC_t _cmSrFinal( cmSr_t* p )
|
||||
cmSyRC_t _cmSrFinal( cmSr_t* p )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
|
||||
// write any remaining cache records
|
||||
if( cmIsFlag(p->flags,kReadSrFl) == false )
|
||||
{
|
||||
if((rc = _cmSrWriteCache(p)) == kOkSrRC )
|
||||
if((rc = _cmSrWriteCache(p)) == kOkSyRC )
|
||||
{
|
||||
if(cmFileSeek(p->fH,kBeginFileFl,p->offs) != kOkFileRC )
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC, "File seek fail on file offset positioning.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC, "File seek fail on file offset positioning.");
|
||||
else
|
||||
if(cmFileWriteUInt(p->fH,&p->fn,1) != kOkFileRC )
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC, "File write failed on record count.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC, "File write failed on record count.");
|
||||
}
|
||||
}
|
||||
|
||||
// release the audio file object
|
||||
if( cmAudioFileIsValid(p->afH) )
|
||||
if( cmAudioFileDelete(&p->afH) != kOkAfRC )
|
||||
return cmErrMsg(&p->err,kAudioFileFailSrRC,"Audio file object delete failed.");
|
||||
return cmErrMsg(&p->err,kAudioFileFailSyRC,"Audio file object delete failed.");
|
||||
|
||||
// release the sync-recd file object
|
||||
if( cmFileIsValid(p->fH) )
|
||||
if( cmFileClose(&p->fH) != kOkFileRC )
|
||||
return cmErrMsg(&p->err,kFileFailSrRC,"File close failed.");
|
||||
return cmErrMsg(&p->err,kFileFailSyRC,"File close failed.");
|
||||
|
||||
cmMemFree(p->cache);
|
||||
cmMemFree(p->map);
|
||||
@ -134,27 +135,27 @@ cmSr_t* _cmSrAlloc( cmCtx_t* ctx, unsigned flags )
|
||||
return p;
|
||||
}
|
||||
|
||||
cmSrRC_t cmSyncRecdCreate( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn, const cmChar_t* audioFn, double srate, unsigned chCnt, unsigned bits )
|
||||
cmSyRC_t cmSyncRecdCreate( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn, const cmChar_t* audioFn, double srate, unsigned chCnt, unsigned bits )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmRC_t afRC = kOkAfRC;
|
||||
|
||||
assert( audioFn != NULL );
|
||||
|
||||
if((rc = cmSyncRecdFinal(hp)) != kOkSrRC )
|
||||
if((rc = cmSyncRecdFinal(hp)) != kOkSyRC )
|
||||
return rc;
|
||||
|
||||
cmSr_t* p = _cmSrAlloc(ctx,0);
|
||||
|
||||
if( cmFileOpen(&p->fH,srFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to create the sync-recd file '%s'.",cmStringNullGuard(srFn));
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to create the sync-recd file '%s'.",cmStringNullGuard(srFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmAudioFileIsValid(p->afH = cmAudioFileNewCreate(audioFn,srate,bits,chCnt,&afRC,&ctx->rpt))==false)
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Unable to create the sync-recd audio file '%s'.",cmStringNullGuard(audioFn));
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Unable to create the sync-recd audio file '%s'.",cmStringNullGuard(audioFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -163,47 +164,47 @@ cmSrRC_t cmSyncRecdCreate( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
|
||||
if( cmFileWriteUInt(p->fH,&fileUUId,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File write failed on UUID.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File write failed on UUID.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileWriteUInt(p->fH,&audioFnCnt,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File write failed on audio file length write count.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File write failed on audio file length write count.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileWriteChar(p->fH,audioFn,audioFnCnt) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File write failed on audio file string.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File write failed on audio file string.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileTell(p->fH,&p->offs) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to determine file offset.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to determine file offset.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileWriteUInt(p->fH,&p->fn,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File write failed on initial record count.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File write failed on initial record count.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
hp->h = p;
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkSrRC )
|
||||
if( rc != kOkSyRC )
|
||||
_cmSrFinal(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn )
|
||||
cmSyRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmRC_t afRC = kOkAfRC;
|
||||
unsigned fileUUId = cmInvalidId;
|
||||
unsigned audioFnCnt = 0;
|
||||
@ -213,26 +214,26 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
unsigned mcnt = 0;
|
||||
unsigned* tiV = NULL;
|
||||
|
||||
if((rc = cmSyncRecdFinal(hp)) != kOkSrRC )
|
||||
if((rc = cmSyncRecdFinal(hp)) != kOkSyRC )
|
||||
return rc;
|
||||
|
||||
cmSr_t* p = _cmSrAlloc(ctx,kReadSrFl);
|
||||
|
||||
if( cmFileOpen(&p->fH,srFn,kReadFileFl,&ctx->rpt) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to open the sync-recd file '%s'.",cmStringNullGuard(srFn));
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to open the sync-recd file '%s'.",cmStringNullGuard(srFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileReadUInt(p->fH,&fileUUId,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File read failed on UUId.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File read failed on UUId.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileReadUInt(p->fH,&audioFnCnt,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File read failed on audio file name count.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File read failed on audio file name count.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -240,20 +241,20 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
|
||||
if( cmFileReadChar(p->fH,audioFn,audioFnCnt) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File read failed on audio file string.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File read failed on audio file string.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( cmFileReadUInt(p->fH,&p->fn,1) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"File read failed on record count.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"File read failed on record count.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// store the file offset to the first recd
|
||||
if( cmFileTell(p->fH,&p->offs) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to determine the current file offset.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to determine the current file offset.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -264,7 +265,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
cmSrRecd_t r;
|
||||
if( cmFileRead(p->fH,&r,sizeof(r)) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to read the record at index %i.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to read the record at index %i.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -288,7 +289,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
// rewind to the begining of the records
|
||||
if( cmFileSeek(p->fH,kBeginFileFl,p->offs) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to seek to first recd offset.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to seek to first recd offset.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -303,7 +304,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
{
|
||||
if( cmFileRead(p->fH,p->cache + p->ci,sizeof(cmSrRecd_t)) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to read the record at index %i.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to read the record at index %i.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -317,7 +318,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
// rewind to the first recd
|
||||
if( cmFileSeek(p->fH,kBeginFileFl,p->offs) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to seek to first recd offset.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to seek to first recd offset.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -328,7 +329,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
cmSrRecd_t r;
|
||||
if( cmFileRead(p->fH,&r,sizeof(r)) != kOkFileRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kFileFailSrRC,"Unable to read the record at index %i.");
|
||||
rc = cmErrMsg(&p->err,kFileFailSyRC,"Unable to read the record at index %i.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -358,7 +359,7 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
// open the audio file
|
||||
if( cmAudioFileIsValid(p->afH = cmAudioFileNewOpen(audioFn,&p->afInfo,&afRC,&ctx->rpt ))==false)
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Unable to open the sync-recd audio file '%s'.",cmStringNullGuard(audioFn));
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Unable to open the sync-recd audio file '%s'.",cmStringNullGuard(audioFn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -371,22 +372,22 @@ cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn
|
||||
cmMemFree(tiV);
|
||||
cmMemFree(audioFn);
|
||||
|
||||
if( rc != kOkSrRC )
|
||||
if( rc != kOkSyRC )
|
||||
_cmSrFinal(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSrRC_t cmSyncRecdFinal( cmSyncRecdH_t* hp )
|
||||
cmSyRC_t cmSyncRecdFinal( cmSyncRecdH_t* hp )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
|
||||
if( hp==NULL || cmSyncRecdIsValid(*hp)==false)
|
||||
return rc;
|
||||
|
||||
cmSr_t* p = _cmSrHtoP(*hp);
|
||||
|
||||
if((rc = _cmSrFinal(p)) != kOkSrRC )
|
||||
if((rc = _cmSrFinal(p)) != kOkSyRC )
|
||||
return rc;
|
||||
|
||||
hp->h = NULL;
|
||||
@ -397,9 +398,9 @@ cmSrRC_t cmSyncRecdFinal( cmSyncRecdH_t* hp )
|
||||
bool cmSyncRecdIsValid( cmSyncRecdH_t h )
|
||||
{ return h.h != NULL; }
|
||||
|
||||
cmSrRC_t cmSyncRecdMidiWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned status, unsigned d0, unsigned d1 )
|
||||
cmSyRC_t cmSyncRecdMidiWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned status, unsigned d0, unsigned d1 )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmSr_t* p = _cmSrHtoP(h);
|
||||
cmSrRecd_t* rp = p->cache + p->ci;
|
||||
rp->tid = kMidiSrId;
|
||||
@ -416,9 +417,9 @@ cmSrRC_t cmSyncRecdMidiWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, u
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSrRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned smpIdx, const cmSample_t* ch[], unsigned chCnt, unsigned frmCnt )
|
||||
cmSyRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned smpIdx, const cmSample_t* ch[], unsigned chCnt, unsigned frmCnt )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmSr_t* p = _cmSrHtoP(h);
|
||||
cmSrRecd_t* rp = p->cache + p->ci;
|
||||
rp->tid = kAudioSrId;
|
||||
@ -428,25 +429,25 @@ cmSrRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, u
|
||||
p->ci += 1;
|
||||
|
||||
if( p->ci == p->cn )
|
||||
if((rc = _cmSrWriteCache(p)) != kOkSrRC )
|
||||
if((rc = _cmSrWriteCache(p)) != kOkSyRC )
|
||||
goto errLabel;
|
||||
|
||||
if( cmAudioFileWriteSample(p->afH,frmCnt,chCnt,(cmSample_t**)ch) != kOkAfRC )
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Audio file write failed.");
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Audio file write failed.");
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
cmSrRC_t cmSyncRecdPrint( cmSyncRecdH_t h )
|
||||
cmSyRC_t cmSyncRecdPrint( cmSyncRecdH_t h )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmSr_t* p = _cmSrHtoP(h);
|
||||
unsigned i;
|
||||
|
||||
if( cmIsFlag(p->flags,kReadSrFl)==false)
|
||||
return cmErrMsg(&p->err,kInvalidOpSrRC,"The 'print' operation is only valid on sync-recd files opened for reading.");
|
||||
return cmErrMsg(&p->err,kInvalidOpSyRC,"The 'print' operation is only valid on sync-recd files opened for reading.");
|
||||
|
||||
for(i=0; i<p->cn; ++i)
|
||||
{
|
||||
@ -457,9 +458,9 @@ cmSrRC_t cmSyncRecdPrint( cmSyncRecdH_t h )
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
cmSyRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
{
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
cmSr_t* p = _cmSrHtoP(h);
|
||||
cmAudioFileH_t afH = cmNullAudioFileH;
|
||||
unsigned chCnt = 2;
|
||||
@ -474,19 +475,19 @@ cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
chs[1] = buf+frmCnt;
|
||||
|
||||
if( cmIsFlag(p->flags,kReadSrFl)==false)
|
||||
return cmErrMsg(&p->err,kInvalidOpSrRC,"The 'audio-file-output' operation is only valid on sync-recd files opened for reading.");
|
||||
return cmErrMsg(&p->err,kInvalidOpSyRC,"The 'audio-file-output' operation is only valid on sync-recd files opened for reading.");
|
||||
|
||||
/// Open an audio file for writing
|
||||
if(cmAudioFileIsValid(afH = cmAudioFileNewCreate(fn, p->afInfo.srate, p->afInfo.bits, chCnt, &afRC, p->err.rpt))==false)
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Unable to create the synchronized audio file '%s'.",cmStringNullGuard(fn));
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Unable to create the synchronized audio file '%s'.",cmStringNullGuard(fn));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// rewind the input audio file
|
||||
if( cmAudioFileSeek(p->afH,0) != kOkAfRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Seek failed during synchronized audio file output.");
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Seek failed during synchronized audio file output.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
@ -500,7 +501,7 @@ cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
// read frmCnt samples from the first channel of the input audio file
|
||||
if( cmAudioFileReadSample(p->afH, frmCnt, chIdx, 1, chs, &actFrmCnt ) != kOkAfRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Audio file read failed.");
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Audio file read failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -515,7 +516,7 @@ cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
// write the audio output samples
|
||||
if( cmAudioFileWriteSample(afH, frmCnt, chCnt, chs ) != kOkAfRC )
|
||||
{
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Synchronized audio file write failed.");
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Synchronized audio file write failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -523,12 +524,12 @@ cmSrRC_t cmSyncRecdAudioFile( cmSyncRecdH_t h, const cmChar_t* fn )
|
||||
|
||||
errLabel:
|
||||
if( cmAudioFileDelete(&afH) != kOkAfRC )
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSrRC,"Synchronized audio file close failed.");
|
||||
rc = cmErrMsg(&p->err,kAudioFileFailSyRC,"Synchronized audio file close failed.");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
||||
cmSyRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
||||
{
|
||||
enum
|
||||
{
|
||||
@ -536,7 +537,7 @@ cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
||||
kTestFailRC,
|
||||
};
|
||||
|
||||
cmSrRC_t rc = kOkSrRC;
|
||||
cmSyRC_t rc = kOkSyRC;
|
||||
const cmChar_t* srFn = "/home/kevin/temp/kr/sr/sr0.sr";
|
||||
const cmChar_t* aFn = "/home/kevin/temp/kr/sr/sync_af.aiff";
|
||||
cmErr_t err;
|
||||
@ -545,7 +546,7 @@ cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
||||
cmErrSetup(&err,&ctx->rpt,"SyncRecdTest");
|
||||
|
||||
|
||||
if((rc = cmSyncRecdOpen(ctx, &srH, srFn )) != kOkSrRC )
|
||||
if((rc = cmSyncRecdOpen(ctx, &srH, srFn )) != kOkSyRC )
|
||||
{
|
||||
cmErrMsg(&err,kTestFailRC,"Sync-recd open failed.");
|
||||
goto errLabel;
|
||||
@ -555,7 +556,7 @@ cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx )
|
||||
cmSyncRecdAudioFile(srH,aFn);
|
||||
|
||||
errLabel:
|
||||
if((rc = cmSyncRecdFinal(&srH)) != kOkSrRC )
|
||||
if((rc = cmSyncRecdFinal(&srH)) != kOkSyRC )
|
||||
cmErrMsg(&err,kTestFailRC,"Sync-recd close failed.");
|
||||
|
||||
return rc;
|
||||
|
22
cmSyncRecd.h
22
cmSyncRecd.h
@ -7,26 +7,26 @@ extern "C" {
|
||||
|
||||
enum
|
||||
{
|
||||
kOkSrRC,
|
||||
kFileFailSrRC,
|
||||
kAudioFileFailSrRC,
|
||||
kInvalidOpSrRC
|
||||
kOkSyRC,
|
||||
kFileFailSyRC,
|
||||
kAudioFileFailSyRC,
|
||||
kInvalidOpSyRC
|
||||
};
|
||||
|
||||
typedef cmHandle_t cmSyncRecdH_t;
|
||||
typedef cmRC_t cmSrRC_t;
|
||||
typedef cmRC_t cmSyRC_t;
|
||||
extern cmSyncRecdH_t cmSyncRecdNullHandle;
|
||||
|
||||
cmSrRC_t cmSyncRecdCreate( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn, const cmChar_t* audioFn, double srate, unsigned chCnt, unsigned bits );
|
||||
cmSrRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn );
|
||||
cmSrRC_t cmSyncRecdFinal( cmSyncRecdH_t* hp );
|
||||
cmSyRC_t cmSyncRecdCreate( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn, const cmChar_t* audioFn, double srate, unsigned chCnt, unsigned bits );
|
||||
cmSyRC_t cmSyncRecdOpen( cmCtx_t* ctx, cmSyncRecdH_t* hp, const cmChar_t* srFn );
|
||||
cmSyRC_t cmSyncRecdFinal( cmSyncRecdH_t* hp );
|
||||
bool cmSyncRecdIsValid( cmSyncRecdH_t h );
|
||||
|
||||
cmSrRC_t cmSyncRecdMidiWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned status, unsigned d0, unsigned d1 );
|
||||
cmSrRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned smpIdx, const cmSample_t* ch[], unsigned chCnt, unsigned frmCnt );
|
||||
cmSyRC_t cmSyncRecdMidiWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned status, unsigned d0, unsigned d1 );
|
||||
cmSyRC_t cmSyncRecdAudioWrite( cmSyncRecdH_t h, const cmTimeSpec_t* timestamp, unsigned smpIdx, const cmSample_t* ch[], unsigned chCnt, unsigned frmCnt );
|
||||
|
||||
|
||||
cmSrRC_t cmSyncRecdTest( cmCtx_t* ctx );
|
||||
cmSyRC_t cmSyncRecdTest( cmCtx_t* ctx );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -2383,7 +2383,7 @@ cmDspRC_t _cmDspNanoMapSend( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned st, un
|
||||
|
||||
void _cmDspNanoMapPgm( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned pgm )
|
||||
{
|
||||
cmDspNanoMap_t* p = (cmDspNanoMap_t*)inst;
|
||||
//cmDspNanoMap_t* p = (cmDspNanoMap_t*)inst;
|
||||
|
||||
unsigned i;
|
||||
|
||||
@ -2430,7 +2430,7 @@ cmDspRC_t _cmDspNanoMapReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_
|
||||
|
||||
cmDspRC_t _cmDspNanoMapRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
|
||||
{
|
||||
cmDspNanoMap_t* p = (cmDspNanoMap_t*)inst;
|
||||
//cmDspNanoMap_t* p = (cmDspNanoMap_t*)inst;
|
||||
|
||||
switch( evt->dstVarId )
|
||||
{
|
||||
@ -3070,7 +3070,7 @@ cmDspRC_t _cmDspSyncRecdCreateFile( cmDspCtx_t* ctx, cmDspInst_t* inst )
|
||||
return cmDspInstErr(ctx,&p->inst,kFileSysFailDspRC,"Sync-recd file name generation failed for dir='%s' and prefix='%s'.",cmStringNullGuard(dir),cmStringNullGuard(srFn));
|
||||
|
||||
unsigned bits = cmDspUInt(inst,kBitsSrId);
|
||||
if( cmSyncRecdCreate( ctx->cmCtx, &p->srH, p->srFn, p->aFn, cmDspSampleRate(ctx), p->chCnt, bits ) != kOkSrRC )
|
||||
if( cmSyncRecdCreate( ctx->cmCtx, &p->srH, p->srFn, p->aFn, cmDspSampleRate(ctx), p->chCnt, bits ) != kOkSyRC )
|
||||
return cmDspInstErr(ctx,&p->inst,kSubSysFailDspRC,"Sync-recd file create failed for '%s'.",p->srFn);
|
||||
|
||||
p->smpIdx = 0;
|
||||
@ -3152,7 +3152,7 @@ cmDspRC_t _cmDspSyncRecdExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_
|
||||
}
|
||||
|
||||
if( n>0 && cmSyncRecdIsValid(p->srH ) )
|
||||
if( cmSyncRecdAudioWrite( p->srH, &ctx->ctx->iTimeStamp, p->smpIdx, x, p->chCnt, n ) != kOkSrRC )
|
||||
if( cmSyncRecdAudioWrite( p->srH, &ctx->ctx->iTimeStamp, p->smpIdx, x, p->chCnt, n ) != kOkSyRC )
|
||||
return cmDspInstErr(ctx,&p->inst,kSubSysFailDspRC,"Sync-recd audio update failed.");
|
||||
|
||||
p->smpIdx += n;
|
||||
@ -3179,7 +3179,7 @@ cmDspRC_t _cmDspSyncRecdRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_
|
||||
//printf("%i %i\n",cmDspUInt(inst,kD1SrId),cmTimeElapsedMicros(&ts,&p->ats));
|
||||
|
||||
if( cmSyncRecdIsValid(p->srH ) )
|
||||
if( cmSyncRecdMidiWrite(p->srH, &ts, cmDspUInt(inst,kStatusSrId), cmDspUInt(inst,kD0SrId), cmDspUInt(inst,kD1SrId) ) != kOkSrRC )
|
||||
if( cmSyncRecdMidiWrite(p->srH, &ts, cmDspUInt(inst,kStatusSrId), cmDspUInt(inst,kD0SrId), cmDspUInt(inst,kD1SrId) ) != kOkSyRC )
|
||||
return cmDspInstErr(ctx,&p->inst,kSubSysFailDspRC,"Sync-recd MIDI update failed.");
|
||||
}
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user