#include "cmPrefix.h" #include "cmGlobal.h" #include "cmFloatTypes.h" #include "cmComplexTypes.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmLinkedHeap.h" #include "cmSymTbl.h" #include "cmMath.h" #include "cmFile.h" #include "cmAudioFile.h" #include "cmJson.h" #include "cmFileSys.h" #include "cmTime.h" #include "cmMidi.h" #include "cmProcObj.h" #include "cmProcTemplateMain.h" #include "cmProc.h" #include "cmProc2.h" #include "cmVectOps.h" #include "cmFrameFile.h" #include "cmFeatFile.h" #include "cmSerialize.h" #define kConstQThresh (0.0054) enum { kFrameTypeFtId = 1, kFrameStreamFtId = 1, kStatRecdVectCnt = 8 // count of vectors in cmFtSumm_t }; // master control record typedef struct { cmErr_t err; cmCtx_t ctx; cmJsonH_t jsH; // cmSrH_t srH; // file header serializer cmFtAttr_t* attrArray; // unsigned attrCnt; // cmFtParam_t* paramArray; // unsigned paramCnt; // cmCtx* ctxPtr; // process context object cmAudioFileRd* afRdPtr; // audio file reader object cmPvAnl* pvocPtr; // phase vocoder object cmBfcc* bfccPtr; // BFCC generator cmMfcc* mfccPtr; // MFCC generator cmCeps* cepsPtr; // Cepstrum generator cmConstQ* constqPtr; // Const Q generator unsigned progParamIdx; unsigned progPassIdx; unsigned progSmpCnt; unsigned progSmpIdx; } _cmFt_t; // static feature values typedef struct { unsigned order; // determines the order the feature extractors are init'd and exec'd const char* label; // feature label unsigned id; // feature id unsigned ffMtxId; // cmFrameFile matrix type id unsigned ffUnitsId; // cmFrameFile data unit id unsigned srcId; // id of the source vector for this secondary feature (or kInvalidFtId if no src) bool bipolarFl; // this feature is bipolar unsigned maxCnt; // maximum feature vector element count (scalar==1 no max==0) } _cmFtLabel_t; // analysis control record - one recd per feature typedef struct _cmFtAttr_str { cmFtAttr_t* ap; // user supplied feature parameters const _cmFtLabel_t* lp; // static feature parameters cmFtSumm_t* sr; // summary record assoc'd with this feature struct _cmFtAttr_str* sp; // sourcePtr (used by secondary feats to locate primary feature) cmReal_t* v; // v[ap->cnt*2] feature vector memory used by cvp and pvp cmReal_t* cvp; // current feat vect cmReal_t* pvp; // previous feat vect } _cmFtAnl_t; // internal feature desc record typedef struct { const cmFtAttr_t* ap; const _cmFtLabel_t* lp; cmFtSumm_t* sr; } _cmFtDesc_t; // internal feature file control record - file handle record typedef struct { cmFtH_t h; // feat file library handle cmFrameFileH_t ffH; // handle for the frame file cmFtInfo_t info; // file hdr recd _cmFtDesc_t* descArray; // descArray[infoPtr->attrCnt] internal feature desc data void* hdrBuf; // memory used to hold the serialized header } _cmFtFile_t; cmFtH_t cmFtNullHandle = { NULL }; cmFtFileH_t cmFtFileNullHandle = { NULL }; _cmFtLabel_t _cmFtLabelArray[] = { { 0, "ampl", kAmplFtId, kMagMId, kAmplUId, kInvalidFtId, false, 0 }, { 1, "db_ampl", kDbAmplFtId, kMagMId, k20DbUId, kAmplFtId, false, 0 }, { 2, "pow", kPowFtId, kMagMId, kPowUId, kInvalidFtId, false, 0 }, { 3, "db_pow", kDbPowFtId, kMagMId, k10DbUId, kPowFtId, false, 0 }, { 4, "phase", kPhaseFtId, kPhsMId, kRadsUId, kInvalidFtId, false, 0 }, { 5, "bfcc", kBfccFtId, kBfccMId, kBfccUId, kInvalidFtId, false, kDefaultBarkBandCnt }, { 6, "mfcc", kMfccFtId, kMfccMId, kMfccUId, kInvalidFtId, false, kDefaultMelBandCnt }, { 7, "ceps", kCepsFtId, kCepsMId, kCepsUId, kInvalidFtId, false, 0 }, { 8, "constq", kConstQFtId, kConstqMId, kAmplUId, kInvalidFtId, false, 0 }, { 9, "log_constq", kLogConstQFtId, kConstqMId, k20DbUId, kConstQFtId, false, 0 }, { 10, "rms", kRmsFtId, kRmsMId, kAmplUId, kInvalidFtId, false, 1 }, { 11, "db_rms", kDbRmsFtId, kRmsMId, k20DbUId, kRmsFtId, false, 1 }, { 12, "d1_ampl", kD1AmplFtId, kMagMId, kAmplUId | kD1UFl, kAmplFtId, true, 0 }, { 13, "d1_db_ampl", kD1DbAmplFtId, kMagMId, k20DbUId | kD1UFl, kDbAmplFtId, true, 0 }, { 14, "d1_pow", kD1PowFtId, kMagMId, kPowUId | kD1UFl, kPowFtId, true, 0 }, { 15, "d1_db_pow", kD1DbPowFtId, kMagMId, k10DbUId | kD1UFl, kDbPowFtId, true, 0 }, { 16, "d1_phase", kD1PhaseFtId, kPhsMId, kRadsUId | kD1UFl, kPhaseFtId, true, 0 }, { 17, "d1_bfcc", kD1BfccFtId, kBfccMId, kBfccUId | kD1UFl, kBfccFtId, true, kDefaultBarkBandCnt }, { 18, "d1_mfcc", kD1MfccFtId, kMfccMId, kMfccUId | kD1UFl, kMfccFtId, true, kDefaultMelBandCnt }, { 19, "d1_ceps", kD1CepsFtId, kCepsMId, kCepsUId | kD1UFl, kCepsFtId, true, 0 }, { 20, "d1_constq", kD1ConstQFtId, kConstqMId, kAmplUId | kD1UFl, kConstQFtId, true, 0 }, { 21, "d1_log_constq", kD1LogConstQFtId,kConstqMId, k20DbUId | kD1UFl, kLogConstQFtId, true, 0 }, { 22, "d1_rms", kD1RmsFtId, kRmsMId, kAmplUId | kD1UFl, kRmsFtId, true, 1 }, { 23, "d1_db_rms", kD1DbRmsFtId, kRmsMId, k20DbUId | kD1UFl, kDbRmsFtId, true, 1 }, { 24, "", kInvalidFtId, kInvalidMId,kInvalidUId, kInvalidFtId, true, 0 } }; void _cmFtPrint( _cmFt_t* p, const char* fmt, ... ) { va_list vl; va_start(vl,fmt); cmRptVPrintf(&p->ctx.rpt,fmt,vl); va_end(vl); } cmFtRC_t _cmFtErrorV( cmFtRC_t rc, _cmFt_t* p, const char* fmt, va_list vl ) { return cmErrVMsg(&p->err,rc,fmt,vl); } cmFtRC_t _cmFtError( cmFtRC_t rc, _cmFt_t* p, const char* fmt, ... ) { va_list vl; va_start(vl,fmt); _cmFtErrorV(rc,p,fmt,vl); va_end(vl); return rc; } _cmFt_t* _cmFtHandleToPtr( cmFtH_t h ) { assert( h.h != NULL ); return (_cmFt_t*)h.h; } _cmFtFile_t* _cmFtFileHandleToPtr( cmFtFileH_t h ) { assert( h.h != NULL ); return (_cmFtFile_t*)h.h; } _cmFtLabel_t* _cmFtIdToLabelPtr( unsigned id ) { unsigned i=0; for(i=0; _cmFtLabelArray[i].id != kInvalidFtId; ++i) if( _cmFtLabelArray[i].id == id ) return _cmFtLabelArray + i; assert(0); return NULL; } enum { kInfoSrFtId = kStructSrId, kParamSrFtId, kSkipSrFtId, kAttrSrFtId, kStatSrFtId, kHdrSrFtId, kSkipVSrFtId = kSkipSrFtId + kArraySrFl, kAttrVSrFtId = kAttrSrFtId + kArraySrFl, kStatVSrFtId = kStatSrFtId + kArraySrFl }; cmFtRC_t _cmFtFormatFileHdr( _cmFt_t* p ) { cmFtRC_t rc = kOkFtRC; cmSrH_t h = p->srH; cmSrGetAndClearLastErrorCode(h); if( cmSrFmtReset( h ) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "Serializer format reset failed."); goto errLabel; } // cmFtSkip_t smpIdx smpCnt cmSrDefFmt( h, kSkipSrFtId, kUIntSrId, kUIntSrId, kInvalidSrId ); // cmFtAttr_t featId vect cnt normFl cmSrDefFmt( h, kAttrSrFtId, kUIntSrId, kUIntSrId, kBoolSrId, kInvalidSrId ); // cmFtParam_t cmSrDefFmt( h, kParamSrFtId, // audioFn featFn chIdx kCharVSrId, kCharVSrId, kUIntSrId, // wndMs hopFact normAudFl cqMinPitch cqMaxPitch kRealSrId, kUIntSrId, kBoolSrId, kUCharSrId, kUCharSrId, // cqBins minDb skipV attrV kUIntSrId, kRealSrId, kSkipVSrFtId, kAttrVSrFtId, kInvalidSrId ); // cmFtInfo_t cmSrDefFmt( h, kInfoSrFtId, // frmCnt srate fftSmpCnt hopSmpCnt binCnt skipFrmCnt floorFrmCnt param kUIntSrId, kRealSrId, kUIntSrId, kUIntSrId, kUIntSrId, kUIntSrId, kUIntSrId, kParamSrFtId, kInvalidSrId ); // cmFtSumm_t cmSrDefFmt( h, kStatSrFtId, // id cnt kUIntSrId, kUIntSrId, // raw minV maxV avgV std-dev kRealVSrId, kRealVSrId, kRealVSrId, kRealVSrId, // raw min max kRealSrId, kRealSrId, // norm minV maxV avgV std-dev kRealVSrId, kRealVSrId, kRealVSrId, kRealVSrId, // raw min max kRealSrId, kRealSrId, kInvalidSrId ); // master header record info stat array cmSrDefFmt( h, kHdrSrFtId, kInfoSrFtId, kStatVSrFtId, kInvalidSrId ); if( cmSrLastErrorCode(h) != kOkSrRC ) rc = _cmFtError( kSerialFailFtRC,p, "Serializer formatting failed."); errLabel: return rc; } cmFtRC_t _cmFtSerializeFileHdr( _cmFt_t* p, cmFtInfo_t* f, cmFtParam_t* pp, cmFtSumm_t* summArray, void** bufPtrPtr, unsigned* bufByteCntPtr ) { cmFtRC_t rc = kOkFtRC; cmSrH_t h = p->srH; unsigned i; cmSrWrReset(h); cmSrWrStructBegin(h, kHdrSrFtId ); // info record cmSrWrStruct( h, kInfoSrFtId, 1 ); cmSrWrStructBegin(h, kInfoSrFtId ); cmSrWrUInt( h, f->frmCnt ); cmSrWrReal( h, f->srate ); cmSrWrUInt( h, f->fftSmpCnt ); cmSrWrUInt( h, f->hopSmpCnt ); cmSrWrUInt( h, f->binCnt ); cmSrWrUInt( h, f->skipFrmCnt ); cmSrWrUInt( h, f->floorFrmCnt); // param recd cmSrWrStruct( h, kParamSrFtId, 1 ); cmSrWrStructBegin(h, kParamSrFtId ); cmSrWrCharV( h, pp->audioFn, strlen(pp->audioFn)+1); cmSrWrCharV( h, pp->featFn, strlen(pp->featFn)+1); cmSrWrUInt( h, pp->chIdx ); cmSrWrReal( h, pp->wndMs ); cmSrWrUInt( h, pp->hopFact); cmSrWrBool( h, pp->normAudioFl); cmSrWrUChar( h, pp->constQMinPitch); cmSrWrUChar( h, pp->constQMaxPitch); cmSrWrUInt( h, pp->constQBinsPerOctave); cmSrWrReal( h, pp->minDb ); // skip array cmSrWrStruct(h, kSkipSrFtId, pp->skipCnt ); for(i=0; iskipCnt; ++i) { cmSrWrStructBegin(h, kSkipSrFtId ); cmSrWrUInt( h, pp->skipArray[i].smpIdx); cmSrWrUInt( h, pp->skipArray[i].smpCnt); cmSrWrStructEnd(h); } // attr array cmSrWrStruct(h, kAttrSrFtId, pp->attrCnt ); for(i=0; iattrCnt; ++i) { cmSrWrStructBegin( h, kAttrSrFtId ); cmSrWrUInt( h, pp->attrArray[i].id ); cmSrWrUInt( h, pp->attrArray[i].cnt ); cmSrWrBool( h, pp->attrArray[i].normFl); cmSrWrStructEnd(h); } cmSrWrStructEnd(h); // end param cmSrWrStructEnd(h); // end info // write the status array cmSrWrStruct(h, kStatSrFtId, pp->attrCnt ); for(i=0; iattrCnt; ++i) { assert( summArray[i].id == pp->attrArray[i].id ); cmSrWrStructBegin(h,kStatSrFtId); cmSrWrUInt( h, summArray[i].id); cmSrWrUInt( h, summArray[i].cnt); cmSrWrRealV( h, summArray[i].rawMinV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].rawMaxV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].rawAvgV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].rawSdvV, pp->attrArray[i].cnt); cmSrWrReal( h, summArray[i].rawMin ); cmSrWrReal( h, summArray[i].rawMax ); cmSrWrRealV( h, summArray[i].normMinV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].normMaxV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].normAvgV, pp->attrArray[i].cnt); cmSrWrRealV( h, summArray[i].normSdvV, pp->attrArray[i].cnt); cmSrWrReal( h, summArray[i].normMin ); cmSrWrReal( h, summArray[i].normMax ); cmSrWrStructEnd(h); } if( cmSrLastErrorCode(h) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "Header serialization failed."); goto errLabel; } if((*bufPtrPtr = cmSrWrAllocBuf(h,bufByteCntPtr)) == NULL ) { rc = _cmFtError( kSerialFailFtRC, p, "Header serializer failed on write buffer allocation."); goto errLabel; } errLabel: return rc; } cmFtRC_t _cmDeserializeFileHdr( _cmFt_t* p, _cmFtFile_t* fp, void* buf, unsigned bufByteCnt ) { cmFtRC_t rc = kOkFtRC; cmSrH_t h = p->srH; unsigned n,i; cmFtInfo_t* f = &fp->info; cmFtParam_t* pp = &fp->info.param; // do endian swap if( cmSrRdProcessBuffer(h, buf, bufByteCnt ) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "Deserializatoin buffer pre-process failed."); goto errLabel; } // duplciate the buffer - this will allow us to use memory in the buffer to hold header objects. fp->hdrBuf = cmMemResize( char, fp->hdrBuf, bufByteCnt ); memcpy(fp->hdrBuf,buf,bufByteCnt); // setup the serializer reader if( cmSrRdSetup( h, fp->hdrBuf, bufByteCnt ) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "Deserialization buffer setup failed."); goto errLabel; } cmSrRdStructBegin(h, kHdrSrFtId ); // info record cmSrReadStruct( h, kInfoSrFtId, &n ); assert(n==1); cmSrRdStructBegin(h, kInfoSrFtId ); cmSrReadUInt( h, &f->frmCnt ); cmSrReadReal( h, &f->srate ); cmSrReadUInt( h, &f->fftSmpCnt ); cmSrReadUInt( h, &f->hopSmpCnt ); cmSrReadUInt( h, &f->binCnt ); cmSrReadUInt( h, &f->skipFrmCnt ); cmSrReadUInt( h, &f->floorFrmCnt ); // param recd cmSrReadStruct( h, kParamSrFtId, &n ); assert(n==1); cmSrRdStructBegin(h, kParamSrFtId ); cmSrReadCharCV(h, &pp->audioFn, &n ); cmSrReadCharCV(h, &pp->featFn, &n ); cmSrReadUInt( h, &pp->chIdx ); cmSrReadReal( h, &pp->wndMs ); cmSrReadUInt( h, &pp->hopFact); cmSrReadBool( h, &pp->normAudioFl); cmSrReadUChar( h, &pp->constQMinPitch); cmSrReadUChar( h, &pp->constQMaxPitch); cmSrReadUInt( h, &pp->constQBinsPerOctave); cmSrReadReal( h, &pp->minDb ); // skip array cmSrReadStruct(h, kSkipSrFtId, &pp->skipCnt ); pp->skipArray = cmMemResizeZ( cmFtSkip_t, pp->skipArray, pp->skipCnt ); for(i=0; iskipCnt; ++i) { cmSrRdStructBegin(h, kSkipSrFtId ); cmSrReadUInt( h, &pp->skipArray[i].smpIdx); cmSrReadUInt( h, &pp->skipArray[i].smpCnt); cmSrRdStructEnd(h); } // attr array cmSrReadStruct(h, kAttrSrFtId, &pp->attrCnt ); pp->attrArray = cmMemResizeZ( cmFtAttr_t, pp->attrArray, pp->attrCnt ); for(i=0; iattrCnt; ++i) { cmSrRdStructBegin( h, kAttrSrFtId ); cmSrReadUInt( h, &pp->attrArray[i].id ); cmSrReadUInt( h, &pp->attrArray[i].cnt ); cmSrReadBool( h, &pp->attrArray[i].normFl); cmSrRdStructEnd(h); } cmSrRdStructEnd(h); // end param cmSrRdStructEnd(h); // end info // read the status array cmSrReadStruct(h, kStatSrFtId, &n ); assert( n == pp->attrCnt ); fp->info.summArray = cmMemResizeZ( cmFtSumm_t, fp->info.summArray, pp->attrCnt ); for(i=0; iattrCnt; ++i) { cmSrRdStructBegin(h,kStatSrFtId); cmSrReadUInt( h, &fp->info.summArray[i].id); assert( fp->info.summArray[i].id == pp->attrArray[i].id ); cmSrReadUInt( h, &fp->info.summArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].rawMinV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].rawMaxV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].rawAvgV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].rawSdvV, &pp->attrArray[i].cnt); cmSrReadReal( h, &fp->info.summArray[i].rawMin ); cmSrReadReal( h, &fp->info.summArray[i].rawMax ); cmSrReadRealV( h, &fp->info.summArray[i].normMinV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].normMaxV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].normAvgV, &pp->attrArray[i].cnt); cmSrReadRealV( h, &fp->info.summArray[i].normSdvV, &pp->attrArray[i].cnt); cmSrReadReal( h, &fp->info.summArray[i].normMin ); cmSrReadReal( h, &fp->info.summArray[i].normMax ); cmSrRdStructEnd(h); } if( cmSrLastErrorCode(h) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "Deserialization failed."); goto errLabel; } errLabel: return rc; } unsigned cmFtFeatLabelToId( const char* label ) { unsigned i=0; for(i=0; _cmFtLabelArray[i].id != kInvalidFtId; ++i) if( strcmp(label,_cmFtLabelArray[i].label) == 0 ) return _cmFtLabelArray[i].id; return kInvalidFtId; } const char* cmFtFeatIdToLabel( unsigned id ) { unsigned i=0; for(i=0; _cmFtLabelArray[i].id != kInvalidFtId; ++i) if( _cmFtLabelArray[i].id == id ) return _cmFtLabelArray[i].label; return NULL; } cmFtRC_t cmFtInitialize( cmFtH_t* hp, cmCtx_t* ctx ) { cmFtRC_t rc; if((rc = cmFtFinalize(hp)) != kOkFtRC ) return rc; _cmFt_t* p = cmMemAllocZ( _cmFt_t, 1 ); cmErrSetup(&p->err,&ctx->rpt,"Feature file"); p->ctx = *ctx; p->jsH = cmJsonNullHandle; p->progParamIdx = cmInvalidIdx; p->progPassIdx = 0; p->progSmpIdx = 0; p->progSmpCnt = 0; // initialize the serializer if( cmSrAlloc(&p->srH,ctx) != kOkSrRC ) { rc = _cmFtError( kSerialFailFtRC, p, "The serializer allocation failed."); goto errLabel; } // setup the serializer format if((rc = _cmFtFormatFileHdr(p)) != kOkFtRC ) goto errLabel; // create the proc context object if((p->ctxPtr = cmCtxAlloc(NULL,&p->ctx.rpt,cmLHeapNullHandle,cmSymTblNullHandle)) == NULL ) { rc = _cmFtError(kDspProcFailFtRC,p, "The ctx compoenent allocation failed."); goto errLabel; } // create the audio file reader if((p->afRdPtr = cmAudioFileRdAlloc( p->ctxPtr, NULL, 0, NULL, cmInvalidIdx, 0, cmInvalidIdx )) == NULL ) { rc = _cmFtError( kDspProcFailFtRC, p, "The audio file reader allocation failed."); goto errLabel; } // create the phase vocoder if((p->pvocPtr = cmPvAnlAlloc( p->ctxPtr, NULL, 0, 0, 0, 0, 0 )) == NULL ) { rc = _cmFtError( kDspProcFailFtRC,p,"The phase vocoder allocation failed."); goto errLabel; } // create the BFCC transformer if((p->bfccPtr = cmBfccAlloc( p->ctxPtr, NULL, 0, 0, 0 )) == NULL ) { rc = _cmFtError( kDspProcFailFtRC,p,"The BFCC generator allocation failed."); goto errLabel; } // create the MFCC generator if((p->mfccPtr = cmMfccAlloc( p->ctxPtr, NULL, 0, 0, 0, 0)) == NULL ) { rc = _cmFtError( kDspProcFailFtRC,p,"The MFCC generator allocation failed."); goto errLabel; } // create the Cepstrum transformer if((p->cepsPtr = cmCepsAlloc( p->ctxPtr, NULL, 0, 0 )) == NULL ) { rc = _cmFtError( kDspProcFailFtRC,p,"The Cepstrum generator allocation failed."); goto errLabel; } // create the Constant Q generator if((p->constqPtr = cmConstQAlloc( p->ctxPtr, NULL, 0, 0, 0, 0,0 )) == NULL ) { rc = _cmFtError( kDspProcFailFtRC,p,"The Constant-Q generator allocation failed."); goto errLabel; } hp->h = p; errLabel: return rc; } cmFtRC_t cmFtFinalize( cmFtH_t* hp ) { cmFtRC_t rc = kOkFsRC; unsigned i; assert( hp != NULL ); if( hp->h == NULL ) return kOkFsRC; _cmFt_t* p = _cmFtHandleToPtr(*hp); for(i=0; iparamCnt; ++i) cmMemPtrFree(&p->paramArray[i].skipArray); cmMemPtrFree(&p->attrArray); p->attrCnt = 0; cmMemPtrFree(&p->paramArray); p->paramCnt = 0; if( cmConstQFree(&p->constqPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"Constant-Q generator free failed."); goto errLabel; } if( cmCepsFree(&p->cepsPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"Cepstrum generator free failed."); goto errLabel; } if( cmMfccFree(&p->mfccPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"MFCC generator free failed."); goto errLabel; } if( cmBfccFree(&p->bfccPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"BFCC generator free failed."); goto errLabel; } if( cmPvAnlFree(&p->pvocPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"Phase voocoder free failed."); goto errLabel; } if( cmAudioFileRdFree(&p->afRdPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"Audio file reader failed."); goto errLabel; } if( cmCtxFree(&p->ctxPtr) != cmOkRC ) { rc = _cmFtError( kDspProcFailFtRC,p,"Context proc failed."); goto errLabel; } if( cmJsonFinalize(&p->jsH) != kOkJsRC ) { rc = _cmFtError(kJsonFailFtRC, p, "The JSON system object finalization failed."); goto errLabel; } if( cmSrFree(&p->srH) != kOkSrRC ) { rc = _cmFtError(kSerialFailFtRC, p, "The serializer free failed."); goto errLabel; } cmMemPtrFree(&p); hp->h = NULL; errLabel: return rc; } bool cmFtIsValid( cmFtH_t h ) { return h.h != NULL; } cmFtRC_t cmFtParse( cmFtH_t h, const char* cfgFn ) { cmFtRC_t rc = kOkFtRC; cmJsRC_t jsRC = kOkJsRC; cmJsonNode_t* rootPtr = NULL; const char* errLabelPtr = NULL; const char* outDir = NULL; cmReal_t wndMs = 0; unsigned hopFact = 0; bool normAudioFl = false; const char* constQMinPitchStr = NULL; const char* constQMaxPitchStr = NULL; unsigned constQBinsPerOctave = 0; cmMidiByte_t constQMinPitch = 0; cmMidiByte_t constQMaxPitch = 0; cmReal_t minDb = 0; cmReal_t floorThreshDb = 0; cmJsonNode_t* featArrayNodePtr = NULL; cmJsonNode_t* audioFnArrayNodePtr = NULL; _cmFt_t* p = _cmFtHandleToPtr(h); unsigned i,j; assert( cfgFn != NULL ); // parse file if( cmJsonInitializeFromFile( &p->jsH, cfgFn, &p->ctx ) != kOkJsRC ) { rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. file parse failed on: '%s'", cfgFn ); goto errLabel; } // get the json cfg root if( (rootPtr = cmJsonRoot( p->jsH )) == NULL ) { rc = _cmFtError( kCfgParseFailFtRC, p, "The cfg. file '%s' appears to be empty.", cfgFn ); goto errLabel; } // read the cfg file header if((jsRC = cmJsonMemberValues( rootPtr, &errLabelPtr, "outDir", kStringTId, &outDir, "wndMs", kRealTId, &wndMs, "hopFact", kIntTId, &hopFact, "normAudioFl", kTrueTId, &normAudioFl, "constQMinPitch", kStringTId, &constQMinPitchStr, "constQMaxPitch", kStringTId, &constQMaxPitchStr, "constQBinsPerOctave", kIntTId, &constQBinsPerOctave, "minDb", kRealTId, &minDb, "floorThreshDb", kRealTId, &floorThreshDb, "featArray", kArrayTId, &featArrayNodePtr, "audioFnArray", kArrayTId, &audioFnArrayNodePtr, NULL )) != kOkJsRC ) { if( jsRC == kNodeNotFoundJsRC ) rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. field not found:'%s' in file:'%s'.",cmStringNullGuard(errLabelPtr),cmStringNullGuard(cfgFn)); else rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. header parse failed '%s'.",cmStringNullGuard(cfgFn) ); goto errLabel; } // convert the min const-q sci pitch string to a midi pitch value if( (constQMinPitch = cmSciPitchToMidi( constQMinPitchStr )) == kInvalidMidiPitch ) { rc = _cmFtError( kCfgParseFailFtRC, p, "The const-Q min. pitch ('%s') is invalid.", cmStringNullGuard(constQMinPitchStr)); goto errLabel; } // convert the max const-q sci pitch string to a midi pitch value if( (constQMaxPitch = cmSciPitchToMidi( constQMaxPitchStr )) == kInvalidMidiPitch ) { rc = _cmFtError( kCfgParseFailFtRC, p, "The const-Q max. pitch ('%s') is invalid.", cmStringNullGuard(constQMaxPitchStr)); goto errLabel; } unsigned parseAttrCnt = cmJsonChildCount( featArrayNodePtr ); p->attrArray = cmMemAllocZ( cmFtAttr_t, parseAttrCnt ); // read the attribute array for(i=0,j=0; iattrArray[j].cnt = 0; p->attrArray[j].enableFl = true; if((jsRC = cmJsonMemberValues( cmJsonArrayElement(featArrayNodePtr,i), &errLabelPtr, "feat", kStringTId, &featLabel, "cnt", kIntTId | kOptArgJsFl, &p->attrArray[j].cnt, "normFl", kTrueTId, &p->attrArray[j].normFl, "enableFl", kTrueTId | kOptArgJsFl, &p->attrArray[j].enableFl, NULL )) != kOkJsRC ) { if( jsRC == kNodeNotFoundJsRC ) rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. feature attribute field:'%s' not found at index %i in file:'%s'.",cmStringNullGuard(errLabelPtr),i,cmStringNullGuard(cfgFn)); else rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. feature attribute parse failed at index %i in '%s'.",i,cmStringNullGuard(cfgFn) ); goto errLabel; } if( p->attrArray[j].enableFl ) { // convert the feature label to an id if( (p->attrArray[j].id = cmFtFeatLabelToId( featLabel)) == kInvalidFtId ) { rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. feature '%s' was not found at featArray index %i in '%s'.", featLabel, i, cmStringNullGuard(cfgFn)); goto errLabel; } ++j; } } p->attrCnt = j; p->paramCnt = cmJsonChildCount( audioFnArrayNodePtr ); p->paramArray = cmMemAllocZ( cmFtParam_t, p->paramCnt ); // read the audio file array for(i=0; iparamCnt; ++i) { cmJsonNode_t* skipArrayNodePtr = NULL; // read the audio file read if((jsRC = cmJsonMemberValues( cmJsonArrayElement(audioFnArrayNodePtr,i), &errLabelPtr, "audioFn", kStringTId, &p->paramArray[i].audioFn, "featFn", kStringTId, &p->paramArray[i].featFn, "skipArray",kArrayTId | kOptArgJsFl, &skipArrayNodePtr, "chIdx", kIntTId, &p->paramArray[i].chIdx, NULL)) != kOkJsRC ) { if( jsRC == kNodeNotFoundJsRC ) rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. audio file field :'%s' not found at index %i in file:'%s'.",cmStringNullGuard(errLabelPtr),i,cmStringNullGuard(cfgFn)); else rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. audio file parse failed at index %i in '%s'.",i,cmStringNullGuard(cfgFn) ); goto errLabel; } p->paramArray[i].wndMs = wndMs; p->paramArray[i].hopFact = hopFact; p->paramArray[i].normAudioFl = normAudioFl; p->paramArray[i].constQBinsPerOctave = constQBinsPerOctave; p->paramArray[i].constQMinPitch = constQMinPitch; p->paramArray[i].constQMaxPitch = constQMaxPitch; p->paramArray[i].minDb = minDb; p->paramArray[i].floorThreshDb = floorThreshDb; p->paramArray[i].attrArray = p->attrArray; p->paramArray[i].attrCnt = p->attrCnt; p->paramArray[i].skipCnt = skipArrayNodePtr==NULL ? 0 : cmJsonChildCount( skipArrayNodePtr ); p->paramArray[i].skipArray = skipArrayNodePtr==NULL ? NULL : cmMemAllocZ( cmFtSkip_t, p->paramArray[i].skipCnt ); // read the skip array in the audio file recd for(j=0; jparamArray[i].skipCnt; ++j) { if((jsRC = cmJsonMemberValues( cmJsonArrayElement(skipArrayNodePtr,j), &errLabelPtr, "smpIdx", kIntTId, &p->paramArray[i].skipArray[j].smpIdx, "smpCnt", kIntTId, &p->paramArray[i].skipArray[j].smpCnt, NULL)) != kOkJsRC ) { if( jsRC == kNodeNotFoundJsRC ) rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. audio file skip field '%s' not found at index %i in file:'%s'.",cmStringNullGuard(errLabelPtr),j,cmStringNullGuard(cfgFn)); else rc = _cmFtError( kCfgParseFailFtRC, p, "Cfg. audio file skip parse failed at index %i in '%s'.",j, cmStringNullGuard(cfgFn) ); goto errLabel; } } // if the audio file does not exist if( cmFsIsFile( p->paramArray[i].audioFn ) == false ) { rc = _cmFtError( kFileNotFoundFtRC, p, "The audio file '%s' was not found.", p->paramArray[i].audioFn ); goto errLabel; } // form the feature file name for this file if((p->paramArray[i].featFn = cmFsMakeFn( outDir, p->paramArray[i].featFn, NULL, NULL )) == NULL ) { rc = _cmFtError( kFileSysFailFtRC, p, "The attempt to create the feature file name for '%s' failed.", cmStringNullGuard(p->paramArray[i].featFn)); goto errLabel; } } // if the output directory does not exist then create it if( cmFsIsDir(outDir) == false ) if( cmFsMkDir(outDir) != kOkFsRC ) { rc = _cmFtError( kDirCreateFailFtRC, p, "The attempt to create the output directory '%s' failed.",outDir); goto errLabel; } errLabel: return rc; } bool _cmFtZeroSkipSamples( const cmFtParam_t* pp, cmSample_t* v, unsigned vn, unsigned begSmpIdx ) { unsigned endSmpIdx = begSmpIdx + vn - 1; bool retFl = false; unsigned i = 0; const cmFtSkip_t* sp = pp->skipArray; // for each skipArray[] record for(i=0; iskipCnt; ++sp,++i) if( sp->smpCnt != 0 ) { unsigned bi = 0; unsigned ei = vn-1; unsigned sp_endIdx; // if sp->smpCnt is negative then skip to end of file if( sp->smpCnt == -1 ) sp_endIdx = endSmpIdx; else sp_endIdx = sp->smpIdx + sp->smpCnt - 1; // begSmpIdx:endSmpIdx indicate the index range of v[] // sp->smpIdx:sp_endIdx indicate the skip index range // if the skip range is entirely before or after v[] if( sp_endIdx < begSmpIdx || sp->smpIdx > endSmpIdx ) continue; // if sp->smpIdx is inside v[] if( sp->smpIdx > begSmpIdx ) bi = sp->smpIdx - begSmpIdx; // if sp_endIdx is inside v[] if( sp_endIdx < endSmpIdx ) { assert( endSmpIdx - sp_endIdx <= ei ); ei -= endSmpIdx - sp_endIdx; } assert( bi <= ei ); assert( bi < vn && ei < vn ); // zero the samples which are inside the skip range cmVOS_Zero(v+bi,(ei-bi)+1); retFl = true; } return retFl; } cmFtRC_t _cmFtProcInit( _cmFt_t* p, cmFtInfo_t* f, cmFtParam_t* pp, _cmFtAnl_t* anlArray ) { cmFtRC_t rc = kOkFtRC; unsigned i; // initialize the phase vocoder if( cmPvAnlInit( p->pvocPtr, f->hopSmpCnt, f->srate, f->fftSmpCnt, f->hopSmpCnt, kNoCalcHzPvaFl ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p," The phase vocoder initialization failed."); goto errLabel; } assert( f->binCnt == p->pvocPtr->binCnt ); cmReal_t binHz = f->srate / f->fftSmpCnt; // initialize each requested feature extractor for(i=0; iattrCnt; ++i) { _cmFtAnl_t* a = anlArray + i; assert( a->lp != NULL ); switch( a->ap->id ) { case kAmplFtId: case kDbAmplFtId: case kPowFtId: case kDbPowFtId: case kPhaseFtId: if( a->ap->cnt > f->binCnt ) { rc = _cmFtError(kParamRangeFtRC,p,"The '%s' cnt value: %i must be less than the bin count: %i.",a->lp->label,a->ap->cnt,f->binCnt+1); goto errLabel; } if( a->ap->cnt == 0 ) a->ap->cnt = f->binCnt; break; case kBfccFtId: // initialize the BFCC generator if( a->ap->cnt > kDefaultBarkBandCnt ) { rc = _cmFtError(kParamRangeFtRC,p,"The BFCC feature vector length (%i) must be less than (%i).", a->ap->cnt, kDefaultBarkBandCnt+1 ); goto errLabel; } if( a->ap->cnt == 0 ) a->ap->cnt = kDefaultBarkBandCnt; if( cmBfccInit( p->bfccPtr, kDefaultBarkBandCnt, p->pvocPtr->binCnt, binHz ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p," The BFCC generator initialization failed."); goto errLabel; } break; case kMfccFtId: // initialize the MFCC generator if( a->ap->cnt > kDefaultMelBandCnt ) { rc = _cmFtError(kParamRangeFtRC,p,"The MFCC feature vector length (%i) must be less than (%i).", a->ap->cnt, kDefaultMelBandCnt+1 ); goto errLabel; } if( a->ap->cnt == 0 ) a->ap->cnt = kDefaultMelBandCnt; if( cmMfccInit( p->mfccPtr, f->srate, kDefaultMelBandCnt, a->ap->cnt, p->pvocPtr->binCnt ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p," The MFCC generator initialization failed."); goto errLabel; } break; case kCepsFtId: // initialize the cepstrum generator if( a->ap->cnt > f->binCnt ) { rc = _cmFtError(kParamRangeFtRC,p,"The '%s' cnt value: %i must be less than the bin count: %i.",a->lp->label,a->ap->cnt,f->binCnt+1); goto errLabel; } if( a->ap->cnt == 0 ) a->ap->cnt = f->binCnt; if( cmCepsInit( p->cepsPtr, p->pvocPtr->binCnt, a->ap->cnt ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p," The Cepstrum generator initialization failed."); goto errLabel; } break; case kConstQFtId: // initialize the constant Q generator case kLogConstQFtId: if( cmConstQInit(p->constqPtr, f->srate, pp->constQMinPitch, pp->constQMaxPitch, pp->constQBinsPerOctave, kConstQThresh ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p,"The constant-q generator initialization failed."); goto errLabel; } if( a->ap->cnt > p->constqPtr->constQBinCnt ) { rc = _cmFtError(kParamRangeFtRC,p,"The '%s' cnt value: %i must be less than the bin count: %i.",a->lp->label,a->ap->cnt,p->constqPtr->constQBinCnt+1); goto errLabel; } if( a->ap->cnt == 0 ) a->ap->cnt = p->constqPtr->constQBinCnt; break; case kRmsFtId: case kDbRmsFtId: a->ap->cnt = 1; // scalars must have a cnt == 1 break; case kD1AmplFtId: case kD1DbAmplFtId: case kD1PowFtId: case kD1DbPowFtId: case kD1PhaseFtId: case kD1BfccFtId: case kD1MfccFtId: case kD1CepsFtId: case kD1ConstQFtId: case kD1LogConstQFtId: if( a->ap->cnt == 0 ) a->ap->cnt = a->sp->ap->cnt; break; case kD1RmsFtId: case kD1DbRmsFtId: a->ap->cnt = 1; break; default: { assert(0); } } // end switch // setup the feature label record and allocate the feature vector if( a->ap->cnt ) { // 2==cvp and pvp + kStatRecdVectCnt==count of summary vectors unsigned nn = a->ap->cnt * (2 + kStatRecdVectCnt); unsigned n = 0; assert(a->v == NULL); a->v = cmMemAllocZ( cmReal_t, nn ); a->cvp = a->v + n; n += a->ap->cnt; a->pvp = a->v + n; n += a->ap->cnt; a->sr->cnt = a->ap->cnt; a->sr->rawMinV = a->v + n; n += a->ap->cnt; a->sr->rawMaxV = a->v + n; n += a->ap->cnt; a->sr->rawAvgV = a->v + n; n += a->ap->cnt; a->sr->rawSdvV = a->v + n; n += a->ap->cnt; a->sr->rawMin = cmReal_MAX; a->sr->rawMax = -cmReal_MAX; cmVOR_Fill( a->sr->rawMinV, a->ap->cnt, cmReal_MAX ); cmVOR_Fill( a->sr->rawMaxV, a->ap->cnt, -cmReal_MAX ); a->sr->normMinV = a->v + n; n += a->ap->cnt; a->sr->normMaxV = a->v + n; n += a->ap->cnt; a->sr->normAvgV = a->v + n; n += a->ap->cnt; a->sr->normSdvV = a->v + n; n += a->ap->cnt; a->sr->normMin = cmReal_MAX; a->sr->normMax = -cmReal_MAX; cmVOR_Fill( a->sr->normMinV, a->ap->cnt, cmReal_MAX ); cmVOR_Fill( a->sr->normMaxV, a->ap->cnt, -cmReal_MAX ); assert(n == nn); } if( a->sp != NULL ) { if( a->sp->ap->cnt > a->ap->cnt ) { rc = _cmFtError( kParamRangeFtRC,p,"The feature element count '%i' for '%s' is greater than the source vector '%s' '%i'.", a->ap->cnt, a->lp->label, a->sp->lp->label, a->sp->ap->cnt ); goto errLabel; } } } // end for errLabel: return rc; } cmFtRC_t _cmFtProcExec( _cmFt_t* p, cmFtInfo_t* f, cmFtParam_t* pp, cmFrameFileH_t ffH, _cmFtAnl_t* anlArray, const cmSample_t* audV ) { cmFtRC_t rc = kOkFtRC; unsigned i; for(i=0; i < pp->attrCnt; ++i) { _cmFtAnl_t* a = anlArray + i; // swap current and previous pointer cmReal_t* tp = a->cvp; a->cvp = a->pvp; a->pvp = tp; switch( a->lp->id ) { case kAmplFtId: cmVOR_Copy(a->cvp, a->ap->cnt, p->pvocPtr->magV ); break; case kDbAmplFtId: cmVOR_AmplToDbVV( a->cvp, a->ap->cnt, p->pvocPtr->magV, pp->minDb ); break; case kPowFtId: cmVOR_PowVVS( a->cvp, a->ap->cnt, p->pvocPtr->magV, 2.0 ); break; case kDbPowFtId: cmVOR_PowToDbVV( a->cvp, a->ap->cnt, a->sp->cvp, pp->minDb ); break; case kPhaseFtId: cmVOR_Copy( a->cvp, a->ap->cnt, p->pvocPtr->phsV ); break; case kBfccFtId: { cmBfccExec( p->bfccPtr, p->pvocPtr->magV, p->pvocPtr->binCnt ); cmVOR_Copy(a->cvp, a->ap->cnt, p->bfccPtr->outV ); } break; case kMfccFtId: { cmMfccExecAmplitude( p->mfccPtr, p->pvocPtr->magV, p->pvocPtr->binCnt ); cmVOR_Copy( a->cvp, a->ap->cnt, p->mfccPtr->outV ); } break; case kCepsFtId: { cmCepsExec( p->cepsPtr, p->pvocPtr->magV, p->pvocPtr->phsV, p->pvocPtr->binCnt ); cmVOR_Copy(a->cvp, a->ap->cnt, p->cepsPtr->outV ); } break; case kConstQFtId: { // convert from float complex to double complex cmComplexR_t tmp0[ p->pvocPtr->binCnt ]; unsigned j; for(j=0; jpvocPtr->binCnt; ++j) tmp0[j] = p->pvocPtr->ft.complexV[j]; cmConstQExec( p->constqPtr, tmp0, p->pvocPtr->binCnt ); cmVOR_Copy( a->cvp, a->ap->cnt, p->constqPtr->magV ); } break; case kLogConstQFtId: cmVOR_LogV( a->cvp, a->ap->cnt, p->constqPtr->magV ); break; case kRmsFtId: a->cvp[0] = cmVOS_RMS( audV, p->afRdPtr->outN, p->afRdPtr->outN ); break; case kDbRmsFtId: cmVOR_AmplToDbVV( a->cvp, 1, a->sp->cvp, pp->minDb ); break; case kD1AmplFtId: case kD1DbAmplFtId: case kD1PowFtId: case kD1DbPowFtId: case kD1PhaseFtId: case kD1BfccFtId: case kD1MfccFtId: case kD1CepsFtId: case kD1ConstQFtId: case kD1LogConstQFtId: case kD1RmsFtId: case kD1DbRmsFtId: cmVOR_SubVVV( a->cvp, a->ap->cnt, a->sp->pvp, a->sp->cvp ); break; default: assert(0); break; } // end switch if( cmFrameFileWriteMtxReal( ffH, a->lp->ffMtxId, a->lp->ffUnitsId, a->cvp, a->ap->cnt, 1 ) != kOkFfRC ) { rc = _cmFtError( kFrameWriteFailFtRC, p, "Matrix write failed (feature:%s size:%i).",a->lp->label,a->ap->cnt); goto errLabel; } } errLabel: return rc; } unsigned _cmFtWriteField( char* buf, unsigned bufByteCnt, unsigned bufIdx, const void* s, unsigned srcByteCnt ) { assert( bufIdx + srcByteCnt <= bufByteCnt ); memcpy(buf+bufIdx,s,srcByteCnt); return bufIdx + srcByteCnt; } cmFtRC_t _cmFtWriteFileHdr( _cmFt_t* p, cmFtInfo_t* f, cmFtParam_t* pp, cmFrameFileH_t ffH, cmFtSumm_t* summArray, bool updateFl ) { cmFtRC_t rc = kOkFtRC; void* buf; unsigned bufByteCnt; // serialize the file header if((rc = _cmFtSerializeFileHdr(p,f,pp,summArray,&buf,&bufByteCnt)) != kOkFtRC ) goto errLabel; if( updateFl ) { const cmFfMtx_t* mp = NULL; void* hdrPtr = NULL; if( (hdrPtr = cmFrameFileMtxBlob(ffH, kDataMId, kNoUnitsUId, &mp )) == NULL ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file header read before update failed."); goto errLabel; } assert( mp->rowCnt == bufByteCnt ); memcpy( hdrPtr, buf, bufByteCnt ); } else { if( cmFrameFileWriteMtxBlob( ffH, kDataMId, kNoUnitsUId, buf, bufByteCnt, 1 ) != kOkFfRC ) { rc = _cmFtError( kFrameWriteFailFtRC, p, "Header write failed."); goto errLabel; } } errLabel: return rc; } // Interface to the _cmFtProcFile() user programmable process function. // This function is called once per each feature vector in the feature file. // v[fn] points to the feature file. // Return true if the feature has been modified and should be written back to disk. typedef bool (*_cmFtProcFunc_t)( _cmFt_t* p, _cmFtAnl_t* a, cmReal_t* v, unsigned vn ); // Iterate through each frame and each frame matrix call procFunc(). cmFtRC_t _cmFtProcFile( _cmFt_t* p, cmFrameFileH_t ffH, cmFtParam_t* pp, _cmFtAnl_t* anlArray, _cmFtProcFunc_t procFunc ) { cmFtRC_t rc = kOkFtRC; cmFfRC_t ffRC = kOkFfRC; unsigned i,j; ++p->progPassIdx; p->progSmpIdx = 0; p->progSmpCnt = cmFrameFileDesc( ffH )->frameCnt; // rewind the frame file if( cmFrameFileRewind( ffH ) != kOkFfRC ) { rc = _cmFtError(kFrameFileFailFtRC,p,"Normalize rewind failed on '%s'.", cmStringNullGuard(pp->featFn)); goto errLabel; } // load the next data frame for(i=0; (ffRC=cmFrameFileFrameLoadNext(ffH,kFrameTypeFtId,kFrameStreamFtId,NULL)) == kOkFfRC; ++i,++p->progSmpIdx) { bool updateFl = false; // for each feature matrix for(j=0; jattrCnt; ++j) { unsigned dn; cmReal_t* dp; const cmFfMtx_t* mtxDescPtr = NULL; _cmFtAnl_t* a = anlArray + j; // get a pointer to the matrix data if((dp = cmFrameFileMtxReal( ffH, a->lp->ffMtxId, a->lp->ffUnitsId, &mtxDescPtr )) == NULL ) { rc = _cmFtError(kFrameFileFailFtRC,p,"Data access failed during post processing on feature:'%s' in '%s'.", a->lp->label,cmStringNullGuard(pp->featFn)); goto errLabel; } // get the lenth of the feature vector dn = mtxDescPtr->rowCnt*mtxDescPtr->colCnt; // processes this feature if( procFunc(p,a,dp,dn) ) updateFl = true; } // write the frame back to disk if( updateFl ) if( cmFrameFileFrameUpdate(ffH) != kOkFfRC ) { rc = _cmFtError(kFrameFileFailFtRC,p,"Post procssing failed on record index %i in '%s'.", i, cmStringNullGuard(pp->featFn)); goto errLabel; } } if( ffRC != kEofFfRC && ffRC != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC,p,"Post processing iterationg failed on record index %i in '%s'.",i,cmStringNullGuard(pp->featFn)); goto errLabel; } errLabel: return rc; } // Sum the feature vector into a->sr->rawAvg and track the global min/max value. bool _cmFtProcRawMinMaxSum( _cmFt_t* p, _cmFtAnl_t* a, cmReal_t* v, unsigned vn ) { assert( vn == a->ap->cnt ); cmVOR_AddVV( a->sr->rawAvgV, vn, v ); // track vector sum for use in avg cmVOR_MinVV( a->sr->rawMinV, vn, v ); // track min/max per vector dim cmVOR_MaxVV( a->sr->rawMaxV, vn, v ); a->sr->rawMin = cmMin(a->sr->rawMin, cmVOR_Min(v,vn,1)); // track global min/max a->sr->rawMax = cmMax(a->sr->rawMax, cmVOR_Max(v,vn,1)); return false; } // Sum the the squared diff. between feature value and feature avg into rawSdvV[] bool _cmFtProcRawStdDev( _cmFt_t* p, _cmFtAnl_t* a, cmReal_t* v, unsigned vn ) { cmReal_t t[ vn ]; assert( vn == a->ap->cnt ); cmVOR_SubVVV( t, a->ap->cnt, v, a->sr->rawAvgV ); cmVOR_PowVS( t, a->ap->cnt, 2.0 ); cmVOR_AddVV( a->sr->rawSdvV, a->ap->cnt, t ); return false; } bool _cmFtProcNormMinMaxSum( _cmFt_t* p, _cmFtAnl_t* a, cmReal_t* v, unsigned vn ) { assert( a->ap->cnt == vn ); if( a->ap->normFl == false ) { cmVOR_Zero( a->sr->normMaxV, vn ); cmVOR_Zero( a->sr->normMinV, vn ); a->sr->normMin = 0; a->sr->normMax = 0; } else { if( a->lp->bipolarFl ) { // subtract mean and divide by std-dev cmVOR_SubVV(v, vn, a->sr->rawAvgV ); cmVOR_DivVVZ(v, vn, a->sr->rawSdvV ); } else { // scale feature into unit range based on file wide min/max cmVOR_SubVS(v, vn, a->sr->rawMin ); if( a->sr->rawMax - a->sr->rawMin > 0 ) cmVOR_DivVS(v, vn, a->sr->rawMax - a->sr->rawMin ); else cmVOR_Zero(v,vn); // convert to unit total energy (UTE) // (this makes the vector sum to one (like a prob. distrib)) if( vn > 1 ) { cmReal_t sum = cmVOR_Sum(v, vn ); if( sum > 0 ) cmVOR_DivVS(v, vn, sum ); else cmVOR_Zero(v,vn); } } cmVOR_AddVV( a->sr->normAvgV, a->ap->cnt, v ); // track norm sum cmVOR_MinVV( a->sr->normMinV, vn, v ); // track norm min/max per dim cmVOR_MaxVV( a->sr->normMaxV, vn, v ); a->sr->normMin = cmMin(a->sr->normMin, cmVOR_Min(v,vn,1)); // track norm global min/max a->sr->normMax = cmMax(a->sr->normMax, cmVOR_Max(v,vn,1)); return true; } return false; } // calc squared diff into a->sr->normSdv[] bool _cmFtNormStdDev( _cmFt_t* p, _cmFtAnl_t* a, cmReal_t* v, unsigned vn ) { if( a->ap->normFl ) { assert( a->ap->cnt == vn ); cmReal_t t[vn]; cmVOR_SubVVV( t, a->ap->cnt, v, a->sr->normAvgV ); cmVOR_PowVS( t, a->ap->cnt, 2.0 ); cmVOR_AddVV( a->sr->normSdvV, a->ap->cnt, t ); } return false; } // anlArray[] sorting function int _cmFtAnlCompare( const void* pp0, const void* pp1 ) { const _cmFtAnl_t* p0 = (const _cmFtAnl_t*)pp0; const _cmFtAnl_t* p1 = (const _cmFtAnl_t*)pp1; assert( p0 != NULL && p0->lp !=NULL && p1!=NULL && p1->lp != NULL ); return p0->lp->order - p1->lp->order; } cmFtRC_t _cmFtValidateAttrArray( _cmFt_t* p ) { cmFtRC_t rc = kOkFtRC; unsigned i,j; for(i=0; iattrCnt; ++i) { _cmFtLabel_t* lp = _cmFtIdToLabelPtr(p->attrArray[i].id); assert( lp != NULL ); // check for duplicate features for(j=0; jattrCnt; ++j) if( i!=j && p->attrArray[i].id == p->attrArray[j].id ) { rc = _cmFtError( kParamErrorFtRC, p, "The attribute '%s' has duplicate entries in the attribute array.", cmStringNullGuard(lp->label)); goto errLabel; } // verify that the source id for this secondary feature was specified if( lp->srcId != kInvalidFtId ) { for(j=0; jattrCnt; ++j) if( p->attrArray[j].id == lp->srcId ) break; if( j == p->attrCnt ) { rc = _cmFtError( kParamErrorFtRC, p, "The primary feature '%s' must be specified in order to use the secondary feature '%s'.",cmStringNullGuard(_cmFtIdToLabelPtr(lp->srcId)->label),lp->label); goto errLabel; } } } errLabel: return rc; } cmFtRC_t cmFtAnalyzeFile( cmFtH_t h, cmFtParam_t* pp) { cmFtRC_t rc = kOkFtRC; _cmFt_t* p = _cmFtHandleToPtr(h); cmSample_t minSmp,maxSmp,meanSmp; cmReal_t audioSigNormFact; cmFtInfo_t f; unsigned frameIdx,sampleIdx; cmFrameFileH_t ffH = cmFrameFileNullHandle; cmAudioFileInfo_t afInfo; _cmFtAnl_t* anlArray = NULL; cmFtSumm_t* summArray = NULL; unsigned i; cmReal_t floorThreshAmpl; if((rc = _cmFtValidateAttrArray(p)) != kOkFtRC ) goto errLabel; cmVOR_DbToAmplVV(&floorThreshAmpl,1,&pp->floorThreshDb); // get the audio file header information if( cmAudioFileGetInfo(pp->audioFn, &afInfo, &p->ctx.rpt ) != kOkAfRC ) { rc = _cmFtError(kDspProcFailFtRC,p, "The audio file open failed on '%s'.",cmStringNullGuard(pp->audioFn)); goto errLabel; } p->progSmpCnt = afInfo.frameCnt; p->progSmpIdx = 0; f.srate = afInfo.srate; f.smpCnt = afInfo.frameCnt; f.fftSmpCnt = cmNearPowerOfTwo( (unsigned)floor( pp->wndMs * f.srate / 1000 ) ); f.binCnt = f.fftSmpCnt / 2 + 1; f.hopSmpCnt = f.fftSmpCnt / pp->hopFact; f.frmCnt = 0; f.skipFrmCnt = 0; f.floorFrmCnt = 0; // verify that the audio channel index is valid if( pp->chIdx >= afInfo.chCnt ) { rc = _cmFtError(kChIdxInvalidFtRC,p,"The channel index (%i) specified for audio file '%s' is greater than the audio file channel count.",pp->chIdx,pp->audioFn,afInfo.chCnt ); goto errLabel; } // initialize the audio file reader if( cmAudioFileRdOpen( p->afRdPtr, f.hopSmpCnt, pp->audioFn, pp->chIdx, 0, cmInvalidIdx ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p, "The audio file reader open failed."); goto errLabel; } // get the range of sample values from this audio file for later normalization if( cmAudioFileRdMinMaxMean( p->afRdPtr, pp->chIdx, &minSmp, &maxSmp, &meanSmp ) != cmOkRC ) { rc = _cmFtError(kDspProcFailFtRC,p,"Audio file min/max/mean processing failed on the audio file:'%s'.",cmStringNullGuard(pp->audioFn)); goto errLabel; } audioSigNormFact = cmMax( fabs(minSmp), fabs(maxSmp) ); // allocate anlArray[] anlArray = cmMemAllocZ( _cmFtAnl_t, pp->attrCnt ); summArray = cmMemAllocZ( cmFtSumm_t, pp->attrCnt ); // iniitalize anlArray[] for(i=0; iattrCnt; ++i) { _cmFtAnl_t* a = anlArray + i; a->ap = pp->attrArray + i; a->lp = _cmFtIdToLabelPtr(a->ap->id); a->sr = summArray + i; a->sr->id = a->lp->id; } // sort anlArray[] into init and exec order qsort( anlArray, pp->attrCnt, sizeof(anlArray[0]), _cmFtAnlCompare); // set the anlArray[i] source attribute pointer for secondary features (feat's based on other feat's) for(i=0; iattrCnt; ++i) if( anlArray[i].lp->srcId != kInvalidFtId ) { unsigned j; for(j=0; jattrCnt; ++j) if( i!=j && anlArray[j].lp->id == anlArray[i].lp->srcId ) { anlArray[i].sp = anlArray + j; break; } assert( j != pp->attrCnt ); } // initialize the feature extractors and allocate feature vector memory if((rc = _cmFtProcInit(p, &f, pp, anlArray)) != kOkFtRC ) goto errLabel; // create the output frame file if( cmFrameFileCreate(&ffH, pp->featFn, f.srate, &p->ctx ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "The feature file '%s' could not be created.",cmStringNullGuard(pp->featFn)); goto errLabel; } // read the next block of samples from the audio file for(frameIdx=0,sampleIdx=0; cmAudioFileRdRead(p->afRdPtr) != cmEofRC; sampleIdx+=f.hopSmpCnt ) { cmSample_t aV[ p->afRdPtr->outN ]; cmSample_t* audV = aV; cmSample_t rms; p->progSmpIdx = sampleIdx; // if this audio buffer is fully or paritally marked as 'skip' if( _cmFtZeroSkipSamples( pp, p->afRdPtr->outV, p->afRdPtr->outN, p->afRdPtr->curFrmIdx - p->afRdPtr->lastReadFrmCnt ) ) { ++f.skipFrmCnt; continue; } // if the audio buffer is zero - skip it if((rms = cmVOS_RMS( p->afRdPtr->outV, p->afRdPtr->outN, p->afRdPtr->outN )) < floorThreshAmpl ) { ++f.floorFrmCnt; continue; } // normalize the audio if( pp->normAudioFl ) cmVOS_MultVVS( audV, p->afRdPtr->outN, p->afRdPtr->outV, audioSigNormFact ); else audV = p->afRdPtr->outV; // execute the phase vocoder if( cmPvAnlExec(p->pvocPtr, audV, p->afRdPtr->outN )==false ) continue; // create an empty frame if( cmFrameFileFrameCreate( ffH, kFrameTypeFtId, kFrameStreamFtId, sampleIdx, 0 ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame creation failed for frame index:%i on frame file:'%s'.",frameIdx,cmStringNullGuard(pp->featFn)); goto errLabel; } // include the incomplete file header record in the first frame if( frameIdx == 0 ) if((rc = _cmFtWriteFileHdr( p, &f, pp, ffH, summArray, false )) != kOkFtRC ) goto errLabel; // execute each of the feature extractors and store the result if((rc = _cmFtProcExec(p, &f, pp, ffH, anlArray, audV )) != kOkFtRC ) goto errLabel; // close and write the current frame if( cmFrameFileFrameClose( ffH ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame write failed for frame index:%i on frame file:'%s'.",frameIdx,cmStringNullGuard(pp->featFn)); goto errLabel; } ++frameIdx; } f.frmCnt = frameIdx; // update the rawAvgV[] for each feature if( f.frmCnt > 0 ) { // sum feature value into a->sr->rawAvgV[] if(( rc = _cmFtProcFile(p,ffH,pp,anlArray, _cmFtProcRawMinMaxSum )) != kOkFtRC ) goto errLabel; // complete the a->sr->rawAvgV[] calc for(i=0; iattrCnt; ++i) cmVOR_DivVS( anlArray[i].sr->rawAvgV, anlArray[i].ap->cnt, f.frmCnt ); // calc sum of squared diff into a->sr->rawSdvV[] if(( rc = _cmFtProcFile(p,ffH,pp,anlArray, _cmFtProcRawStdDev )) != kOkFtRC ) goto errLabel; // complete calc of std-dev for(i=0; iattrCnt; ++i) { _cmFtAnl_t* a = anlArray + i; cmVOR_DivVS( a->sr->rawSdvV, a->ap->cnt, f.frmCnt ); cmVOR_PowVS( a->sr->rawSdvV, a->ap->cnt, 0.5 ); } // make the initial normalized vector calculation (min/max/sum) if(( rc = _cmFtProcFile(p,ffH,pp,anlArray, _cmFtProcNormMinMaxSum )) != kOkFtRC ) goto errLabel; // complete the a->sr->normAvgV[] calculation for(i=0; iattrCnt; ++i) cmVOR_DivVS( anlArray[i].sr->normAvgV, anlArray[i].ap->cnt, f.frmCnt ); // calc squared of squared diff into a->sr->normSdvV[] if(( rc = _cmFtProcFile(p,ffH,pp,anlArray, _cmFtNormStdDev )) != kOkFtRC ) goto errLabel; // complete the calc of norm std-dev for(i=0; iattrCnt; ++i) { _cmFtAnl_t* a = anlArray + i; cmVOR_DivVS( a->sr->normSdvV, a->ap->cnt, f.frmCnt ); cmVOR_PowVS( a->sr->normSdvV, a->ap->cnt, 0.5 ); } } //------------------------------------------------------------------------- // // rewrite the updated feature file header into the first frame // // rewind to the first frame if( cmFrameFileRewind( ffH ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file rewind failed during header update on '%s'.", cmStringNullGuard(pp->featFn)); goto errLabel; } // make the first frame current and load it into the cmFrameFiles current frame buffer if( cmFrameFileFrameLoadNext( ffH, kFrameTypeFtId, kFrameStreamFtId, NULL ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file load next frme failed during header update on '%s'.", cmStringNullGuard(pp->featFn)); goto errLabel; } // copy the update header record into the current frame buffer if((rc = _cmFtWriteFileHdr(p, &f, pp, ffH, summArray, true)) != kOkFtRC ) goto errLabel; // write the updated frame back to disk if( cmFrameFileFrameUpdate( ffH ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file frame update failed during header update on '%s'.", cmStringNullGuard(pp->featFn)); goto errLabel; } errLabel: if( anlArray != NULL ) for(i=0; iattrCnt; ++i) cmMemPtrFree(&anlArray[i].v); cmMemPtrFree(&anlArray); cmMemPtrFree(&summArray); cmFrameFileClose(&ffH); return rc; } cmFtRC_t cmFtAnalyze( cmFtH_t h ) { cmFtRC_t rc = kOkFtRC; _cmFt_t* p = _cmFtHandleToPtr(h); unsigned i; for(i=0; iparamCnt; ++i) { p->progParamIdx = i; p->progPassIdx = 0; if((rc = cmFtAnalyzeFile(h,p->paramArray+i)) != kOkFtRC ) break; } return rc; } const char* cmFtAnalyzeProgress( cmFtH_t h, unsigned* passPtr, cmReal_t* percentPtr ) { _cmFt_t* p = _cmFtHandleToPtr(h); if( percentPtr != NULL ) *percentPtr = 0; if( passPtr != NULL) *passPtr = 0; if( p->progParamIdx == cmInvalidIdx ) return NULL; if( percentPtr != NULL && p->progSmpCnt > 0 ) *percentPtr = 100.0 * p->progSmpIdx / p->progSmpCnt; if( passPtr != NULL ) *passPtr = p->progPassIdx; return p->paramArray[ p->progParamIdx ].audioFn; } cmFtRC_t _cmFtReaderClose( _cmFtFile_t* fp ) { cmFtRC_t rc = kOkFtRC; _cmFt_t* p = _cmFtHandleToPtr(fp->h); /* unsigned i; if( cmPlviewIsValid( p->plvH ) ) for(i=0; iinfo.param.attrCnt; ++i) if( cmPlviewFreeSource( p->plvH, fp->descArray[i].ap->id ) != kOkPlvRC ) { rc = _cmFtError( kPlviewFailFtRC, p, "Plview source free failed on feature '%s'.",fp->descArray[i].lp->label); goto errLabel; } */ if( cmFrameFileClose( &fp->ffH ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file close failed."); goto errLabel; } cmMemPtrFree(&fp->descArray); cmMemPtrFree(&fp->info.summArray); cmMemPtrFree(&fp->info.param.skipArray); cmMemPtrFree(&fp->info.param.attrArray); cmMemPtrFree(&fp->hdrBuf); cmMemPtrFree(&fp); errLabel: return rc; } /* // Fill buf[rowCnt,colCnt] with data from the source submatrix located at rowIdx,colIdx. // Return the count of elements actually copied into buf[]. unsigned cmFtPlviewSrcFunc( void* userPtr, unsigned srcId, unsigned binIdx, unsigned frmIdx, cmReal_t* buf, unsigned binCnt, unsigned frmCnt ) { assert(userPtr != NULL ); _cmFtFile_t* fp = (_cmFtFile_t*)userPtr; _cmFt_t* p = _cmFtHandleToPtr(fp->h); cmFfRC_t rc = kOkFfRC; const cmFfFrame_t* frmDescPtr = NULL; const cmFfMtx_t* mtxDescPtr = NULL; unsigned i; // seek to frmIdx if((rc = cmFrameFileSeek( fp->ffH, frmIdx )) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Seek failed on plot data cmcess."); goto errLabel; } // load the frame for(i=0; iffH, kFrameTypeFtId, kFrameStreamFtId, &frmDescPtr))==kOkFfRC; ++i) { const cmReal_t* dp; const _cmFtLabel_t* lp = _cmFtIdToLabelPtr(srcId); assert(lp != NULL); if((dp = cmFrameFileMtxReal( fp->ffH, lp->ffMtxId, lp->ffUnitsId, kRealFmtId, &mtxDescPtr)) == NULL ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Mtx data cmcess failed on plot data access."); goto errLabel; } cmVOR_Copy( buf + (i*binCnt), binCnt, dp ); return binCnt; } errLabel: return 0; } */ cmFtRC_t cmFtReaderOpen(cmFtH_t h, cmFtFileH_t* hp, const char* featFn, const cmFtInfo_t** infoPtrPtr ) { cmFfRC_t ffRC = kOkFfRC; const cmFfFile_t* fileDescPtr = NULL; const cmFfFrame_t* frameDescPtr = NULL; cmFtRC_t rc = kOkFtRC; _cmFt_t* p = _cmFtHandleToPtr(h); _cmFtFile_t* fp = cmMemAllocZ( _cmFtFile_t, 1 ); const cmFfMtx_t* mp = NULL; void* buf = NULL; unsigned i,j; //cmPlvSrc_t plvSrc; if( infoPtrPtr != NULL ) *infoPtrPtr = NULL; fp->h = h; fp->ffH = cmFrameFileNullHandle; // open the frame file if( cmFrameFileOpen(&fp->ffH, featFn, &p->ctx, &fileDescPtr ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file open failed."); goto errLabel; } // load the first frame if((ffRC = cmFrameFileFrameLoadNext( fp->ffH, kFrameTypeFtId, kFrameStreamFtId, &frameDescPtr )) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file load failed."); goto errLabel; } // read the file header if((buf = cmFrameFileMtxBlob(fp->ffH, kDataMId, kNoUnitsUId, &mp )) == NULL ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file header read failed."); goto errLabel; } // parse the file header into fp->infoPtr if((rc = _cmDeserializeFileHdr( p, fp, buf, mp->rowCnt*mp->colCnt )) != kOkFtRC ) goto errLabel; fp->descArray = cmMemAllocZ( _cmFtDesc_t, fp->info.param.attrCnt ); // for each feature for(i=0; iinfo.param.attrCnt; ++i) { // setup the desc array fp->descArray[i].ap = fp->info.param.attrArray + i; fp->descArray[i].lp = _cmFtIdToLabelPtr( fp->descArray[i].ap->id ); // sync descArray[] to summArray[] by matching the feature id's for(j=0; jinfo.param.attrCnt; ++j) if( fp->info.summArray[j].id == fp->descArray[i].lp->id ) { fp->descArray[i].sr = fp->info.summArray + j; break; } /* plvSrc.id = fp->descArray[i].lp->id; plvSrc.label = fp->descArray[i].lp->label; plvSrc.rn = fp->descArray[i].ap->cnt; plvSrc.cn = fp->info.frmCnt; plvSrc.userPtr = fp; plvSrc.srcFuncPtr = cmFtPlviewSrcFunc; plvSrc.worldExts.xMin = 0; plvSrc.worldExts.xMax = fp->info.frmCnt; plvSrc.worldExts.yMin = fp->descArray[i].ap->cnt <= 1 ? fp->descArray[i].sr->rawMin : 0; plvSrc.worldExts.yMax = fp->descArray[i].ap->cnt <= 1 ? fp->descArray[i].sr->rawMax : fp->descArray[i].ap->cnt; if( cmPlviewIsValid( p->plvH ) ) if( cmPlviewAllocSource( p->plvH, &plvSrc ) != kOkPlvRC ) { rc = _cmFtError( kPlviewFailFtRC, p, "Plview source allocattion failed for feature '%s'.",fp->descArray[i].lp->label); goto errLabel; } */ } // rewind to the frame file if((ffRC = cmFrameFileRewind( fp->ffH )) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file rewind failed."); goto errLabel; } hp->h = fp; if( infoPtrPtr != NULL ) *infoPtrPtr = &fp->info; errLabel: if( rc != kOkFtRC ) _cmFtReaderClose(fp); return rc; } cmFtRC_t cmFtReaderClose( cmFtFileH_t* hp ) { cmFtRC_t rc = kOkFtRC; if( cmFtReaderIsValid(*hp) == false ) return rc; _cmFtFile_t* fp = _cmFtFileHandleToPtr(*hp); if((rc = _cmFtReaderClose(fp)) != kOkFtRC ) goto errLabel; hp->h = NULL; errLabel: return rc; } bool cmFtReaderIsValid( cmFtFileH_t h ) { return h.h != NULL; } unsigned cmFtReaderFeatCount( cmFtFileH_t h ) { _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); return fp->info.param.attrCnt; } unsigned cmFtReaderFeatId( cmFtFileH_t h, unsigned index ) { _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); assert( index < fp->info.param.attrCnt ); return fp->descArray[index].lp->id; } cmFtRC_t cmFtReaderRewind( cmFtFileH_t h ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); if(cmFrameFileRewind( fp->ffH ) != kOkFfRC ) { _cmFt_t* p = _cmFtHandleToPtr(fp->h); rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file advance failed."); goto errLabel; } errLabel: return rc; } cmFtRC_t cmFtReaderSeek( cmFtFileH_t h, unsigned frmIdx ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); if( cmFrameFileSeek( fp->ffH, kFrameStreamFtId, frmIdx ) != kOkFtRC ) { _cmFt_t* p = _cmFtHandleToPtr(fp->h); rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file seek failed."); goto errLabel; } errLabel: return rc; } cmFtRC_t cmFtReaderAdvance( cmFtFileH_t h, cmFtFrameDesc_t* fdp ) { cmFfRC_t ffRC = kOkFfRC; const cmFfFrame_t* frameDescPtr = NULL; cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); if((ffRC = cmFrameFileFrameLoadNext( fp->ffH, kFrameTypeFtId, kFrameStreamFtId, &frameDescPtr )) != kOkFfRC ) { if( ffRC == kEofFfRC ) rc = kEofFtRC; else { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame file advance failed."); goto errLabel; } } errLabel: if( fdp != NULL ) { if( rc == kOkFtRC ) { fdp->smpIdx = frameDescPtr->tm.sampleIdx; fdp->frmIdx = cmFrameFileFrameLoadedIndex(fp->ffH); } else { fdp->smpIdx = cmInvalidIdx; fdp->frmIdx = cmInvalidIdx; } } return rc; } cmReal_t* cmFtReaderData( cmFtFileH_t h, unsigned id, unsigned* cntPtr ) { _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); cmReal_t* dp = NULL; _cmFtLabel_t* lp = _cmFtIdToLabelPtr(id); const cmFfMtx_t* mdp = NULL; assert( lp != NULL ); if( cntPtr != NULL ) *cntPtr = 0; if((dp = cmFrameFileMtxReal(fp->ffH,lp->ffMtxId,lp->ffUnitsId,&mdp)) == NULL ) return NULL; if( cntPtr != NULL ) *cntPtr = mdp->rowCnt * mdp->colCnt; return dp; } cmFtRC_t cmFtReaderCopy( cmFtFileH_t h, unsigned featId, unsigned frmIdx, cmReal_t* buf, unsigned frmCnt, unsigned elePerFrmCnt, unsigned* outEleCntPtr ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); _cmFtLabel_t* lp = _cmFtIdToLabelPtr(featId); assert( lp != NULL ); if( cmFrameFileMtxLoadReal( fp->ffH, kFrameStreamFtId, lp->ffMtxId, lp->ffUnitsId, frmIdx, frmCnt, buf, frmCnt*elePerFrmCnt, outEleCntPtr ) != kOkFfRC ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Frame load matrix failed."); goto errLabel; } errLabel: return rc; } cmFtRC_t cmFtReaderMultiSetup( cmFtFileH_t h, cmFtMulti_t* multiArray, unsigned multiCnt, unsigned* featVectEleCntPtr ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); unsigned i,j; assert( featVectEleCntPtr != NULL ); *featVectEleCntPtr = 0; for(i=0; iinfo.param.attrCnt; ++j) { if( fp->info.param.attrArray[j].id == multiArray[i].featId ) { // if the multi ele cnt is -1 then use all avail ele's if( multiArray[i].cnt == -1 ) multiArray[i].cnt = fp->info.param.attrArray[j].cnt; // verify the feature element count if( fp->info.param.attrArray[j].cnt < multiArray[i].cnt ) { rc = _cmFtError( kInvalidFeatIdFtRC, p, "The requested feature element count %i is greater than the actual feature count %i in feature file '%s'.",multiArray[i].cnt,fp->info.param.attrArray[j].cnt,fp->info.param.featFn); goto errLabel; } break; } } // verify that the feature attr recd was found if( j >= fp->info.param.attrCnt ) { rc = _cmFtError( kInvalidFeatIdFtRC, p, "The feature %i was not used in the feature file '%s'.",multiArray[i].featId,fp->info.param.featFn); goto errLabel; } multiArray[i].id0 = lp->ffMtxId; multiArray[i].id1 = lp->ffUnitsId; *featVectEleCntPtr += multiArray[i].cnt; } errLabel: return rc; } cmFtRC_t cmFtReaderMultiData( cmFtFileH_t h, const cmFtMulti_t* multiArray, unsigned multiCnt, cmReal_t* outV, unsigned outN ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); unsigned i; unsigned n = 0; for(i=0; iffH,m->id0,m->id1,&mdp)) == NULL ) { rc = _cmFtError( kFrameFileFailFtRC, p, "Matrix read failed on feature file '%s'.", fp->info.param.featFn); goto errLabel; } assert(m->cnt <= mdp->rowCnt*mdp->colCnt); assert(n + m->cnt <= outN ); cmVOR_Copy(outV, m->cnt, dp ); outV += m->cnt; n += m->cnt; } errLabel: return rc; } cmFtSumm_t* _cmFtReaderFindSummPtr( _cmFtFile_t* fp, unsigned featId ) { unsigned i; const cmFtParam_t* pp = &fp->info.param; for(i=0; iattrCnt; ++i) if( fp->info.summArray[i].id == featId ) return fp->info.summArray + i; return NULL; } cmFtRC_t cmFtReaderReport( cmFtFileH_t h, unsigned featId ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); const cmFtInfo_t* ip = &fp->info; const cmFtParam_t* pp = &ip->param; unsigned i; cmFtSumm_t* s; _cmFtPrint(p,"ch:%i audio:%s\n",pp->chIdx,pp->audioFn); _cmFtPrint(p,"wndMs:%f hopFact:%i normAudioFl:%i \n",pp->wndMs,pp->hopFact,pp->normAudioFl); _cmFtPrint(p,"skip:\n"); for(i=0; iskipCnt; ++i) _cmFtPrint(p,"idx:%10i cnt:%10i \n",pp->skipArray[i].smpIdx,pp->skipArray[i].smpCnt); _cmFtPrint(p,"attr:\n"); for(i=0; iattrCnt; ++i) _cmFtPrint(p,"cnt:%4i normFl:%i raw min:%12f max:%12f norm min:%12f max:%12f %s\n",pp->attrArray[i].cnt,pp->attrArray[i].normFl,fp->descArray[i].sr->rawMin,fp->descArray[i].sr->rawMax,fp->descArray[i].sr->normMin,fp->descArray[i].sr->normMax,cmFtFeatIdToLabel(pp->attrArray[i].id)); _cmFtPrint(p,"frmCnt:%i skipFrmCnt:%i floorFrmCnt:%i srate:%f fftSmpCnt:%i hopSmpCnt:%i binCnt:%i binHz:%f\n",ip->frmCnt,ip->skipFrmCnt,ip->floorFrmCnt,ip->srate,ip->fftSmpCnt,ip->hopSmpCnt,ip->binCnt,ip->srate/ip->fftSmpCnt); if( featId != kInvalidFtId ) { if((s = _cmFtReaderFindSummPtr(fp,featId)) == NULL ) return _cmFtError( kInvalidFeatIdFtRC, p, "The feature id %i is not valid.",featId); _cmFtPrint(p,"feature:%s \n",_cmFtIdToLabelPtr(featId)->label); cmVOR_PrintLE("raw min: ", &p->ctx.rpt, 1, s->cnt, s->rawMinV ); cmVOR_PrintLE("raw max: ", &p->ctx.rpt, 1, s->cnt, s->rawMaxV ); cmVOR_PrintLE("raw avg: ", &p->ctx.rpt, 1, s->cnt, s->rawAvgV ); cmVOR_PrintLE("raw sdv: ", &p->ctx.rpt, 1, s->cnt, s->rawSdvV ); cmVOR_PrintLE("norm min:", &p->ctx.rpt, 1, s->cnt, s->normMinV ); cmVOR_PrintLE("norm max:", &p->ctx.rpt, 1, s->cnt, s->normMaxV ); cmVOR_PrintLE("norm avg:", &p->ctx.rpt, 1, s->cnt, s->normAvgV ); cmVOR_PrintLE("norm sdv:", &p->ctx.rpt, 1, s->cnt, s->normSdvV ); } return rc; } cmFtRC_t cmFtReaderReportFn( cmFtH_t h, const cmChar_t* fn, unsigned featId ) { cmFtRC_t rc0,rc1; cmFtFileH_t fh = cmFtFileNullHandle; if((rc0 = cmFtReaderOpen(h,&fh,fn,NULL)) != kOkFtRC ) return rc0; rc0 = cmFtReaderReport(fh,featId); rc1 = cmFtReaderClose(&fh); return rc0 != kOkFtRC ? rc0 : rc1; } cmFtRC_t cmFtReaderReportFeature( cmFtFileH_t h, unsigned featId, unsigned frmIdx, unsigned frmCnt ) { cmFtRC_t rc = kOkFtRC; _cmFtFile_t* fp = _cmFtFileHandleToPtr(h); _cmFt_t* p = _cmFtHandleToPtr(fp->h); unsigned i; cmFtFrameDesc_t ftFrameDesc; if((rc = cmFtReaderSeek(h,frmIdx)) != kOkFtRC ) return rc; for(i=0; ih); unsigned i; cmFtFrameDesc_t ftFrameDesc; cmFileH_t fH; unsigned hdr[] = {0,0,0}; unsigned maxCnt = 0; // create the output file if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC ) return _cmFtError( kFileFailFtRC, p, "Feature to binary file '%s' failed on output file creation.",outFn); // if frmCnt is not valid then set it to all frames past frmIdx if( frmCnt == cmInvalidCnt ) frmCnt = cmFrameFileFrameCount(fp->ffH,kFrameStreamFtId); // validate frm idx if( frmIdx > frmCnt ) { rc = _cmFtError( kInvalidFrmIdxFtRC,p,"Frame index %i is invalid for frame count = %i.",frmIdx,frmCnt); goto errLabel; } // seek to the location first output frame if((rc = cmFtReaderSeek(h,frmIdx)) != kOkFtRC ) goto errLabel; hdr[0] = frmCnt; // count of frames hdr[1] = 0; // count of elements per frame hdr[2] = sizeof(cmReal_t); // write the file header if( cmFileWrite(fH,hdr,sizeof(hdr)) != kOkFileRC ) { rc = _cmFtError( kFileFailFtRC,p,"The output file header write failed."); goto errLabel; } // iterate through each frame for(i=0; i maxCnt ) maxCnt = cnt; } // rewind to the beginning of the file if( cmFileSeek(fH,kBeginFileFl,0) != kOkFileRC ) { rc = _cmFtError( kFileFailFtRC,p,"Output file rewind failed."); goto errLabel; } // rewrite the header hdr[1] = maxCnt; if( cmFileWrite(fH,hdr,sizeof(hdr)) != kOkFileRC ) { rc = _cmFtError( kFileFailFtRC,p,"The output file header re-write failed."); goto errLabel; } errLabel: if( cmFileIsValid(fH) ) if( cmFileClose(&fH) != kOkFileRC ) _cmFtError( kFileFailFtRC,p,"Output file close failed."); return rc; } cmFtRC_t cmFtReaderToBinaryFn(cmFtH_t h, const cmChar_t* fn, unsigned featId, unsigned frmIdx, unsigned frmCnt, const cmChar_t* outFn ) { cmFtRC_t rc = kOkFtRC; cmFtFileH_t fH = cmFtFileNullHandle; if((rc = cmFtReaderOpen(h,&fH,fn,NULL)) != kOkFtRC ) return rc; rc = cmFtReaderToBinary(fH,featId,frmIdx,frmCnt,outFn); cmFtRC_t rc1 = cmFtReaderClose(&fH); return rc==kOkFtRC ? rc1 : rc; }