#include "cmPrefix.h" #include "cmGlobal.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmLinkedHeap.h" #include "cmSymTbl.h" #include "cmFloatTypes.h" #include "cmComplexTypes.h" #include "cmFileSys.h" #include "cmProcObj.h" #include "cmProcTemplate.h" #include "cmAudioFile.h" #include "cmMath.h" #include "cmProc.h" #include "cmVectOps.h" #include "cmKeyboard.h" #include "cmGnuPlot.h" #include // time() //------------------------------------------------------------------------------------------------------------ void cmFloatPointExceptHandler( int signo, siginfo_t* info, void* context ) { char* cp = ""; switch( info->si_code ) { case FPE_INTDIV: cp = "integer divide by zero"; break; case FPE_INTOVF: cp = "integer overflow"; break; case FPE_FLTDIV: cp = "divide by zero"; break; case FPE_FLTUND: cp = "underflow"; break; case FPE_FLTRES: cp = "inexact result"; break; case FPE_FLTINV: cp = "invalid operation"; break; case FPE_FLTSUB: cp = "subscript range error"; break; } fprintf(stderr,"Floating point exception: Type: %s\n",cp); exit(1); } // set 'orgSaPtr' to NULL to discard the current signal action state void cmSetupFloatPointExceptHandler( struct sigaction* orgSaPtr ) { struct sigaction sa; sa.sa_handler = SIG_DFL; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = cmFloatPointExceptHandler; sigemptyset(&sa.sa_mask); // set all FP except flags excetp: FE_INEXACT #ifdef OS_OSX // we don't yet support FP exceptions on OSX // for an example of how to make this work with the linux interface as below // see: http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c assert(0); #else // int flags = FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID; // feenableexcept(flags); assert(0); #endif sigaction( SIGFPE, &sa, orgSaPtr ); } //------------------------------------------------------------------------------------------------------------ cmAudioFileRd* cmAudioFileRdAlloc( cmCtx* c, cmAudioFileRd* p, unsigned procSmpCnt, const cmChar_t* fn, unsigned chIdx, unsigned begFrmIdx, unsigned endFrmIdx ) { cmAudioFileRd* op = cmObjAlloc( cmAudioFileRd, c, p ); if( fn != NULL ) if( cmAudioFileRdOpen( op, procSmpCnt, fn, chIdx, begFrmIdx, endFrmIdx ) != cmOkRC ) cmAudioFileRdFree(&op); return op; } cmRC_t cmAudioFileRdFree( cmAudioFileRd** pp ) { cmRC_t rc = cmOkRC; if( pp != NULL && *pp != NULL ) { cmAudioFileRd* p = *pp; if((rc = cmAudioFileRdClose(p)) == cmOkRC ) { cmMemPtrFree(&p->outV); cmMemPtrFree(&p->fn); cmObjFree(pp); } } return rc; } cmRC_t cmAudioFileRdOpen( cmAudioFileRd* p, unsigned procSmpCnt, const cmChar_t* fn, unsigned chIdx, unsigned begFrmIdx, unsigned endFrmIdx ) { cmRC_t rc; cmRC_t afRC; if((rc = cmAudioFileRdClose(p)) != cmOkRC ) return rc; p->h = cmAudioFileNewOpen( fn, &p->info, &afRC, p->obj.err.rpt ); if( afRC != kOkAfRC ) return cmCtxRtCondition( &p->obj, afRC, "Unable to open the audio file:'%s'", fn ); p->chIdx = chIdx; p->outN = procSmpCnt; p->outV = cmMemResizeZ( cmSample_t, p->outV, p->outN ); p->fn = cmMemResizeZ( cmChar_t, p->fn, strlen(fn)+1 ); strcpy(p->fn,fn); //p->mfp = cmCtxAllocDebugFile( p->obj.ctx,"audioFile"); p->lastReadFrmCnt = 0; p->eofFl = false; p->begFrmIdx = begFrmIdx; p->endFrmIdx = endFrmIdx; p->curFrmIdx = p->begFrmIdx; if( p->begFrmIdx > 0 ) rc = cmAudioFileRdSeek(p,p->begFrmIdx); return rc; } cmRC_t cmAudioFileRdClose( cmAudioFileRd* p ) { cmRC_t rc = cmOkRC; cmRC_t afRC; if( p == NULL ) return cmOkRC; //cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); if( cmAudioFileIsOpen(p->h) == false ) return cmOkRC; if((afRC = cmAudioFileDelete(&p->h)) != cmOkRC ) rc = cmCtxRtCondition( &p->obj, afRC, "An attempt to close the audio file'%s' failed.", p->fn ); return rc; } cmRC_t cmAudioFileRdRead( cmAudioFileRd* p ) { cmRC_t rc = cmOkRC; cmRC_t afRC; if(p->eofFl || ((p->eofFl = cmAudioFileIsEOF(p->h)) == true) ) return cmEofRC; unsigned n = p->endFrmIdx==cmInvalidIdx ? p->outN : cmMin( p->outN, p->endFrmIdx - p->curFrmIdx ); if((afRC = cmAudioFileReadSample( p->h, n, p->chIdx, 1, &p->outV, &p->lastReadFrmCnt )) != kOkAfRC ) rc = cmCtxRtCondition( &p->obj, afRC, "Audio file read failed on:'%s'.", p->fn); p->curFrmIdx += p->lastReadFrmCnt; if( n < p->outN ) { cmVOS_Zero(p->outV + p->lastReadFrmCnt, p->outN - p->lastReadFrmCnt); p->eofFl = true; } if( p->mfp != NULL ) cmMtxFileSmpExec( p->mfp, p->outV, p->outN ); return rc; } cmRC_t cmAudioFileRdSeek( cmAudioFileRd* p, unsigned frmIdx ) { cmRC_t rc = cmOkRC; cmRC_t afRC; if((afRC = cmAudioFileSeek( p->h, frmIdx )) != kOkAfRC ) rc = cmCtxRtCondition( &p->obj, afRC, "Audio file read failed on:'%s'.", p->fn); return rc; } cmRC_t cmAudioFileRdMinMaxMean( cmAudioFileRd* p, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr ) { cmRC_t rc = cmOkRC; cmRC_t afRC; if(( afRC = cmAudioFileMinMaxMean( p->h, chIdx, minPtr, maxPtr, meanPtr )) != kOkAfRC ) rc = cmCtxRtCondition( &p->obj, afRC, "Audio file min, max, and mean calculation failed on '%s'", p->fn ); return rc; } //------------------------------------------------------------------------------------------------------------ cmShiftBuf* cmShiftBufAlloc( cmCtx* c, cmShiftBuf* p, unsigned procSmpCnt, unsigned wndSmpCnt, unsigned hopSmpCnt ) { cmShiftBuf* op = cmObjAlloc( cmShiftBuf, c, p ); if( procSmpCnt > 0 && wndSmpCnt > 0 && hopSmpCnt > 0 ) if( cmShiftBufInit(op, procSmpCnt, wndSmpCnt, hopSmpCnt ) != cmOkRC) cmShiftBufFree(&op); return op; } cmRC_t cmShiftBufFree( cmShiftBuf** pp ) { cmRC_t rc = cmOkRC; if( pp != NULL && *pp != NULL ) { if((rc = cmShiftBufFinal(*pp)) == cmOkRC ) { cmMemPtrFree(&(*pp)->bufV); cmObjFree(pp); } } return rc; } cmRC_t cmShiftBufInit( cmShiftBuf* p, unsigned procSmpCnt, unsigned wndSmpCnt, unsigned hopSmpCnt ) { cmRC_t rc; if( hopSmpCnt > wndSmpCnt ) return cmCtxRtAssertFailed( &p->obj, cmArgAssertRC, "The window sample count (%i) must be greater than or equal to the hop sample count (%i).", wndSmpCnt, hopSmpCnt ); if((rc = cmShiftBufFinal(p)) != cmOkRC ) return rc; // The worst case storage requirement is where there are wndSmpCnt-1 samples in outV[] and procSmpCnt new samples arrive. p->bufSmpCnt = wndSmpCnt + procSmpCnt; p->bufV = cmMemResizeZ( cmSample_t, p->outV, p->bufSmpCnt ); p->outV = p->bufV; p->outN = wndSmpCnt; p->wndSmpCnt = wndSmpCnt; p->procSmpCnt = procSmpCnt; p->hopSmpCnt = hopSmpCnt; p->inPtr = p->outV; p->fl = false; return cmOkRC; } cmRC_t cmShiftBufFinal( cmShiftBuf* p ) { return cmOkRC; } // This function should be called in a loop until it returns false. // Note that 'sp' and 'sn' are ignored except p->fl == false. bool cmShiftBufExec( cmShiftBuf* p, const cmSample_t* sp, unsigned sn ) { assert( sn <= p->procSmpCnt ); // The active samples are in outV[wndSmpCnt] // Stored samples are between outV + wndSmpCnt and inPtr. // if the previous call to this function returned true then the buffer must be // shifted by hopSmpCnt samples - AND sp[] is ignored. if( p->fl ) { // shift the output buffer to the left to remove expired samples p->outV += p->hopSmpCnt; // if there are not wndSmpCnt samples left in the buffer if( p->inPtr - p->outV < p->wndSmpCnt ) { // then copy the remaining active samples (between outV and inPtr) // to the base of the physicalbuffer unsigned n = p->inPtr - p->outV; memmove( p->bufV, p->outV, n * sizeof(cmSample_t)); p->inPtr = p->bufV + n; // update the input and output positions p->outV = p->bufV; } } else { // if the previous call to this function returned false then sp[sn] should not be ignored assert( p->inPtr + sn <= p->outV + p->bufSmpCnt ); // copy the incoming samples into the buffer cmVOS_Copy(p->inPtr,sn,sp); p->inPtr += sn; } // if there are at least wndSmpCnt available samples in outV[] p->fl = p->inPtr - p->outV >= p->wndSmpCnt; return p->fl; } void cmShiftBufTest( cmCtx* c ) { unsigned smpCnt = 48; unsigned procSmpCnt = 5; unsigned hopSmpCnt = 6; unsigned wndSmpCnt = 7; unsigned i; cmShiftBuf* b = cmShiftBufAlloc(c,NULL,procSmpCnt,wndSmpCnt,hopSmpCnt ); cmSample_t x[ smpCnt ]; cmVOS_Seq(x,smpCnt,1,1); //cmVOS_Print( rptFuncPtr, 1, smpCnt, x ); for(i=0; iobj.err.rpt, 1, wndSmpCnt, b->outV ); } } cmShiftBufFree(&b); } /* bool cmShiftBufExec( cmShiftBuf* p, const cmSample_t* sp, unsigned sn ) { bool retFl = false; if( sn > p->procSmpCnt ) { cmCtxRtAssertFailed( p->obj.ctx, cmArgAssertRC, "The input sample count (%i) must be less than or equal to the proc sample count (%i).", sn, p->procSmpCnt); return false; } assert( sn <= p->procSmpCnt ); cmSample_t* dbp = p->outV; cmSample_t* dep = p->outV + (p->outN - sn); cmSample_t* sbp = p->outV + sn; // shift the last bufCnt-shiftCnt samples over the first shiftCnt samples while( dbp < dep ) *dbp++ = *sbp++; // copy in the new samples dbp = dep; dep = dbp + sn; while( dbp < dep ) *dbp++ = *sp++; // if any space remains at the end of the buffer then zero it dep = p->outV + p->outN; while( dbp < dep ) *dbp++ = 0; if( p->firstPtr > p->outV ) p->firstPtr = cmMax( p->outV, p->firstPtr - p->procSmpCnt); p->curHopSmpCnt += sn; if( p->curHopSmpCnt >= p->hopSmpCnt ) { p->curHopSmpCnt -= p->hopSmpCnt; retFl = true; } if( p->mfp != NULL ) cmMtxFileSmpExec(p->mfp,p->outV,p->outN); return retFl; } */ //------------------------------------------------------------------------------------------------------------ cmWndFunc* cmWndFuncAlloc( cmCtx* c, cmWndFunc* p, unsigned wndId, unsigned wndSmpCnt, double kaiserSideLobeRejectDb ) { cmWndFunc* op = cmObjAlloc( cmWndFunc, c, p ); if( wndId != kInvalidWndId ) if( cmWndFuncInit(op,wndId,wndSmpCnt,kaiserSideLobeRejectDb ) != cmOkRC ) cmWndFuncFree(&op); return op; } cmRC_t cmWndFuncFree( cmWndFunc** pp ) { cmRC_t rc = cmOkRC; if( pp != NULL && *pp != NULL ) { cmWndFunc* p = *pp; if((rc = cmWndFuncFinal(p)) == cmOkRC ) { cmMemPtrFree(&p->wndV); cmMemPtrFree(&p->outV); cmObjFree(pp); } } return rc; } cmRC_t cmWndFuncInit( cmWndFunc* p, unsigned wndId, unsigned wndSmpCnt, double kslRejectDb ) { cmRC_t rc; if( wndId == (p->wndId | p->flags) && wndSmpCnt == p->outN && kslRejectDb == p->kslRejectDb ) return cmOkRC; if((rc = cmWndFuncFinal(p)) != cmOkRC ) return rc; p->wndV = cmMemResize( cmSample_t, p->wndV, wndSmpCnt ); p->outV = cmMemResize( cmSample_t, p->outV, wndSmpCnt ); p->outN = wndSmpCnt; p->wndId = wndId; p->kslRejectDb = kslRejectDb; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"wndFunc"); p->flags = wndId & (~kWndIdMask); switch( wndId & kWndIdMask ) { case kHannWndId: cmVOS_Hann( p->wndV, p->outN ); break; case kHannMatlabWndId: cmVOS_HannMatlab( p->wndV, p->outN ); break; case kHammingWndId: cmVOS_Hamming( p->wndV, p->outN ); break; case kTriangleWndId: cmVOS_Triangle( p->wndV, p->outN ); break; case kUnityWndId: cmVOS_Fill( p->wndV, p->outN, 1.0 ); break; case kKaiserWndId: { double beta = cmVOS_KaiserBetaFromSidelobeReject(fabs(kslRejectDb)); cmVOS_Kaiser( p->wndV,p->outN, beta); } break; case kInvalidWndId: break; default: { assert(0); } } cmSample_t den = 0; cmSample_t num = 1; if( cmIsFlag(p->flags,kNormBySumWndFl) ) { den = cmVOS_Sum(p->wndV, p->outN); num = wndSmpCnt; } if( cmIsFlag(p->flags,kNormByLengthWndFl) ) den += wndSmpCnt; if( den > 0 ) { cmVOS_MultVS(p->wndV,p->outN,num); cmVOS_DivVS(p->wndV,p->outN,den); } return cmOkRC; } cmRC_t cmWndFuncFinal( cmWndFunc* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmWndFuncExec( cmWndFunc* p, const cmSample_t* sp, unsigned sn ) { if( sn > p->outN ) return cmCtxRtAssertFailed( &p->obj, cmArgAssertRC, "The length of the input vector (%i) is greater thean the length of the window function (%i).", sn, p->outN ); if( p->wndId != kInvalidWndId ) cmVOS_MultVVV( p->outV, sn, sp, p->wndV ); if( p->mfp != NULL ) cmMtxFileSmpExec(p->mfp,p->outV,p->outN); return cmOkRC; } void cmWndFuncTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ) { unsigned wndCnt = 5; double kaiserSideLobeRejectDb = 30; cmCtx c; cmCtxAlloc(&c,rpt,lhH,stH); cmWndFunc* p = cmWndFuncAlloc(&c,NULL,kHannWndId,wndCnt, 0 ); cmVOS_Print( rpt, 1, wndCnt, p->wndV ); cmWndFuncInit(p,kHammingWndId ,wndCnt, 0 ); cmVOS_Print( rpt, 1, wndCnt, p->wndV ); cmWndFuncInit(p,kTriangleWndId ,wndCnt, 0 ); cmVOS_Print( rpt, 1, wndCnt, p->wndV ); cmWndFuncInit(p,kKaiserWndId ,wndCnt, kaiserSideLobeRejectDb ); cmVOS_Print( rpt, 1, wndCnt, p->wndV ); cmSample_t wV[ wndCnt ]; cmVOS_HannMatlab(wV,wndCnt); cmVOS_Print( rpt, 1, wndCnt, wV); cmWndFuncFree(&p); } //------------------------------------------------------------------------------------------------------------ cmSpecDelay* cmSpecDelayAlloc( cmCtx* c, cmSpecDelay* ap, unsigned maxDelayCnt, unsigned binCnt ) { cmSpecDelay* p = cmObjAlloc( cmSpecDelay, c, ap ); if( maxDelayCnt > 0 && binCnt > 0 ) if( cmSpecDelayInit(p,maxDelayCnt,binCnt) != cmOkRC ) cmSpecDelayFree(&p); return p; } cmRC_t cmSpecDelayFree( cmSpecDelay** pp ) { cmRC_t rc = cmOkRC; if( pp != NULL && *pp != NULL ) { cmSpecDelay* p = *pp; if((rc=cmSpecDelayFinal(p)) == cmOkRC ) { cmMemPtrFree(&p->bufPtr); cmObjFree(pp); } } return rc; } cmRC_t cmSpecDelayInit( cmSpecDelay* p, unsigned maxDelayCnt, unsigned binCnt ) { cmRC_t rc; if((rc = cmSpecDelayFinal(p)) != cmOkRC ) return rc; p->bufPtr = cmMemResizeZ( cmSample_t, p->bufPtr, binCnt * maxDelayCnt ); p->maxDelayCnt = maxDelayCnt; p->outN = binCnt; p->inIdx = 0; return cmOkRC; } cmRC_t cmSpecDelayFinal(cmSpecDelay* p ) { return cmOkRC; } cmRC_t cmSpecDelayExec( cmSpecDelay* p, const cmSample_t* sp, unsigned sn ) { cmSample_t* dp = p->bufPtr + (p->inIdx * p->outN); cmVOS_Copy( dp, cmMin(sn,p->outN), sp); p->inIdx = (p->inIdx+1) % p->maxDelayCnt; return cmOkRC; } const cmSample_t* cmSpecDelayOutPtr( cmSpecDelay* p, unsigned delayCnt ) { assert( delayCnt < p->maxDelayCnt ); int i = p->inIdx - delayCnt; if( i < 0 ) i = p->maxDelayCnt + i; return p->bufPtr + (i * p->outN); } //------------------------------------------------------------------------------------------------------------ cmFilter* cmFilterAlloc( cmCtx* c, cmFilter* ap, const cmReal_t* b, unsigned bn, const cmReal_t* a, unsigned an, unsigned procSmpCnt, const cmReal_t* d ) { cmRC_t rc; cmFilter* p = cmObjAlloc(cmFilter,c,ap); if( (bn > 0 || an > 0) && procSmpCnt > 0 ) if( (rc = cmFilterInit( p, b, bn, a, an, procSmpCnt, d)) != cmOkRC ) cmFilterFree(&p); return p; } cmFilter* cmFilterAllocEllip( cmCtx* c, cmFilter* ap, cmReal_t srate, cmReal_t passHz, cmReal_t stopHz, cmReal_t passDb, cmReal_t stopDb, unsigned procSmpCnt, const cmReal_t* d ) { cmRC_t rc; cmFilter* p = cmObjAlloc(cmFilter,c,ap); if( srate > 0 && passHz > 0 && procSmpCnt > 0 ) if( (rc = cmFilterInitEllip( p, srate, passHz, stopHz, passDb, stopDb, procSmpCnt, d)) != cmOkRC ) cmFilterFree(&p); return p; } cmRC_t cmFilterFree( cmFilter** pp ) { cmRC_t rc = cmOkRC; if( pp != NULL && *pp != NULL ) { cmFilter* p = *pp; if((rc = cmFilterFinal(p)) == cmOkRC ) { cmMemPtrFree(&p->a); cmMemPtrFree(&p->b); cmMemPtrFree(&p->d); cmMemPtrFree(&p->outSmpV); cmObjFree(pp); } } return rc; } cmRC_t cmFilterInit( cmFilter* p, const cmReal_t* b, unsigned bn, const cmReal_t* a, unsigned an, unsigned procSmpCnt, const cmReal_t* d ) { assert( bn >= 1 ); assert( an >= 1 && a[0] != 0 ); cmRC_t rc; if((rc = cmFilterFinal(p)) != cmOkRC ) return rc; int cn = cmMax(an,bn) - 1; // The output vector may be used as either cmReal_t or cmSample_t. // Find the larger of the two possible types. if( sizeof(cmReal_t) > sizeof(cmSample_t) ) { p->outRealV = cmMemResizeZ( cmReal_t, p->outRealV, procSmpCnt ); p->outSmpV = (cmSample_t*)p->outRealV; } else { p->outSmpV = cmMemResizeZ( cmSample_t, p->outSmpV, procSmpCnt ); p->outRealV = (cmReal_t*)p->outRealV; } p->a = cmMemResizeZ( cmReal_t, p->a, cn ); p->b = cmMemResizeZ( cmReal_t, p->b, cn ); p->d = cmMemResizeZ( cmReal_t, p->d, cn+1 ); //p->outV = cmMemResizeZ( cmSample_t, p->outV, procSmpCnt ); p->outN = procSmpCnt; p->an = an; p->bn = bn; p->cn = cn; p->di = 0; p->b0 = b[0] / a[0]; int i; for(i=0; ia[i] = a[i+1] / a[0]; for(i=0; ib[i] = b[i+1] / a[0]; if( d != NULL ) cmVOR_Copy(p->d,cn,d); return cmOkRC; } // initialize an elliptic lowpass filter with the given characteristics // ref: Parks & Burrus, Digital Filter Design, sec. 7.2.7 - 7.2.8 cmRC_t cmFilterInitEllip( cmFilter* p, cmReal_t srate, cmReal_t passHz, cmReal_t stopHz, cmReal_t passDb, cmReal_t stopDb, unsigned procSmpCnt, const cmReal_t* d ) { assert( srate > 0 ); assert( passHz > 0 && stopHz > passHz && srate/2 > stopHz ); cmReal_t Wp, Ws, ep, v0, k, kc, k1, k1c, K, Kc, K1, K1c, sn, cn, dn, sm, cm, dm, zr, zi, pr, pi; unsigned N, L, j; // prewarp Wp and Ws, calculate k Wp = 2 * srate * tan(M_PI * passHz / srate); Ws = 2 * srate * tan(M_PI * stopHz / srate); k = Wp / Ws; // calculate ep and k1 from passDb and stopDb ep = sqrt(pow(10, passDb/10) - 1); k1 = ep / sqrt(pow(10, stopDb/10) - 1); // calculate complimentary moduli kc = sqrt(1-k*k); k1c = sqrt(1-k1*k1); // calculate complete elliptic integrals K = cmEllipK( kc ); Kc = cmEllipK( k ); K1 = cmEllipK( k1c ); K1c = cmEllipK( k1 ); // calculate minimum integer filter order N N = ceil(K*K1c/Kc/K1); // recalculate k and kc from chosen N // Ws is minimized while other specs held constant k = cmEllipDeg( K1c/K1/N ); kc = sqrt(1-k*k); K = cmEllipK( kc ); Kc = cmEllipK( k ); Ws = Wp / k; // initialize temporary coefficient arrays cmReal_t b[N+1], a[N+1]; a[0] = b[0] = 1; memset(b+1, 0, N*sizeof(cmReal_t)); memset(a+1, 0, N*sizeof(cmReal_t)); // intermediate value needed for determining poles v0 = K/K1/N * cmEllipArcSc( 1/ep, k1 ); cmEllipJ( v0, k, &sm, &cm, &dm ); for( L=1-N%2; L= 2; j-- ) { b[j] = b[j] + zr*b[j-1] + zi*b[j-2]; a[j] = a[j] + pr*a[j-1] + pi*a[j-2]; } b[1] += zr; a[1] += pr; } } // scale b coefficients s.t. DC gain is 0 dB cmReal_t sumB = 0, sumA = 0; for( j = 0; j < N+1; j++ ) { sumB += b[j]; sumA += a[j]; } sumA /= sumB; for( j = 0; j < N+1; j++ ) b[j] *= sumA; return cmFilterInit( p, b, N+1, a, N+1, procSmpCnt, d ); } cmRC_t cmFilterFinal( cmFilter* p ) { return cmOkRC; } cmRC_t cmFilterExecS( cmFilter* p, const cmSample_t* x, unsigned xn, cmSample_t* yy, unsigned yn ) { cmSample_t* y; if( yy == NULL || yn==0 ) { y = p->outSmpV; yn = p->outN; } else { y = yy; } cmVOS_Filter( y, yn, x, xn, p->b0, p->b, p->a, p->d, p->cn ); return cmOkRC; /* int i,j; cmSample_t y0 = 0; cmSample_t* y; unsigned n; if( yy == NULL || yn==0 ) { n = cmMin(p->outN,xn); y = p->outSmpV; yn = p->outN; } else { n = cmMin(yn,xn); y = yy; } // This is a direct form II algorithm based on the MATLAB implmentation // http://www.mathworks.com/access/helpdesk/help/techdoc/ref/filter.html#f83-1015962 for(i=0; ib0) + p->d[0]; y0 = y[i]; for(j=0; jcn; ++j) p->d[j] = (p->b[j] * x[i]) - (p->a[j] * y0) + p->d[j+1]; } // if fewer input samples than output samples - zero the end of the output buffer if( yn > xn ) cmVOS_Fill(y+i,yn-i,0); return cmOkRC; */ } cmRC_t cmFilterExecR( cmFilter* p, const cmReal_t* x, unsigned xn, cmReal_t* yy, unsigned yn ) { cmReal_t* y; if( yy == NULL || yn==0 ) { y = p->outRealV; yn = p->outN; } else { //n = cmMin(yn,xn); y = yy; } cmVOR_Filter( y, yn, x, xn, p->b0, p->b, p->a, p->d, p->cn ); return cmOkRC; } cmRC_t cmFilterSignal( cmCtx* c, const cmReal_t b[], unsigned bn, const cmReal_t a[], unsigned an, const cmSample_t* x, unsigned xn, cmSample_t* y, unsigned yn ) { int procSmpCnt = cmMin(1024,xn); cmFilter* p = cmFilterAlloc(c,NULL,b,bn,a,an,procSmpCnt,NULL); int i,n; for(i=0; ioutRealV ); cmVOR_Print( rpt, 1, p->cn, p->d ); cmFilterFree(&p); cmObjFreeStatic( cmCtxFree, cmCtx, c ); /* cmReal_t b[] = { 0.16, 0.32, 0.16 }; unsigned bn = sizeof(b)/sizeof(cmReal_t); cmReal_t a[] = { 1, -.5949, .2348}; unsigned an = sizeof(a)/sizeof(cmReal_t); cmSample_t x[] = { 1,0,0,0,0,0,0,0,0,0 }; unsigned xn = sizeof(x)/sizeof(cmSample_t); cmFilter* p = cmFilterAlloc(&c,NULL,b,bn,a,an,xn); cmFilterExec(&c,p,x,xn,NULL,0); cmVOS_Print( vReportFunc, 1, xn, p->outV ); cmVOR_Print( vReportFunc, 1, p->cn, p->d ); cmFilterExec(&c,p,x,xn,NULL,0); cmVOS_Print( vReportFunc, 1, xn, p->outV ); cmFilterFree(&p); */ } void cmFilterFilterTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ) { cmCtx c; cmCtxAlloc(&c, rpt, lhH, stH ); cmReal_t b[] = { 0.36, 0.32, 0.36 }; unsigned bn = sizeof(b)/sizeof(cmReal_t); cmReal_t a[] = {1 , -.5949, .2348 }; unsigned an = sizeof(a)/sizeof(cmReal_t); cmReal_t x[] = { 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 }; unsigned xn = sizeof(x)/sizeof(cmReal_t); unsigned yn = xn; cmReal_t y[yn]; memset(y,0,sizeof(y)); cmFilterFilterR(&c, b,bn,a,an,x,xn,y,yn ); cmVOR_Print( rpt, 1, yn, y ); cmObjFreeStatic( cmCtxFree, cmCtx, c ); } //------------------------------------------------------------------------------------------------------------ cmComplexDetect* cmComplexDetectAlloc(cmCtx* c, cmComplexDetect* p, unsigned binCnt ) { cmComplexDetect* op = cmObjAlloc( cmComplexDetect, c, p ); cmSpecDelayAlloc(c,&op->phsDelay,0,0); cmSpecDelayAlloc(c,&op->magDelay,0,0); if( binCnt > 0 ) if( cmComplexDetectInit(op,binCnt) != cmOkRC && p == NULL ) cmComplexDetectFree(&op); return op; } cmRC_t cmComplexDetectFree( cmComplexDetect** pp ) { cmRC_t rc; if( pp != NULL && *pp != NULL ) { cmComplexDetect* p = *pp; if((rc = cmComplexDetectFinal(p)) == cmOkRC ) { cmSpecDelay* sdp; sdp = &p->phsDelay; cmSpecDelayFree(&sdp); sdp = &p->magDelay; cmSpecDelayFree(&sdp); cmObjFree(pp); } } return cmOkRC; } cmRC_t cmComplexDetectInit( cmComplexDetect* p, unsigned binCnt ) { cmRC_t rc; if((rc = cmComplexDetectFinal(p)) != cmOkRC ) return rc; cmSpecDelayInit(&p->phsDelay,2,binCnt); cmSpecDelayInit(&p->magDelay,1,binCnt); p->binCnt = binCnt; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"complexDetect"); //p->cdfSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kCDF_FId, 1 ); return cmOkRC; } cmRC_t cmComplexDetectFinal( cmComplexDetect* p) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmComplexDetectExec( cmComplexDetect* p, const cmSample_t* magV, const cmSample_t* phsV, unsigned binCnt ) { p->out = cmVOS_ComplexDetect( magV, cmSpecDelayOutPtr(&p->magDelay,0), phsV, cmSpecDelayOutPtr(&p->phsDelay,1), cmSpecDelayOutPtr(&p->phsDelay,0), binCnt); p->out /= 10000000; cmSpecDelayExec(&p->magDelay,magV,binCnt); cmSpecDelayExec(&p->phsDelay,phsV,binCnt); //if( p->mfp != NULL ) // cmMtxFileSmpExec( p->mfp, &p->out, 1 ); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmSample_t _cmComplexOnsetMedian( const cmSample_t* sp, unsigned sn, void* userPtr ) { return cmVOS_Median(sp,sn); } cmComplexOnset* cmComplexOnsetAlloc( cmCtx* c, cmComplexOnset* p, unsigned procSmpCnt, double srate, unsigned medFiltWndSmpCnt, double threshold, unsigned frameCnt ) { cmComplexOnset* op = cmObjAlloc( cmComplexOnset, c, p ); if( procSmpCnt > 0 && srate > 0 && medFiltWndSmpCnt > 0 ) if( cmComplexOnsetInit( op, procSmpCnt, srate, medFiltWndSmpCnt, threshold, frameCnt ) != cmOkRC ) cmComplexOnsetFree(&op); return op; } cmRC_t cmComplexOnsetFree( cmComplexOnset** pp) { cmRC_t rc = cmOkRC; cmComplexOnset* p = *pp; if( pp==NULL || *pp == NULL ) return cmOkRC; if((rc = cmComplexOnsetFinal(*pp)) != cmOkRC ) return rc; cmMemPtrFree(&p->df); cmMemPtrFree(&p->fdf); cmObjFree(pp); return cmOkRC; } cmRC_t cmComplexOnsetInit( cmComplexOnset* p, unsigned procSmpCnt, double srate, unsigned medFiltWndSmpCnt, double threshold, unsigned frameCnt ) { cmRC_t rc; if(( rc = cmComplexOnsetFinal(p)) != cmOkRC ) return rc; p->frmCnt = frameCnt; p->dfi = 0; p->df = cmMemResizeZ( cmSample_t, p->df, frameCnt ); p->fdf = cmMemResizeZ( cmSample_t, p->fdf, frameCnt ); p->onrate = 0; p->threshold = threshold; p->medSmpCnt = medFiltWndSmpCnt; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"complexOnset"); return cmOkRC; } cmRC_t cmComplexOnsetFinal( cmComplexOnset* p) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmComplexOnsetExec( cmComplexOnset* p, cmSample_t cdf ) { p->df[p->dfi++] = cdf; return cmOkRC; } cmRC_t cmComplexOnsetCalc( cmComplexOnset* p ) { // df -= mean(df) cmVOS_SubVS(p->df,p->frmCnt,cmVOS_Mean(p->df,p->frmCnt)); // low pass forward/backward filter df[] into fdf[] double d = 2 + sqrt(2); cmReal_t b[] = {1/d, 2/d, 1/d}; unsigned bn = sizeof(b)/sizeof(b[0]); cmReal_t a[] = {1, 0, 7-2*d}; unsigned an = sizeof(a)/sizeof(a[0]); cmFilterFilterS(p->obj.ctx,b,bn,a,an,p->df,p->frmCnt,p->fdf,p->frmCnt); // median filter to low-passed filtered fdf[] into df[] cmVOS_FnThresh(p->fdf,p->frmCnt,p->medSmpCnt,p->df,1,NULL); // subtract med filtered signal from the low passed signal. // fdf[] -= df[]; cmVOS_SubVV(p->fdf,p->frmCnt,p->df); cmVOS_SubVS(p->fdf,p->frmCnt,p->threshold); cmSample_t *bp = p->df, *ep = bp + p->frmCnt - 1, *dp = p->fdf + 1; *bp++ = *ep = 0; for( ; bp *(dp-1) && *dp > *(dp+1) && *dp > 0) ? 1 : 0; p->onrate += *bp; } p->onrate /= p->frmCnt; /* if( p->mfp != NULL ) { bp = p->df; ep = bp + p->frmCnt; while( bp < ep ) cmMtxFileSmpExec( p->mfp, bp++, 1 ); } */ return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmMfcc* cmMfccAlloc( cmCtx* c, cmMfcc* ap, double srate, unsigned melBandCnt, unsigned dctCoeffCnt, unsigned binCnt ) { cmMfcc* p = cmObjAlloc( cmMfcc, c, ap ); if( melBandCnt > 0 && binCnt > 0 && dctCoeffCnt > 0 ) if( cmMfccInit( p, srate, melBandCnt, dctCoeffCnt, binCnt ) != cmOkRC ) cmMfccFree(&p); return p; } cmRC_t cmMfccFree( cmMfcc** pp ) { cmRC_t rc = cmOkRC; if( pp==NULL || *pp == NULL ) return cmOkRC; cmMfcc* p = *pp; if( (rc = cmMfccFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->melM); cmMemPtrFree(&p->dctM); cmMemPtrFree(&p->outV); cmObjFree(pp); return rc; } cmRC_t cmMfccInit( cmMfcc* p, double srate, unsigned melBandCnt, unsigned dctCoeffCnt, unsigned binCnt ) { cmRC_t rc; if((rc = cmMfccFinal(p)) != cmOkRC ) return rc; p->melM = cmMemResize( cmReal_t, p->melM, melBandCnt * binCnt ); p->dctM = cmMemResize( cmReal_t, p->dctM, dctCoeffCnt * melBandCnt ); p->outV = cmMemResize( cmReal_t, p->outV, dctCoeffCnt ); // each row of the matrix melp contains a mask cmVOR_MelMask( p->melM, melBandCnt, binCnt, srate, kShiftMelFl ); // each row contains melBandCnt elements cmVOR_DctMatrix(p->dctM, dctCoeffCnt, melBandCnt ); p->melBandCnt = melBandCnt; p->dctCoeffCnt = dctCoeffCnt; p->binCnt = binCnt; p->outN = dctCoeffCnt; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"mfcc"); //if( p->obj.ctx->statsProcPtr != NULL ) // p->mfccSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kMFCC_FId, p->outN ); return cmOkRC; } cmRC_t cmMfccFinal( cmMfcc* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmMfccExecPower( cmMfcc* p, const cmReal_t* magPowV, unsigned binCnt ) { assert( binCnt == p->binCnt ); cmReal_t t[ p->melBandCnt ]; // apply the mel filter mask to the power spectrum cmVOR_MultVMV( t, p->melBandCnt, p->melM, binCnt, magPowV ); // convert mel bands to dB cmVOR_PowerToDb( t, p->melBandCnt, t ); // decorellate the bands with a DCT cmVOR_MultVMV( p->outV, p->dctCoeffCnt, p->dctM, p->melBandCnt, t ); /* cmPlotSelectSubPlot(0,0); cmPlotClear(); //cmPlotLineS( "power", NULL, magPowV, NULL, 35, NULL, kSolidPlotLineId ); cmPlotLineS( "mel", NULL, t0, NULL, p->melBandCnt, NULL, kSolidPlotLineId ); cmPlotSelectSubPlot(1,0); cmPlotClear(); //cmPlotLineS( "meldb", NULL, t1, NULL, p->melBandCnt, NULL, kSolidPlotLineId ); cmPlotLineS( "mfcc", NULL, p->outV+1, NULL, p->dctCoeffCnt-1, NULL, kSolidPlotLineId ); */ if( p->mfp != NULL ) cmMtxFileRealExec(p->mfp,p->outV, p->outN); return cmOkRC; } cmRC_t cmMfccExecAmplitude( cmMfcc* p, const cmReal_t* magAmpV, unsigned binCnt ) { cmReal_t t[ binCnt ]; cmVOR_MultVVV( t,binCnt, magAmpV, magAmpV ); cmMfccExecPower(p,t,binCnt); if( p->mfp != NULL ) cmMtxFileRealExec(p->mfp,p->outV, p->outN); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ enum { cmSonesEqlConBinCnt = kEqualLoudBandCnt, cmSonesEqlConCnt=13 }; cmSones* cmSonesAlloc( cmCtx* c, cmSones* ap, double srate, unsigned barkBandCnt, unsigned binCnt, unsigned flags ) { cmSones* p = cmObjAlloc( cmSones, c, ap ); if( srate > 0 && barkBandCnt > 0 && binCnt > 0 ) if( cmSonesInit(p,srate,barkBandCnt,binCnt,flags) != cmOkRC ) cmSonesFree(&p); return p; } cmRC_t cmSonesFree( cmSones** pp ) { cmRC_t rc = cmOkRC; cmSones* p = *pp; if( pp==NULL || *pp==NULL) return cmOkRC; if((rc = cmSonesFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->ttmV); cmMemPtrFree(&p->sfM); cmMemPtrFree(&p->barkIdxV); cmMemPtrFree(&p->barkCntV); cmMemPtrFree(&p->outV); cmObjFree(pp); return rc; } cmRC_t cmSonesInit( cmSones* p, double srate, unsigned barkBandCnt, unsigned binCnt, unsigned flags ) { p->ttmV = cmMemResize( cmReal_t, p->ttmV, binCnt); p->sfM = cmMemResize( cmReal_t, p->sfM, binCnt*barkBandCnt); p->barkIdxV = cmMemResize( unsigned, p->barkIdxV, barkBandCnt); p->barkCntV = cmMemResize( unsigned, p->barkCntV, barkBandCnt); p->outV = cmMemResize( cmReal_t, p->outV, barkBandCnt); // calc outer ear filter cmVOR_TerhardtThresholdMask( p->ttmV, binCnt, srate, kNoTtmFlags ); // calc shroeder spreading function cmVOR_ShroederSpreadingFunc(p->sfM, barkBandCnt, srate); // calc the bin to bark maps p->barkBandCnt = cmVOR_BarkMap( p->barkIdxV, p->barkCntV, barkBandCnt, binCnt, srate ); //unsigned i = 0; //for(; iflags, kUseEqlLoudSonesFl); p->binCnt = binCnt; p->outN = elFl ? cmSonesEqlConCnt : p->barkBandCnt; p->overallLoudness = 0; p->flags = flags; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"sones"); //p->sonesSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kSones_FId, p->outN ); //p->loudSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kLoud_FId, 1 ); return cmOkRC; } cmRC_t cmSonesFinal( cmSones* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmSonesExec( cmSones* p, const cmReal_t* magPowV, unsigned binCnt ) { assert( binCnt == p->binCnt ); // Equal-loudness and phon map from: Y. Wonho, 1999, EMBSD: an objective speech quality measure based on audible distortion, // equal-loudness contours double eqlcon[cmSonesEqlConCnt][cmSonesEqlConBinCnt] = { {12,7,4,1,0,0,0,-0.5,-2,-3,-7,-8,-8.5,-8.5,-8.5}, {20,17,14,12,10,9.5,9,8.5,7.5,6.5,4,3,2.5,2,2.5}, {29,26,23,21,20,19.5,19.5,19,18,17,15,14,13.5,13,13.5}, {36,34,32,30,29,28.5,28.5,28.5,28,27.5,26,25,24.5,24,24.5}, {45,43,41,40,40,40,40,40,40,39.5,38,37,36.5,36,36.5}, {53,51,50,49,48.5,48.5,49,49,49,49,48,47,46.5,45.5,46}, {62,60,59,58,58,58.5,59,59,59,59,58,57.5,57,56,56}, {70,69,68,67.5,67.5,68,68,68,68,68,67,66,65.5,64.5,64.5}, {79,79,79,79,79,79,79,79,78,77.5,76,75,74.5,73,73}, {89,89,89,89.5,90,90,90,89.5,89,88.5,87,86,85.5,84,83.5}, {100,100,100,100,100,99.5,99,99,98.5,98,96,95,94.5,93.5,93}, {112,112,112,112,111,110.5,109.5,109,108.5,108,106,105,104.5,103,102.5}, {122,122,121,121,120.5,120,119,118,117,116.5,114.5,113.5,113,111, 110.5} }; // loudness levels (phone scales) double phons[cmSonesEqlConCnt]= {0.0,10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,110.0,120.0}; unsigned i,j; cmReal_t t0[ binCnt ]; cmReal_t t1[ p->barkBandCnt ]; cmReal_t t2[ p->barkBandCnt ]; unsigned* idxV = p->barkIdxV; unsigned* cntV = p->barkCntV; cmReal_t* sfM = p->sfM; // apply the outer ear filter cmVOR_MultVVV( t0, binCnt, magPowV, p->ttmV); // apply the bark frequency warping for(i=0; ibarkBandCnt; ++i) { if( cntV[i] == 0 ) t1[i] = 0; else { t1[i] = t0[ idxV[i] ]; for(j=1; jbarkBandCnt, sfM, p->barkBandCnt, t1 ); bool elFl = cmIsFlag(p->flags, kUseEqlLoudSonesFl); unsigned bandCnt = elFl ? cmMin(p->barkBandCnt,cmSonesEqlConBinCnt) : p->barkBandCnt; //p->outN = elFl ? cmSonesEqlConCnt : p->barkBandCnt; p->overallLoudness = 0; for( i = 0; i barkBandCnt ) { double v = t2[k]; // convert to db v = 10*log10( v<1 ? 1 : v ); if( elFl ) { // db to phons // see: Y. Wonho, 1999, EMBSD: an objective speech quality measure based on audible distortion, j = 0; // find the equal loudness curve for this frequency and db level while( v >= eqlcon[j][i] ) ++j; if( j == cmSonesEqlConCnt ) { cmCtxRtAssertFailed( &p->obj, cmArgAssertRC, "Bark band %i is out of range during equal-loudness mapping.",j ); continue; } // convert db to phons if( j == 0 ) v = phons[0]; else { double t1 = ( v - eqlcon[j-1][i] ) / ( eqlcon[j][i] - eqlcon[j-1][i] ); v = phons[j-1] + t1 * (phons[j] - phons[j-1]); } } // convert to sones // bladon and lindblom, 1981, JASA, modelling the judment of vowel quality differences if( v >= 40 ) p->outV[i] = pow(2,(v-40)/10); else p->outV[i] = pow(v/40,2.642); p->overallLoudness += p->outV[i]; } } if( p->mfp != NULL ) cmMtxFileRealExec( p->mfp, p->outV, p->outN ); return cmOkRC; } void cmSonesTest() { cmKbRecd kb; double srate = 44100; unsigned bandCnt = 23; unsigned binCnt = 513; cmSample_t tv[ binCnt ]; cmSample_t sm[ bandCnt * bandCnt ]; cmSample_t t[ bandCnt * bandCnt ]; unsigned binIdxV[ bandCnt ]; unsigned cntV[ bandCnt ]; unsigned i; cmPlotSetup("Sones",1,1); cmVOS_TerhardtThresholdMask(tv,binCnt,srate, kModifiedTtmFl ); cmVOS_ShroederSpreadingFunc(sm, bandCnt, srate); cmVOS_Transpose( t, sm, bandCnt, bandCnt ); bandCnt = cmVOS_BarkMap(binIdxV,cntV, bandCnt, binCnt, srate ); for(i=0; i 0 && srate > 0 ) if( cmAudioOffsetScaleInit( p, procSmpCnt, srate, offset, rmsWndSecs, dBref, flags ) != cmOkRC ) cmAudioOffsetScaleFree(&p); return p; } cmRC_t cmAudioOffsetScaleFree( cmAudioOffsetScale** pp ) { cmRC_t rc = cmOkRC; cmAudioOffsetScale* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmAudioOffsetScaleFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->cBufPtr); cmMemPtrFree(&p->cCntPtr); cmMemPtrFree(&p->outV); cmObjFree(pp); return rc; } cmRC_t cmAudioOffsetScaleInit( cmAudioOffsetScale* p, unsigned procSmpCnt, double srate, cmSample_t offset, double rmsWndSecs, double dBref, unsigned flags ) { assert( procSmpCnt > 0 && srate > 0); cmRC_t rc; if((rc = cmAudioOffsetScaleFinal(p)) != cmOkRC ) return rc; p->cBufCnt = 0; if( cmIsFlag(flags, kRmsAudioScaleFl) ) { if( rmsWndSecs > 0 ) { unsigned rmsSmpCnt = srate * rmsWndSecs; p->cBufCnt = (unsigned)ceil( rmsSmpCnt / procSmpCnt ); if( p->cBufCnt > 0 ) { p->cBufPtr = cmMemResizeZ( cmReal_t, p->cBufPtr, p->cBufCnt ); p->cCntPtr = cmMemResizeZ( unsigned, p->cCntPtr, p->cBufCnt ); } } else { p->cBufCnt = 0; p->cBufPtr = NULL; p->cCntPtr = NULL; } } p->cBufIdx = 0; p->cBufCurCnt = 0; p->cBufSum = 0; p->cCntSum = 0; p->outV = cmMemResize( cmSample_t, p->outV, procSmpCnt ); p->outN = procSmpCnt; p->offset = offset; p->dBref = dBref; p->flags = flags; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"audioOffsetScale"); return cmOkRC; } cmRC_t cmAudioOffsetScaleFinal( cmAudioOffsetScale* p ) { //if( p != NULL) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmAudioOffsetScaleExec( cmAudioOffsetScale* p, const cmSample_t* sp, unsigned sn ) { double Pref = 20.0 / 1000000; // 20 micro Pascals cmSample_t* dbp = p->outV; const cmSample_t* dep = dbp + sn; double scale = 0; // if no scaling was requested then add offset only if( cmIsFlag(p->flags, kNoAudioScaleFl) ) { while( dbp < dep ) *dbp++ = *sp++ + p->offset; goto doneLabel; } // if fixed scaling if( cmIsFlag(p->flags, kFixedAudioScaleFl) ) { if( scale == 0 ) scale = pow(10,p->dBref/20); while( dbp < dep ) *dbp++ = (*sp++ + p->offset) * scale; } else // if RMS scaling { double sum = 0; double rms = 0; while( dbp < dep ) { double v = (*sp++ + p->offset) / Pref; sum += v*v; *dbp++ = v; } // if there is no RMS buffer calc RMS on procSmpCnt samles if( p->cBufCnt == 0 ) rms = sqrt( sum / sn ); else { p->cBufSum -= p->cBufPtr[ p->cBufIdx ]; p->cBufSum += sum; p->cCntSum -= p->cCntPtr[ p->cBufIdx ]; p->cCntSum += sn; p->cBufIdx = (p->cBufIdx+1) % p->cBufCnt; p->cBufCurCnt = cmMin( p->cBufCurCnt+1, p->cBufCnt ); assert( p->cCntSum > 0 ); rms = sqrt( p->cBufSum / p->cCntSum ); } double sigSPL = 20*log10(rms); scale = pow(10,(p->dBref - sigSPL)/20); dbp = p->outV; while( dbp < dep ) *dbp++ *= scale; } doneLabel: dbp = p->outV + sn; dep = p->outV + p->outN; while( dbp < dep ) *dbp++ = 0; if( p->mfp != NULL ) cmMtxFileSmpExec(p->mfp,p->outV,p->outN); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmSpecMeas* cmSpecMeasAlloc( cmCtx* c, cmSpecMeas* ap, double srate, unsigned binCnt, unsigned wndFrmCnt, unsigned flags ) { cmSpecMeas* p = cmObjAlloc( cmSpecMeas, c, ap ); if( srate > 0 && binCnt > 0 ) if( cmSpecMeasInit( p, srate, binCnt, wndFrmCnt, flags ) != cmOkRC ) cmSpecMeasFree(&p); return p; } cmRC_t cmSpecMeasFree( cmSpecMeas** pp ) { cmRC_t rc = cmOkRC; cmSpecMeas* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmSpecMeasFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->rmsV); cmMemPtrFree(&p->hfcV); cmMemPtrFree(&p->scnV); cmObjFree(pp); return rc; } cmRC_t cmSpecMeasInit( cmSpecMeas* p, double srate, unsigned binCnt, unsigned wndFrmCnt, unsigned flags ) { cmRC_t rc; if((rc = cmSpecMeasFinal(p)) != cmOkRC ) return rc; if( cmIsFlag(flags, kUseWndSpecMeasFl) ) { p->rmsV = cmMemResizeZ( cmReal_t, p->rmsV, wndFrmCnt ); p->hfcV = cmMemResizeZ( cmReal_t, p->hfcV, wndFrmCnt ); p->scnV = cmMemResizeZ( cmReal_t, p->scnV, wndFrmCnt ); } p->rmsSum = 0; p->hfcSum = 0; p->scnSum = 0; p->binCnt = binCnt; p->flags = flags; p->wndFrmCnt = wndFrmCnt; p->frameCnt = 0; p->frameIdx = 0; p->binHz = srate / ((binCnt-1) * 2); //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"specMeas"); //p->rmsSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kRMS_FId, 1); //p->hfcSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kHFC_FId, 1); //p->scSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kSC_FId, 1); //p->ssSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kSS_FId, 1); return cmOkRC; } cmRC_t cmSpecMeasFinal( cmSpecMeas* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmSpecMeasExec( cmSpecMeas* p, const cmReal_t* magPowV, unsigned binCnt ) { assert( binCnt == p->binCnt ); unsigned i = 0; const cmReal_t* sbp = magPowV; const cmReal_t* sep = sbp + binCnt; cmReal_t rmsSum = 0; cmReal_t hfcSum = 0; cmReal_t scnSum = 0; cmReal_t ssSum = 0; for(i=0; sbp < sep; ++i, ++sbp ) { rmsSum += *sbp; hfcSum += *sbp * i; scnSum += *sbp * i * p->binHz; } p->frameCnt++; if( cmIsFlag(p->flags, kUseWndSpecMeasFl) ) { p->frameCnt = cmMin( p->frameCnt, p->wndFrmCnt ); cmReal_t* rmsV = p->rmsV + p->frameIdx; cmReal_t* hfcV = p->hfcV + p->frameIdx; cmReal_t* scnV = p->scnV + p->frameIdx; p->rmsSum -= *rmsV; p->hfcSum -= *hfcV; p->scnSum -= *scnV; *rmsV = rmsSum; *hfcV = hfcSum; *scnV = scnSum; p->frameIdx = (p->frameIdx+1) % p->frameCnt; } p->rmsSum += rmsSum; p->hfcSum += hfcSum; p->scnSum += scnSum; p->rms = sqrt(p->rmsSum / (p->binCnt * p->frameCnt) ); p->hfc = p->hfcSum / ( p->binCnt * p->frameCnt ); p->sc = p->scnSum / cmMax( cmReal_EPSILON, p->rmsSum ); sbp = magPowV; for(i=0; sbp < sep; ++i ) { cmReal_t t = (i*p->binHz) - p->sc; ssSum += *sbp++ * (t*t); } p->ss = sqrt(ssSum / cmMax( cmReal_EPSILON, p->rmsSum )); if( p->mfp != NULL ) { cmReal_t a[4] = { p->rms, p->hfc, p->sc, p->ss }; cmMtxFileRealExec( p->mfp, a, 4 ); } return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmSigMeas* cmSigMeasAlloc( cmCtx* c, cmSigMeas* ap, double srate, unsigned procSmpCnt, unsigned measSmpCnt ) { cmSigMeas* p = cmObjAlloc( cmSigMeas, c, ap ); p->sbp = cmShiftBufAlloc(c,&p->shiftBuf,0,0,0); if( srate > 0 && procSmpCnt > 0 && measSmpCnt > 0 ) if( cmSigMeasInit( p, srate, procSmpCnt, measSmpCnt ) != cmOkRC ) cmSigMeasFree(&p); return p; } cmRC_t cmSigMeasFree( cmSigMeas** pp ) { cmRC_t rc = cmOkRC; cmSigMeas* p = *pp; if( pp==NULL || *pp==NULL) return cmOkRC; if((rc = cmSigMeasFinal(p)) != cmOkRC ) return rc; cmShiftBufFree(&p->sbp); cmObjFree(pp); return rc; } cmRC_t cmSigMeasInit( cmSigMeas* p, double srate, unsigned procSmpCnt, unsigned measSmpCnt ) { cmRC_t rc; if((rc = cmSigMeasFinal(p)) != cmOkRC ) return rc; if( procSmpCnt != measSmpCnt ) cmShiftBufInit( p->sbp, procSmpCnt, measSmpCnt, procSmpCnt ); p->zcrDelay = 0; p->srate = srate; p->measSmpCnt = measSmpCnt; p->procSmpCnt = procSmpCnt; //p->zcrSpRegId = cmStatsProcReg( p->obj.ctx->statsProcPtr, kZCR_FId, 1 ); //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"sigMeas"); return cmOkRC; } cmRC_t cmSigMeasFinal( cmSigMeas* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmSigMeasExec( cmSigMeas* p, const cmSample_t* sp, unsigned sn ) { if( p->procSmpCnt != p->measSmpCnt ) { cmShiftBufExec( p->sbp, sp, sn ); sp = p->sbp->outV; sn = p->sbp->wndSmpCnt; assert( p->sbp->wndSmpCnt == p->measSmpCnt ); } unsigned zcn = cmVOS_ZeroCrossCount( sp, sn, NULL ); p->zcr = (cmReal_t)zcn * p->srate / p->measSmpCnt; if( p->mfp != NULL ) cmMtxFileRealExec( p->mfp, &p->zcr, 1 ); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmSRC* cmSRCAlloc( cmCtx* c, cmSRC* ap, double srate, unsigned procSmpCnt, unsigned upFact, unsigned dnFact ) { cmSRC* p = cmObjAlloc( cmSRC, c,ap ); cmFilterAlloc(c,&p->filt,NULL,0,NULL,0,0,NULL); if( srate > 0 && procSmpCnt > 0 ) if( cmSRCInit( p, srate, procSmpCnt, upFact, dnFact ) != cmOkRC ) cmSRCFree(&p); return p; } cmRC_t cmSRCFree( cmSRC** pp ) { cmRC_t rc; if( pp != NULL && *pp != NULL ) { cmSRC* p = *pp; if((rc = cmSRCFinal( p )) == cmOkRC ) { cmFilter* fp = &p->filt; cmFilterFree(&fp); cmMemPtrFree(&p->outV); cmObjFree(pp); } } return cmOkRC; } cmRC_t cmSRCInit( cmSRC* p, double srate, unsigned procSmpCnt, unsigned upFact, unsigned dnFact ) { cmRC_t rc; if((rc = cmSRCFinal(p)) != cmOkRC ) return rc; double hiRate = upFact * srate; double loRate = hiRate / dnFact; double minRate= cmMin( loRate, srate ); double fcHz = minRate/2; double dHz = (fcHz * .1); // transition band is 5% of min sample rate double passHz = fcHz-dHz; double stopHz = fcHz; double passDb = 0.001; double stopDb = 20; cmFilterInitEllip( &p->filt, hiRate, passHz, stopHz, passDb, stopDb, procSmpCnt, NULL ); //printf("CoeffCnt:%i dHz:%f passHz:%f stopHz:%f passDb:%f stopDb:%f\n", p->fir.coeffCnt, dHz, passHz, stopHz, passDb, stopDb ); p->outN = (unsigned)ceil(procSmpCnt * upFact / dnFact); p->outV = cmMemResize( cmSample_t, p->outV, p->outN ); p->upi = 0; p->dni = 0; p->upFact = upFact; p->dnFact = dnFact; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"src"); return cmOkRC; } cmRC_t cmSRCFinal( cmSRC* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmSRCExec( cmSRC* p, const cmSample_t* sp, unsigned sn ) { const cmSample_t* sep = sp + sn; cmSample_t* op = p->outV; const cmSample_t* oep = op + p->outN; unsigned iN = sn * p->upFact; unsigned i,j; // run the filter at the upsampled rate ... for(i=0; iupi!=0 || spupi==0 ? *sp++ : 0, y0 = x0 * p->filt.b0 + p->filt.d[0]; // ... but output at the down sampled rate if( p->dni==0 ) { assert( op < oep ); *op++ = y0; } // advance the filter delay line for(j=0; jfilt.cn; ++j) p->filt.d[j] = p->filt.b[j]*x0 - p->filt.a[j]*y0 + p->filt.d[j+1]; // update the input/output clocks p->upi = (p->upi + 1) % p->upFact; p->dni = (p->dni + 1) % p->dnFact; } p->outN = op - p->outV; if( p->mfp != NULL ) cmMtxFileSmpExec(p->mfp,p->outV,p->outN ); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmConstQ* cmConstQAlloc( cmCtx* c, cmConstQ* ap, double srate, unsigned minMidiPitch, unsigned maxMidiPitch, unsigned binsPerOctave, double thresh ) { cmConstQ* p = cmObjAlloc( cmConstQ, c, ap ); if( srate >0 ) if( cmConstQInit(p,srate,minMidiPitch,maxMidiPitch,binsPerOctave,thresh) != cmOkRC ) cmConstQFree(&p); return p; } cmRC_t cmConstQFree( cmConstQ** pp ) { cmRC_t rc; cmConstQ* p = *pp; if( pp==NULL || *pp==NULL) return cmOkRC; if((rc = cmConstQFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->fiV); cmMemPtrFree(&p->foV); cmMemPtrFree(&p->skM); cmMemPtrFree(&p->outV); cmMemPtrFree(&p->magV); cmMemPtrFree(&p->skBegV); cmMemPtrFree(&p->skEndV); cmObjFree(pp); return cmOkRC; } cmRC_t cmConstQInit( cmConstQ* p, double srate, unsigned minMidiPitch, unsigned maxMidiPitch, unsigned binsPerOctave, double thresh ) { cmRC_t rc; if((rc = cmConstQFinal(p)) != cmOkRC ) return rc; cmReal_t minHz = cmMidiToHz(minMidiPitch); cmReal_t maxHz = cmMidiToHz(maxMidiPitch); cmReal_t Q = 1.0/(pow(2,(double)1.0/binsPerOctave)-1); unsigned K = (unsigned)ceil( binsPerOctave * log2(maxHz/minHz) ); unsigned fftN = cmNextPowerOfTwo( (unsigned)ceil(Q*srate/minHz) ); unsigned k = 0; p->fiV = cmMemResize(cmComplexR_t, p->fiV, fftN); p->foV = cmMemResize(cmComplexR_t, p->foV, fftN); cmFftPlanR_t plan = cmFft1dPlanAllocR(fftN, p->fiV, p->foV, FFTW_FORWARD, FFTW_ESTIMATE ); p->wndSmpCnt = fftN; p->constQBinCnt = K; p->binsPerOctave= binsPerOctave; p->skM = cmMemResizeZ( cmComplexR_t, p->skM, p->wndSmpCnt * p->constQBinCnt); p->outV = cmMemResizeZ( cmComplexR_t, p->outV, p->constQBinCnt); p->magV = cmMemResizeZ( cmReal_t, p->magV, p->constQBinCnt); p->skBegV = cmMemResizeZ( unsigned, p->skBegV, p->constQBinCnt); p->skEndV = cmMemResizeZ( unsigned, p->skEndV, p->constQBinCnt); //p->mfp = cmCtxAllocDebugFile( p->obj.ctx, "constQ"); //printf("hz:%f %f bpo:%i sr:%f thresh:%f Q:%f K%i (cols) fftN:%i (rows)\n", minHz,maxHz,binsPerOctave,srate,thresh,Q,K,fftN); double* hamm = NULL; // note that the bands are created in reverse order for(k=0; kfiV, 0, fftN * sizeof(cmComplexR_t)); memset( p->foV, 0, fftN * sizeof(cmComplexR_t)); cmVOD_Hamming( hamm, iN ); cmVOD_DivVS( hamm, iN, iN ); if( cmIsEvenU(iN) ) start -= iN/2; else start -= (iN+1)/2; //printf("k:%i iN:%i start:%i %i\n",k,iN,start,start+iN-1); unsigned i = start; for(; i<=start+iN-1; ++i) { double arg = 2.0*M_PI*Q*(i-start)/iN; double mag = hamm[i-start]; p->fiV[i-1] = (mag * cos(arg)) + (mag * I * sin(arg)); } cmFftExecuteR(plan); // since the bands are created in reverse order they are also stored in reverse order // (i.e column k-1 is stored first and column 0 is stored last) i=0; unsigned minIdx = -1; unsigned maxIdx = 0; for(; ifoV[i]) <= thresh; p->skM[ (k*p->wndSmpCnt) + i ] = fl ? 0 : p->foV[i]/fftN; if( fl==false && minIdx == -1 ) minIdx = i; if( fl==false && i>maxIdx ) maxIdx = i; } p->skBegV[k] = minIdx; p->skEndV[k] = maxIdx; } cmMemPtrFree(&hamm); cmFftPlanFreeR(plan); return cmOkRC; } cmRC_t cmConstQFinal( cmConstQ* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmConstQExec( cmConstQ* p, const cmComplexR_t* ftV, unsigned srcBinCnt ) { //acVORC_MultVVM( p->outV, p->constQBinCnt,ftV,p->wndSmpCnt, p->skM ); cmReal_t* mbp = p->magV; cmComplexR_t* dbp = p->outV; const cmComplexR_t* dep = p->outV + p->constQBinCnt; unsigned i = 0; for(; dbp < dep; ++dbp,++i,++mbp ) { const cmComplexR_t* sbp = ftV + p->skBegV[i]; const cmComplexR_t* kp = p->skM + (i*p->wndSmpCnt) + p->skBegV[i]; const cmComplexR_t* ep = kp + (p->skEndV[i] - p->skBegV[i]) + 1; *dbp = 0; while( kp < ep ) *dbp += *sbp++ * *kp++; *mbp = cmCabsR(*dbp); } if( p->mfp != NULL ) cmMtxFileComplexExec( p->mfp, p->outV, p->constQBinCnt, 1 ); return cmOkRC; } void cmConstQTest( cmConstQ* p ) { cmKbRecd kb; unsigned i,j; cmSample_t* t = cmMemAlloc( cmSample_t, p->wndSmpCnt ); for(i=0; iconstQBinCnt; ++i) { for(j=0; jwndSmpCnt; ++j) t[j] = cabs( p->skM[ (i*p->wndSmpCnt) + j ]); //cmPlotClear(); cmPlotLineS( NULL, NULL, t, NULL, 500, NULL, kSolidPlotLineId ); } cmPlotDraw(); cmKeyPress(&kb); cmMemPtrFree(&t); } //------------------------------------------------------------------------------------------------------------ cmHpcp* cmTunedHpcpAlloc( cmCtx* c, cmHpcp* ap, unsigned binsPerOctave, unsigned constQBinCnt, unsigned cqMinMidiPitch, unsigned frameCnt, unsigned medFiltOrder ) { cmHpcp* p = cmObjAlloc( cmHpcp, c, ap ); if( binsPerOctave > 0 && constQBinCnt >> 0 ) if( cmTunedHpcpInit( p, binsPerOctave, constQBinCnt, cqMinMidiPitch, frameCnt, medFiltOrder ) != cmOkRC) cmTunedHpcpFree(&p); return p; } cmRC_t cmTunedHpcpFree( cmHpcp** pp ) { cmRC_t rc = cmOkRC; cmHpcp* p = *pp; if(pp==NULL || *pp==NULL) return cmOkRC; if((rc = cmTunedHpcpFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->hpcpM); cmMemPtrFree(&p->fhpcpM); cmMemPtrFree(&p->histV); cmMemPtrFree(&p->outM); cmMemPtrFree(&p->meanV); cmMemPtrFree(&p->varV); cmObjFree(pp); return cmOkRC; } cmRC_t cmTunedHpcpInit( cmHpcp* p, unsigned binsPerOctave, unsigned constQBinCnt, unsigned cqMinMidiPitch, unsigned frameCnt, unsigned medFiltOrder ) { assert( binsPerOctave % kStPerOctave == 0 ); assert( cmIsOddU( binsPerOctave / kStPerOctave ) ); cmRC_t rc; if((rc = cmTunedHpcpFinal(p)) != cmOkRC ) return rc; p->histN = binsPerOctave/kStPerOctave; p->hpcpM = cmMemResizeZ( cmReal_t, p->hpcpM, frameCnt*binsPerOctave ); p->fhpcpM = cmMemResizeZ( cmReal_t, p->fhpcpM, binsPerOctave*frameCnt ); p->histV = cmMemResizeZ( unsigned, p->histV, p->histN ); p->outM = cmMemResizeZ( cmReal_t, p->outM, kStPerOctave * frameCnt ); p->meanV = cmMemResizeZ( cmReal_t, p->meanV, kStPerOctave ); p->varV = cmMemResizeZ( cmReal_t, p->varV, kStPerOctave ); p->constQBinCnt = constQBinCnt; p->binsPerOctave = binsPerOctave; p->frameCnt = frameCnt; p->frameIdx = 0; p->cqMinMidiPitch= cqMinMidiPitch; p->medFiltOrder = medFiltOrder; //p->mf0p = cmCtxAllocDebugFile(p->obj.ctx,"hpcp"); //p->mf1p = cmCtxAllocDebugFile(p->obj.ctx,"fhpcp"); //p->mf2p = cmCtxAllocDebugFile(p->obj.ctx,"chroma"); return cmOkRC; } cmRC_t cmTunedHpcpFinal( cmHpcp* p ) { /* if( p != NULL ) { cmCtxFreeDebugFile(p->obj.ctx,&p->mf0p); cmCtxFreeDebugFile(p->obj.ctx,&p->mf1p); cmCtxFreeDebugFile(p->obj.ctx,&p->mf2p); } */ return cmOkRC; } cmRC_t cmTunedHpcpExec( cmHpcp* p, const cmComplexR_t* cqp, unsigned cqn ) { assert( cqn == p->constQBinCnt ); // if there is no space to store the output then do nothing if( p->frameIdx >= p->frameCnt ) return cmOkRC; unsigned octCnt = (unsigned)floor(p->constQBinCnt / p->binsPerOctave); unsigned i; cmReal_t hpcpV[ p->binsPerOctave + 2 ]; unsigned idxV[ p->binsPerOctave ]; unsigned binsPerSt = p->binsPerOctave / kStPerOctave; // Notice that the first and last elements of p->hpcp are reserved for // use in producing the appeareance of circularity for the peak picking // algorithm. The cmtual hpcp[] data begins on the index 1 (not 0) and // ends on p->binsPerOctave (not p->binsPerOctave-1). // sum the constQBinCnt constant Q bins into binsPerOctave bins to form the HPCP for(i=0; ibinsPerOctave; ++i) { cmReal_t sum = 0; const cmComplexR_t* sbp = cqp + i; const cmComplexR_t* sep = cqp + (octCnt * p->binsPerOctave); for(; sbp < sep; sbp += p->binsPerOctave) sum += cmCabsR(*sbp); hpcpV[i+1] = sum; } // shift the lowest ST center bin to (binsPerSt+1)/2 such that an equal number of // flat and sharp bins are above an below it int rotateCnt = ((binsPerSt+1)/2) - 1; // shift pitch class C to the lowest semitone boundary rotateCnt -= ( 48-(int)p->cqMinMidiPitch) * binsPerSt; // perform the shift cmVOR_Rotate(hpcpV+1, p->binsPerOctave, rotateCnt); // duplicate the first and last bin to produce circularity in the hpcp hpcpV[0] = hpcpV[ p->binsPerOctave ]; hpcpV[ p->binsPerOctave+1 ] = hpcpV[1]; // locate the indexes of the positive peaks in the hpcp unsigned pkN = cmVOR_PeakIndexes( idxV, p->binsPerOctave, hpcpV, p->binsPerOctave, 0 ); // Convert the peak indexes to values in the range 0 to binsPerSet-1 // If stPerBin == 3 : 0=flat 1=in tune 2=sharp cmVOU_Mod( idxV, pkN, binsPerSt ); // Form a histogram to keep count of the number of flat,in-tune and sharp peaks cmVOU_Hist( p->histV, binsPerSt, idxV, pkN ); // store the hpcpV[] to the row p->hpcpM[p->frameIdx,:] cmVOR_CopyN( p->hpcpM + p->frameIdx, p->binsPerOctave, p->frameCnt, hpcpV+1, 1 ); // write the hpcp debug file if( p->mf0p != NULL ) cmMtxFileRealExecN( p->mf0p, p->hpcpM + p->frameIdx, p->binsPerOctave, p->frameCnt ); p->frameIdx++; return cmOkRC; } cmRC_t cmTunedHpcpTuneAndFilter( cmHpcp* p) { // note: p->frameIdx now holds the cmtual count of frames in p->hpcpA[]. // p->frameCnt holds the allocated count of frames in p->hpcpA[]. unsigned i,j; // filter each column of hpcpA[] into each row of fhpcpA[] for(i=0; ibinsPerOctave; ++i) { cmVOR_MedianFilt( p->hpcpM + (i * p->frameCnt), p->frameIdx, p->medFiltOrder, p->fhpcpM + i, p->binsPerOctave ); // write the fhpcp[i,:] to the debug file if( p->mf1p != NULL ) cmMtxFileRealExecN( p->mf1p, p->fhpcpM + i, p->frameIdx, p->binsPerOctave ); } unsigned binsPerSt = p->histN; assert( (binsPerSt > 0) && (cmIsOddU(binsPerSt)) ); unsigned maxIdx = cmVOU_MaxIndex(p->histV,binsPerSt,1); int tuneShift = -(maxIdx - ((binsPerSt+1)/2)); cmReal_t gaussWndV[ binsPerSt ]; // generate a gaussian window cmVOR_GaussWin( gaussWndV, binsPerSt, 2.5 ); // Rotate the window to apply tuning via the weighted sum operation below // (the result will be equivalent to rotating p->fhpcpM[] prior to reducing the ) cmVOR_Rotate(gaussWndV, binsPerSt, tuneShift); // zero the meanV[] before summing into it cmVOR_Fill(p->meanV,kStPerOctave,0); // for each frame for(i=0; iframeIdx; ++i) { // for each semitone for(j=0; jfhpcpM + (i*p->binsPerOctave) + (j*binsPerSt), binsPerSt ); // store time-series output to the ith column p->outM[ (i*kStPerOctave) + j ] = sum; // calc the sum of all chroma values in bin j. p->meanV[ j ] += sum; } // write the chroma debug file if( p->mf2p != NULL ) cmMtxFileRealExec( p->mf2p, p->outM + (i*kStPerOctave), kStPerOctave ); } // form the chroma mean from the sum calc'd above cmVOR_DivVS( p->meanV, kStPerOctave, p->frameIdx ); // variance for(j=0; jvarV[j] = cmVOR_VarianceN( p->outM + j, p->frameIdx, kStPerOctave, p->meanV + j ); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ /* cmStatsProc* cmStatsProcAlloc( cmCtx* c, cmStatsProc* p, unsigned wndEleCnt, unsigned flags ) { cmStatsProc* op = cmObjAlloc(cmStatsProc,c,p); if( wndEleCnt > 0 ) if( cmStatsProcInit(op, wndEleCnt, flags ) != cmOkRC ) cmStatsProcFree(&op); if( op != NULL ) cmCtxSetStatsProc(c,op); return op; } cmRC_t cmStatsProcFree( cmStatsProc** pp ) { cmRC_t rc = cmOkRC; cmStatsProc* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmStatsProcFinal(p) ) != cmOkRC ) return rc; cmCtxSetStatsProc(p->obj.ctx,NULL); // complement to cmSetStatsProc() in cmStatsProcAlloc() cmMemPtrFree(&p->regArrayV); cmMemPtrFree(&p->m); cmMemPtrFree(&p->sumV); cmMemPtrFree(&p->meanV); cmMemPtrFree(&p->varV); cmObjFree(pp); return cmOkRC; } cmRC_t cmStatsProcInit( cmStatsProc* p, unsigned wndEleCnt, unsigned flags ) { cmRC_t rc; if((rc = cmStatsProcFinal(p)) != cmOkRC ) return rc; p->wndEleCnt = wndEleCnt; p->dimCnt = 0; p->curIdx = 0; p->curCnt = 1; p->flags = flags; p->execCnt = 0; p->regArrayN = 0; //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"statsProc"); return rc; } cmRC_t cmStatsProcFinal( cmStatsProc* p ) { if( p != NULL ) cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } unsigned cmStatsProcReg( cmStatsProc* p, unsigned featId, unsigned featEleCnt ) { cmStatsProcRecd r; r.featId = featId; r.idx = p->dimCnt; r.cnt = featEleCnt; p->dimCnt += featEleCnt; //unsigned i; // printf("B:\n"); //for(i=0; iregArrayN; ++i) // printf("fid:%i idx:%i cnt:%i : fid:%i cnt:%i\n", p->regArrayV[i].featId,p->regArrayV[i].idx,p->regArrayV[i].cnt,featId,featEleCnt); //printf("\nA:\n"); p->regArrayV = cmMemResizePZ( cmStatsProcRecd, p->regArrayV, p->regArrayN+1 ); p->regArrayV[ p->regArrayN ] = r; p->regArrayN++; //for(i=0; iregArrayN; ++i) // printf("fid:%i idx:%i cnt:%i : fid:%i cnt:%i\n", p->regArrayV[i].featId,p->regArrayV[i].idx,p->regArrayV[i].cnt,featId,featEleCnt); //printf("\n"); return p->regArrayN-1; // return the index of the new reg recd } const cmStatsProcRecd* cmStatsProcRecdPtr( cmStatsProc* p, unsigned regId ) { assert( regId < p->regArrayN ); return p->regArrayV + regId; } cmRC_t cmStatsProcExecD( cmStatsProc* p, unsigned regId, const double v[], unsigned vCnt ) { cmRC_t rc = cmOkRC; // on the first pass allcoate the storage buffer (m) and vectors (sumV,meanV and varV) if( p->execCnt == 0 ) { p->sumV = cmMemResizeZ( double, p->sumV, p->dimCnt); p->meanV = cmMemResizeZ( double, p->meanV, p->dimCnt ); p->varV = cmMemResizeZ( double, p->varV, p->dimCnt ); p->m = cmMemResizeZ( double, p->m, p->dimCnt * p->wndEleCnt ); } // if the storage matrix is full if( p->curIdx == p->wndEleCnt ) return rc; // get the pointer to this data source reg recd assert( regId < p->regArrayN); cmStatsProcRecd* r = p->regArrayV + regId; // the dimensionality of the incoming data must be <= the registered dimensionality assert( r->cnt <= vCnt ); unsigned dimIdx = r->idx; bool updateFl = cmIsFlag(p->flags,kUpdateOnExecStatProcFl); double* sbp = p->sumV + dimIdx; // sum base ptr // mbp point to a segment (mbp[vCnt]) in column p->curIdx double* mbp = p->m + (p->curIdx * p->dimCnt) + dimIdx; // mem col base ptr const double* mep = p->m + p->dimCnt * p->wndEleCnt; // decr the current col segment from the sum if( updateFl ) cmVOD_SubVV( sbp, vCnt, mbp ); assert( p->m <= mbp && mbp < mep && p->m <= mbp+vCnt && mbp+vCnt <= mep ); // copy in the incoming values to mem col segment cmVOD_Copy( mbp, vCnt, v ); if( updateFl ) { // incr the sum from the incoming value cmVOD_AddVV( sbp, vCnt, mbp ); // use the new sum to compute new mean values cmVOD_DivVVS( p->meanV + dimIdx, vCnt, sbp, p->curCnt ); // update the variance - cmross each row unsigned di; for(di=dimIdx; divarV[di] = cmVOD_VarianceN( p->m + dimIdx, p->curCnt, p->dimCnt, p->meanV + dimIdx ); } ++p->execCnt; return cmOkRC; } cmRC_t cmStatsProcExecF( cmStatsProc* p, unsigned regId, const float v[], unsigned vCnt ) { double dv[ vCnt ]; cmVOD_CopyF(dv,vCnt,v); cmStatsProcExecD(p,regId,dv,vCnt); return cmOkRC; } cmRC_t cmStatsProcCalc(cmStatsProc* p ) { unsigned colCnt = cmMin(p->curCnt,p->wndEleCnt); unsigned i = 0; cmVOD_Fill(p->sumV,p->dimCnt,0); // sum the ith col of p->m[] into p->sumV[i] for(; isumV, p->dimCnt, p->m + (i * p->dimCnt) ); if( p->mfp != NULL ) cmMtxFileDoubleExec( p->mfp, p->sumV, p->dimCnt, 1 ); } // calc the mean of each row cmVOD_DivVVS( p->meanV, p->dimCnt, p->sumV, colCnt ); // calc the variance cmross each row for(i=0; idimCnt; ++i) p->varV[i] = cmVOD_VarianceN(p->m + i, colCnt, p->dimCnt, p->meanV + i ); return cmOkRC; } cmRC_t cmStatsProcAdvance( cmStatsProc* p ) { ++p->curIdx; if( p->curIdx > p->wndEleCnt ) p->curIdx = 0; p->curCnt = cmMin(p->curCnt+1,p->wndEleCnt); return cmOkRC; } void cmStatsProcTest( cmVReportFuncPtr_t vReportFunc ) { enum { wndEleCnt = 7, dDimCnt = 3, fDimCnt = 2, dimCnt = dDimCnt + fDimCnt, kTypeId0 = 0, kTypeId1 = 1 }; unsigned flags = 0; unsigned i; double dd[ dDimCnt * wndEleCnt ] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; float fd[ 14 ] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; cmCtx c; cmCtxInit(&c, vReportFunc, vReportFunc, NULL ); cmStatsProc* p = cmStatsProcAlloc( &c, NULL, wndEleCnt, flags ); unsigned regId0 = cmStatsProcReg( p, kTypeId0, dDimCnt ); unsigned regId1 = cmStatsProcReg( p, kTypeId1, fDimCnt ); for(i=0; idimCnt, p->meanV ); cmVOD_PrintE( vReportFunc, 1, p->dimCnt, p->varV ); cmStatsProcFree(&p); } */ //------------------------------------------------------------------------------------------------------------ cmBeatHist* cmBeatHistAlloc( cmCtx* c, cmBeatHist* ap, unsigned frmCnt ) { cmBeatHist* p = cmObjAlloc(cmBeatHist,c,ap); p->fft = cmFftAllocRR(c,NULL,NULL,0,kToPolarFftFl); p->ifft = cmIFftAllocRR(c,NULL,0); if( frmCnt > 0 ) if( cmBeatHistInit(p,frmCnt) != cmOkRC ) cmBeatHistFree(&p); return p; } cmRC_t cmBeatHistFree( cmBeatHist** pp ) { cmRC_t rc = cmOkRC; cmBeatHist* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmBeatHistFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->m); cmMemPtrFree(&p->H); cmMemPtrFree(&p->df); cmMemPtrFree(&p->fdf); cmMemPtrFree(&p->histV); cmFftFreeRR(&p->fft); cmIFftFreeRR(&p->ifft); cmObjFree(&p); return rc; } void _cmBeatHistInitH( cmReal_t* H, unsigned hrn, unsigned hcn, unsigned ri, unsigned c0, unsigned c1 ) { unsigned ci; for(ci=c0; ci<=c1; ++ci) H[ (ci*hrn) + ri ] = 1; } cmRC_t cmBeatHistInit( cmBeatHist* p, unsigned frmCnt ) { cmRC_t rc; unsigned i,j,k; enum { kLagFact = 4, kHistBinCnt=15, kHColCnt=128 }; if((rc = cmBeatHistFinal(p)) != cmOkRC ) return rc; p->frmCnt = frmCnt; p->maxLagCnt = (unsigned)floor(p->frmCnt / kLagFact); p->histBinCnt= kHistBinCnt; p->hColCnt = kHColCnt; p->dfi = 0; unsigned cfbMemN = p->frmCnt * p->maxLagCnt; unsigned hMemN = p->histBinCnt * kHColCnt; //cmArrayResizeVZ(p->obj.ctx,&p->cfbMem, cmReal_t, &p->m, cfbMemN, &p->H, hMemN, NULL); p->m = cmMemResizeZ( cmReal_t, p->m, cfbMemN ); p->H = cmMemResizeZ( cmReal_t, p->H, hMemN ); //p->df = cmArrayResizeZ(c,&p->dfMem, 2*p->frmCnt + kHistBinCnt, cmReal_t); //p->fdf = p->df + p->frmCnt; //p->histV = p->fdf + p->frmCnt; //cmArrayResizeVZ(p->obj.ctx, &p->dfMem, cmReal_t, &p->df, p->frmCnt, &p->fdf, p->frmCnt, &p->histV, kHistBinCnt, NULL ); p->df = cmMemResizeZ( cmReal_t, p->df, p->frmCnt ); p->fdf = cmMemResizeZ( cmReal_t, p->fdf, p->frmCnt ); p->histV = cmMemResizeZ( cmReal_t, p->histV, kHistBinCnt ); cmFftInitRR( p->fft,NULL,cmNextPowerOfTwo(2*frmCnt),kToPolarFftFl); cmIFftInitRR(p->ifft,p->fft->binCnt); // initialize H _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 0, 103, 127 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 1, 86, 102 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 2, 73, 85 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 3, 64, 72 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 4, 57, 63 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 5, 51, 56 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 6, 46, 50 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 7, 43, 45 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 8, 39, 42 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 9, 36, 38 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 10,32, 35 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 11,28, 31 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 12,25, 27 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 13,21, 24 ); _cmBeatHistInitH( p->H, p->histBinCnt, p->hColCnt, 14,11, 20 ); // for each column for(i=0; imaxLagCnt; ++i) { // for each lag group for(j=0; jfrmCnt) + (i*j) + i + k; if( idx < cfbMemN ) p->m[ idx ] = 1.0/(2*j+1); } } } double g[ p->maxLagCnt ]; double g_max = 0; double b = 43; b = b*b; for(i=0; imaxLagCnt; ++i) { double n = i+1; g[i] = n/b * exp(-(n*n) / (2*b)); if( g[i] > g_max ) g_max = g[i]; } // normalize g[] cmVOD_DivVS( g, p->maxLagCnt, g_max ); // for each column of p->m[] for(i=0; imaxLagCnt; ++i) { double gg = g[i]; k = i*p->frmCnt; for(j=0; jfrmCnt; ++j) p->m[ k + j ] *= gg; } //p->mfp = cmCtxAllocDebugFile(p->obj.ctx,"beatHist"); return cmOkRC; } cmRC_t cmBeatHistFinal( cmBeatHist* p ) { //if( p != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); return cmOkRC; } cmRC_t cmBeatHistExec( cmBeatHist* p, cmSample_t df ) { if( p->dfi < p->frmCnt ) p->df[p->dfi++] = df; return cmOkRC; } cmRC_t cmBeatHistCalc( cmBeatHist* p ) { unsigned i; // df -= mean(df) cmVOR_SubVS(p->df,p->frmCnt,cmVOR_Mean(p->df,p->frmCnt)); //cmPlotLineR( "dfm", NULL, p->df, NULL, p->frmCnt, NULL, kSolidPlotLineId ); // take alpha norm of df double alpha = 9; cmVOR_DivVS(p->df,p->frmCnt, cmVOR_AlphaNorm(p->df,p->frmCnt,alpha)); //cmPlotLineS( "dfd", NULL, p->df, NULL, p->frmCnt, NULL, kSolidPlotLineId ); // low pass forward/backward filter df[] into fdf[] cmReal_t b[] = {0.1600, 0.3200, 0.1600}; unsigned bn = sizeof(b)/sizeof(b[0]); cmReal_t a[] = {1.0000, -0.5949, 0.2348}; unsigned an = sizeof(a)/sizeof(a[0]); cmFilterFilterR(p->obj.ctx,b,bn,a,an,p->df,p->frmCnt,p->fdf,p->frmCnt); //cmPlotLineS( "fdf", NULL, p->fdf, NULL, p->frmCnt, NULL, kSolidPlotLineId ); // median filter to low-passed filtered fdf[] into df[] cmVOR_FnThresh(p->fdf,p->frmCnt,16,p->df,1,NULL); // subtract med filtered signal from the low pa1ssed signal. // fdf[] -= df[]; cmVOR_SubVV(p->fdf,p->frmCnt,p->df); // half-wave rectify fdf[] = set all negative values in fdf[] to zero. cmVOR_HalfWaveRectify(p->fdf,p->frmCnt,p->fdf); //cmPlotLineS( "meddf", NULL, p->fdf, NULL, p->frmCnt, NULL, kSolidPlotLineId ); // take FT of fdf[] cmFftExecRR(p->fft,p->fdf,p->frmCnt); // square FT magn. cmVOR_PowVS(p->fft->magV,p->fft->binCnt,2); //cmPlotLineS( "mag", NULL, p->fft->magV, NULL, p->fft->binCnt, NULL, kSolidPlotLineId ); // take the IFFT of the squared magnitude vector. cmVOR_Fill(p->fft->phsV,p->fft->binCnt,0); cmIFftExecRectRR(p->ifft,p->fft->magV,p->fft->phsV); // Matlab automatically provides this scaling as part of the IFFT. cmVOR_DivVS(p->ifft->outV,p->ifft->outN,p->ifft->outN); // remove bias for short periods from CMF for(i=0; ifrmCnt; ++i) p->ifft->outV[i] /= (p->frmCnt - i); //cmPlotLineS( "cm", NULL, p->ifft->outV, NULL, p->frmCnt, NULL, kSolidPlotLineId ); // apply comb filter to the CMF and store result in df[maxLagCnt] cmVOR_MultVMtV(p->df,p->maxLagCnt,p->m,p->frmCnt,p->ifft->outV); //acPlotLineS( "cfb", NULL, p->df, NULL, p->maxLagCnt, NULL, kSolidPlotLineId ); //acVOR_Print(p->obj.err.rpt,1,p->maxLagCnt,p->df); assert( p->maxLagCnt == p->hColCnt ); cmVOR_MultVMV(p->histV,p->histBinCnt,p->H,p->hColCnt,p->df); cmReal_t bins[] = { 25, 17, 13, 9, 7, 6, 5, 3, 4, 3, 4, 4, 3, 4, 10}; cmVOR_DivVV( p->histV, p->histBinCnt, bins ); //cmPlotLineS( "cfb", NULL, p->histV, NULL, p->histBinCnt, NULL, kSolidPlotLineId ); if( p->mfp != NULL ) cmMtxFileRealExec( p->mfp, p->histV, p->histBinCnt ); return cmOkRC; } //------------------------------------------------------------------------------------------------------------ cmGmm_t* cmGmmAlloc( cmCtx* c, cmGmm_t* ap, unsigned K, unsigned D, const cmReal_t* gM, const cmReal_t* uM, const cmReal_t* sMM, unsigned uflags ) { cmGmm_t* p = cmObjAlloc( cmGmm_t, c, ap ); if( K > 0 && D > 0 ) if( cmGmmInit(p,K,D,gM,uM,sMM,uflags) != cmOkRC ) cmGmmFree(&p); return p; } cmRC_t cmGmmFree( cmGmm_t** pp ) { cmRC_t rc = cmOkRC; cmGmm_t* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmGmmFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->gV); cmMemPtrFree(&p->uM); cmMemPtrFree(&p->sMM); cmMemPtrFree(&p->isMM); cmMemPtrFree(&p->uMM); cmMemPtrFree(&p->logDetV); cmMemPtrFree(&p->t); cmObjFree(pp); return rc; } cmRC_t _cmGmmUpdateCovar( cmGmm_t* p, const cmReal_t* sMM ) { unsigned i; if( sMM == NULL ) return cmOkRC; unsigned De2 = p->D*p->D; unsigned KDe2 = p->K*De2; cmVOR_Copy(p->sMM, KDe2, sMM); cmVOR_Copy(p->isMM,KDe2, sMM); cmVOR_Copy(p->uMM, KDe2, sMM); //if( cmIsFlag(p->uflags,cmGmmCovarNoProcFl) ) // return cmOkRC; // for each component for(i=0; iK; ++i) { cmReal_t* is = p->isMM + i*De2; cmReal_t* u = p->uMM + i*De2; cmReal_t* r; // if the covariance matrix is diagnal if( cmIsFlag(p->uflags,cmGmmDiagFl)) { p->logDetV[i] = cmVOR_LogDetDiagM(is,p->D); // calc the det. of diag. covar. mtx r = cmVOR_InvDiagM(is,p->D); // calc the inverse in place } else { p->logDetV[i] = cmVOR_LogDetM(is,p->D); // calc the det. of covar mtx r = cmVOR_InvM(is,p->D); // calc the inverse in place } if( fabs(p->logDetV[i]) < 1e-20 ) { cmCtxPrint(p->obj.ctx,"%i\n",i); cmVOR_PrintLE("DANGER SM:\n",p->obj.err.rpt,p->D,p->D,p->sMM); } if( cmVOR_CholZ(u,p->D) == NULL ) { return cmCtxRtCondition(&p->obj, cmSingularMtxRC, "A singular covariance matrix (Cholesky factorization failed.) was encountered in _cmGmmUpdateCovar()."); } if( p->logDetV[i] == 0 ) { cmGmmPrint(p,true); return cmCtxRtCondition(&p->obj, cmSingularMtxRC, "A singular covariance matrix (det==0) was encountered in _cmGmmUpdateCovar()."); } if( r == NULL ) { //cmCtxPrint(c,"%i\n",i); //cmVOR_PrintLE("DANGER SM:\n",p->obj.err.rpt,p->D,p->D,p->sMM); return cmCtxRtCondition(&p->obj, cmSingularMtxRC, "A singular covariance matrix (inversion failed) was encountered in _cmGmmUpdateCovar()."); } } return cmOkRC; } cmRC_t cmGmmInit( cmGmm_t* p, unsigned K, unsigned D, const cmReal_t* gV, const cmReal_t* uM, const cmReal_t* sMM, unsigned uflags ) { cmRC_t rc; if((rc = cmGmmFinal(p)) != cmOkRC ) return rc; // gM[K] uM[DK] sMM[DDK] isMM[DDK]+ uMM[DDK] logDetV[K] t[DD] fact[K] /* unsigned n = K + (D*K) + (D*D*K) + (D*D*K) + (D*D*K) + K + (D*D) + K; p->gV = cmArrayResizeZ(c,&p->memA, n, cmReal_t ); p->uM = p->gV + K; p->sMM = p->uM + (D*K); p->isMM = p->sMM + (D*D*K); p->uMM = p->isMM + (D*D*K); p->logDetV = p->uMM + (D*D*K); p->t = p->logDetV + K; */ //cmArrayResizeVZ(c, &p->memA, cmReal_t, &p->gV,K, &p->uM,D*K, &p->sMM,D*D*K, //&p->isMM,D*D*K, &p->uMM,D*D*K, &p->logDetV,K, &p->t,D*D, NULL ); p->gV = cmMemResizeZ( cmReal_t, p->gV, K ); p->uM = cmMemResizeZ( cmReal_t, p->uM, D*K); p->sMM = cmMemResizeZ( cmReal_t, p->sMM, D*D*K); p->isMM = cmMemResizeZ( cmReal_t, p->isMM, D*D*K); p->uMM = cmMemResizeZ( cmReal_t, p->uMM, D*D*K); p->logDetV = cmMemResizeZ( cmReal_t, p->logDetV, K); p->t = cmMemResizeZ( cmReal_t, p->t, D*D ); p->K = K; p->D = D; p->uflags = uflags; if( gV != NULL ) cmVOR_Copy(p->gV,K,gV); if( uM != NULL ) cmVOR_Copy(p->uM,D*K,uM); return _cmGmmUpdateCovar(p,sMM ); } cmRC_t cmGmmFinal( cmGmm_t* p ) { return cmOkRC; } typedef struct { cmGmm_t* p; const cmReal_t* xM; unsigned colCnt; } _cmGmmRdFuncData_t; const cmReal_t* _cmGmmReadFunc( void* userPtr, unsigned colIdx ) { assert(colIdx < ((const _cmGmmRdFuncData_t*)userPtr)->colCnt); return ((const _cmGmmRdFuncData_t*)userPtr)->xM + (colIdx * ((const _cmGmmRdFuncData_t*)userPtr)->p->D); } // xM[D,xN] // yV[xN] // yM[xN,K] cmRC_t cmGmmEval( cmGmm_t* p, const cmReal_t* xM, unsigned xN, cmReal_t* yV, cmReal_t* yM ) { _cmGmmRdFuncData_t r; r.colCnt = xN; r.p = p; r.xM = xM; return cmGmmEval2(p,_cmGmmReadFunc,&r,xN,yV,yM); } cmRC_t cmGmmEval2( cmGmm_t* p, cmGmmReadFunc_t readFunc, void* userFuncPtr, unsigned xN, cmReal_t* yV, cmReal_t* yM) { cmReal_t tV[xN]; unsigned k; //cmVOR_PrintL("cV: ",p->obj.err.rpt, 1, p->K, p->gV); //cmVOR_PrintL("uM:\n",p->obj.err.rpt, p->D, p->K, p->uM ); // cmVOR_Fill(yV,xN,0); // for each component PDF for(k=0; kK; k++) { const cmReal_t* meanV = p->uM + (k*p->D); const cmReal_t* isM = p->isMM + (k*p->D*p->D); cmReal_t* pV; if( yM == NULL ) pV = tV; else pV = yM + (k*xN); // evaluate the kth component PDF with xM[1:T] //cmVOR_MultVarGaussPDF2( pV, xM, meanV, isM, p->logDetV[k], p->D, xN, cmIsFlag(p->uflags,cmGmmDiagFl) ); cmVOR_MultVarGaussPDF3( pV, readFunc, userFuncPtr, meanV, isM, p->logDetV[k], p->D, xN, cmIsFlag(p->uflags,cmGmmDiagFl) ); // apply the kth component weight cmVOR_MultVS( pV, xN, p->gV[k] ); // sum the result into the output vector cmVOR_AddVV( yV, xN, pV ); } return cmOkRC; } // Evaluate each component for a single data point // xV[D] - observed data point // yV[K] - output contains the evaluation for each component cmRC_t cmGmmEval3( cmGmm_t* p, const cmReal_t* xV, cmReal_t* yV ) { unsigned k; for(k=0; kK; ++k) { const cmReal_t* meanV = p->uM + (k*p->D); const cmReal_t* isM = p->isMM + (k*p->D*p->D); // evaluate the kth component PDF with xM[1:T] cmVOR_MultVarGaussPDF2( yV + k, xV, meanV, isM, p->logDetV[k], p->D, 1, cmIsFlag(p->uflags,cmGmmDiagFl) ); // apply the kth component weight yV[k] *= p->gV[k]; } return cmOkRC; } cmReal_t _cmGmmKmeansDistFunc( void* userPtr, const cmReal_t* v0, const cmReal_t* v1, unsigned vn ) { return cmVOR_EuclidDistance(v0,v1,vn); } cmRC_t cmGmmRandomize2( cmGmm_t* p, cmGmmReadFunc_t readFunc, void* funcUserPtr, unsigned xN, const cmReal_t* uM, const bool* roFlV ) { unsigned k; unsigned iV[ p->K ]; if( uM == NULL ) roFlV = NULL; // randomize the mixture coefficients cmVOR_Random( p->gV, p->K, 0.0, 1.0 ); cmVOR_NormalizeProbability(p->gV,p->K); // fill iV with random integers between 0 and xN-1 cmVOU_Random( iV, p->K, xN-1 ); // for each component for(k=0; kK; ++k) { cmReal_t r[ p->D ]; // if this component's mean is not read-only if( roFlV==NULL || roFlV[k]==false ) { const cmReal_t* xV = NULL; if( uM == NULL ) xV = readFunc( funcUserPtr, iV[k] ); // read a random frame index else xV = uM + (k*p->D); // select a user supplied mean vector assert( xV != NULL ); // set the random feature vector as this components mean value cmVOR_Copy(p->uM+(k*p->D),p->D,xV); } cmReal_t* sM = p->sMM+(k*p->D*p->D); // create a random covariance mtx if( cmIsFlag(p->uflags,cmGmmDiagFl) ) { // create a random diag. covar mtx cmVOR_Random(r,p->D,0.0,1.0); cmVOR_Diag(sM,p->D,r); } else { // create a random symetric positive definite matrix cmVOR_RandSymPosDef(sM,p->D,p->t); } } unsigned* classIdxV = cmMemAllocZ(unsigned, xN ); // if some components have read-only mean's if( uM != NULL && roFlV != NULL ) { assert( xN >= p->K ); for(k=0; kK; ++k) classIdxV[k] = roFlV[k]; } // use kmeans clustering to move the means closer to their center values if( cmIsFlag( p->uflags, cmGmmSkipKmeansFl) == false ) cmVOR_Kmeans2( classIdxV, p->uM, p->K, readFunc, p->D, xN, funcUserPtr, _cmGmmKmeansDistFunc, NULL, -1, 0 ); cmMemPtrFree(&classIdxV); return _cmGmmUpdateCovar(p,p->sMM); } cmRC_t cmGmmRandomize( cmGmm_t* p, const cmReal_t* xM, unsigned xN ) { _cmGmmRdFuncData_t r; r.colCnt = xN; r.p = p; r.xM = xM; return cmGmmRandomize2(p,_cmGmmReadFunc,&r,xN,NULL,NULL); } // xM[D,xN] cmRC_t cmGmmTrain( cmGmm_t* p, const cmReal_t* xM, unsigned xN, unsigned* iterCntPtr ) { unsigned i,k; cmRC_t rc; if((rc = cmGmmRandomize(p,xM,xN)) != cmOkRC ) return rc; //cmGmmPrint(c,p); // wM[xN,K] cmReal_t wM[ xN * p->K ]; // wM[N,K] soft assignment mtx unsigned wV[ xN ]; // wV[N] hard assignment vector unsigned stopCnt = 0; unsigned curStopCnt = 0; if( iterCntPtr != NULL ) { stopCnt = *iterCntPtr; *iterCntPtr = 0; } else { // BUG BUG BUG // stopCnt is used uninitialized when iterCntPtr == NULL assert( 0 ); } while(1) { //cmVOR_NormalizeProbability(p->gV,p->K); cmCtxPrint(p->obj.ctx,"iter:%i --------------------------------------------\n",*iterCntPtr ); cmVOR_PrintL("uM:\n", p->obj.err.rpt, p->D, p->K, p->uM ); cmVOR_PrintL("gV:\n", p->obj.err.rpt, 1, p->K, p->gV ); //cmGmmPrint(c,p); for(k=0; kK; ++k) { cmReal_t* wp = wM + (k*xN); // calc the prob that each data point in xM[] was generated by the kth gaussian // and store as a column vector in wM[:,k] cmVOR_MultVarGaussPDF2( wp, xM, p->uM + (k*p->D), p->isMM + (k*p->D*p->D), p->logDetV[k], p->D, xN, cmIsFlag(p->uflags,cmGmmDiagFl) ); // scale the prob by the gain coeff for gaussian k cmVOR_MultVS( wp, xN, p->gV[k]); } //cmVOR_PrintL("wM:\n",p->obj.err.rpt,xN,p->K,wM); bool doneFl = true; for(i=0; iK, xN); // select the cluster to which the ith data point is most likely to belong unsigned mi = cmVOR_MaxIndex(wM + i, p->K, xN); // if the ith data point changed clusters if( mi != wV[i] ) { doneFl = false; wV[i] = mi; } } curStopCnt = doneFl ? curStopCnt+1 : 0; // if no data points changed owners then the clustering is complete if( curStopCnt == stopCnt ) { //cmVOU_PrintL("wV: ",p->obj.err.rpt,xN,1,wV); break; } // for each cluster for(k=0; kK; ++k) { cmReal_t* uV = p->uM + (k*p->D); // meanV[k] cmReal_t* sM = p->sMM + (k*p->D*p->D); // covarM[k] cmReal_t sw = cmVOR_Sum(wM + (k*xN), xN ); // update the kth weight p->gV[k] = sw / xN; // form a sum of all data points weighted by their soft assignment to cluster k cmReal_t sumV[p->D]; cmVOR_MultVMV( sumV, p->D, xM, xN, wM + k*xN ); // update the mean[k] cmVOR_DivVVS(uV, p->D, sumV, sw ); // update the covar[k] // sM += ( W(i,k) .* ((X(:,i) - uV) * (X(:,i) - uV)')); cmVOR_Fill(sM,p->D*p->D,0); for(i=0; iD ]; cmVOR_SubVVV( duV, p->D, xM + (i*p->D), uV ); // duV[] = xM[:,i] - uV[]; cmVOR_MultMMM( p->t, p->D, p->D, duV, duV, 1 ); // t[,] = duV[] * duV[]' cmVOR_MultVS( p->t, p->D*p->D, wM[ k * xN + i ]); // t[,] *= wM[i,k] cmVOR_AddVV( sM, p->D*p->D, p->t ); // sM[,] += t[,]; } cmVOR_DivVS( sM, p->D*p->D, sw ); // sM[,] ./ sw; } // update the inverted covar mtx and covar det. if((rc = _cmGmmUpdateCovar(p,p->sMM )) != cmOkRC ) return rc; if( iterCntPtr != NULL ) *iterCntPtr += 1; } return cmOkRC; } // xM[D,xN] cmRC_t cmGmmTrain2( cmGmm_t* p, cmGmmReadFunc_t readFunc, void* userFuncPtr, unsigned xN, unsigned* iterCntPtr, const cmReal_t* uM, const bool* roFlV, int maxIterCnt ) { unsigned i,j,k; cmRC_t rc; // if uM[] is not set then ignore roFlV[] if( uM == NULL ) roFlV=NULL; if((rc = cmGmmRandomize2(p,readFunc,userFuncPtr,xN,uM,roFlV)) != cmOkRC ) return rc; //cmGmmPrint(c,p); // wM[xN,K] soft assignment mtx cmReal_t* wM = cmMemAlloc(cmReal_t, xN * p->K ); // wV[N] hard assignment vector unsigned* wV = cmMemAlloc(unsigned, xN ); unsigned stopCnt = 0; unsigned curStopCnt = 0; if( iterCntPtr != NULL ) { stopCnt = *iterCntPtr; *iterCntPtr = 0; } else { // BUG BUG BUG // stopCnt is used uninitialized when iterCntPtr == NULL assert( 0 ); } while(1) { //cmCtxPrint(p->obj.ctx,"iter:%i --------------------------------------------\n",*iterCntPtr ); //cmVOR_PrintL("uM:\n", p->obj.err.rpt, p->D, p->K, p->uM ); cmVOR_PrintL("gV:\n", p->obj.err.rpt, 1, p->K, p->gV ); //cmGmmPrint(c,p); for(k=0; kK; ++k) { cmReal_t* wp = wM + (k*xN); // calc the prob that each data point in xM[] was generated by the kth gaussian // and store as a column vector in wM[:,k] cmVOR_MultVarGaussPDF3( wp, readFunc, userFuncPtr, p->uM + (k*p->D), p->isMM + (k*p->D*p->D), p->logDetV[k], p->D, xN, cmIsFlag(p->uflags,cmGmmDiagFl) ); // scale the prob by the gain coeff for gaussian k cmVOR_MultVS( wp, xN, p->gV[k]); } //cmVOR_PrintL("wM:\n",p->obj.err.rpt,xN,p->K,wM); bool doneFl = true; unsigned changeCnt = 0; for(i=0; iK, xN); // select the cluster to which the ith data point is most likely to belong unsigned mi = cmVOR_MaxIndex(wM + i, p->K, xN); // if the ith data point changed clusters if( mi != wV[i] ) { ++changeCnt; doneFl = false; wV[i] = mi; } } curStopCnt = doneFl ? curStopCnt+1 : 0; printf("%i stopCnt:%i changeCnt:%i\n",*iterCntPtr,curStopCnt,changeCnt); // if no data points changed owners then the clustering is complete if( curStopCnt == stopCnt ) { //cmVOU_PrintL("wV: ",p->obj.err.rpt,xN,1,wV); break; } // if a maxIterCnt was given and the cur iter cnt exceeds the max iter cnt then stop if( maxIterCnt>=1 && *iterCntPtr >= maxIterCnt ) break; // form a sum of all data points weighted by their soft assignment to cluster k // NOTE: cmGmmTrain() performs this step more efficiently because it use // an LAPACK matrix multiply. cmReal_t sumM[ p->D * p->K ]; cmVOR_Zero(sumM,p->D*p->K); for(i=0; iK; ++k) { cmReal_t weight = wM[ i + (k*xN)]; for(j=0; jD; ++j) sumM[ j + (k*p->D) ] += xV[j] * weight; } } // for each cluster that is not marked as read-only for(k=0; kK; ++k) { cmReal_t* uV = p->uM + (k*p->D); // meanV[k] cmReal_t* sM = p->sMM + (k*p->D*p->D); // covarM[k] cmReal_t sw = cmVOR_Sum(wM + (k*xN), xN ); // update the kth weight p->gV[k] = sw / xN; // if this component's mean is not read-only if( (roFlV==NULL || roFlV[k]==false) && sw != 0) { // get vector of all data points weighted by their soft assignment to cluster k cmReal_t* sumV = sumM + (k*p->D); // sumV[p->D]; // update the mean[k] cmVOR_DivVVS(uV, p->D, sumV, sw ); } // update the covar[k] // sM += ( W(i,k) .* ((X(:,i) - uV) * (X(:,i) - uV)')); cmVOR_Fill(sM,p->D*p->D,0); for(i=0; iD ]; const cmReal_t* xV = readFunc( userFuncPtr, i ); assert( xV != NULL ); cmVOR_SubVVV( duV, p->D, xV, uV ); // duV[] = xM[:,i] - uV[]; cmVOR_MultMMM( p->t, p->D, p->D, duV, duV, 1 ); // t[,] = duV[] * duV[]' cmVOR_MultVS( p->t, p->D*p->D, wM[ k * xN + i ]); // t[,] *= wM[i,k] cmVOR_AddVV( sM, p->D*p->D, p->t ); // sM[,] += t[,]; } if( sw != 0 ) cmVOR_DivVS( sM, p->D*p->D, sw ); // sM[,] ./ sw; } // update the inverted covar mtx and covar det. if((rc = _cmGmmUpdateCovar(p,p->sMM )) != cmOkRC ) goto errLabel; if( iterCntPtr != NULL ) *iterCntPtr += 1; } cmMemPtrFree(&wM); cmMemPtrFree(&wV); errLabel: return cmOkRC; } cmRC_t cmGmmTrain3( cmGmm_t* p, const cmReal_t* xM, unsigned xN, unsigned* iterCntPtr ) { _cmGmmRdFuncData_t r; r.colCnt = xN; r.p = p; r.xM = xM; return cmGmmTrain2(p,_cmGmmReadFunc,&r,xN,iterCntPtr,NULL,NULL,-1); } cmRC_t cmGmmGenerate( cmGmm_t* p, cmReal_t* yM, unsigned yN ) { unsigned i=0; unsigned kV[yN]; // use weighted random selection to choose the component for each output value cmVOR_WeightedRandInt(kV,yN, p->gV, p->K ); // cmVOU_Print(p->obj.err.rpt,1,yN,kV); for(i=0; iuM + (kV[i] * p->D); unsigned idx = kV[i] * p->D * p->D; //cmVOR_PrintL("sM\n",p->obj.err.rpt,p->D,p->D,sM); if( cmIsFlag(p->uflags,cmGmmDiagFl) ) { const cmReal_t* sM = p->sMM + idx; cmVOR_RandomGaussDiagM( yM + (i*p->D), p->D, 1, uV, sM ); } else { const cmReal_t* uM = p->uMM + idx; cmVOR_RandomGaussNonDiagM2(yM + (i*p->D), p->D, 1, uV, uM ); } } return cmOkRC; } void cmGmmPrint( cmGmm_t* p, bool fl ) { unsigned k; //cmCtx* c = p->obj.ctx; cmVOR_PrintL("gV: ", p->obj.err.rpt, 1, p->K, p->gV ); cmVOR_PrintL("mM:\n", p->obj.err.rpt, p->D, p->K, p->uM ); for(k=0; kK; ++k) cmVOR_PrintL("sM:\n", p->obj.err.rpt, p->D, p->D, p->sMM + (k*p->D*p->D)); if( fl ) { for(k=0; kK; ++k) cmVOR_PrintL("isM:\n", p->obj.err.rpt, p->D, p->D, p->isMM + (k*p->D*p->D)); for(k=0; kK; ++k) cmVOR_PrintL("uM:\n", p->obj.err.rpt, p->D, p->D, p->uMM + (k*p->D*p->D)); cmVOR_PrintL("logDetV:\n", p->obj.err.rpt, 1, p->K, p->logDetV); } } void cmGmmTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ) { cmCtx* c = cmCtxAlloc(NULL,rpt,lhH,stH); unsigned K = 2; unsigned D = 2; cmReal_t gV[ 2 ] = { .5, .5 }; cmReal_t uM[ 4 ] = { .3, .3, .8, .8 }; cmReal_t sMM[ 8 ] = { .1, 0, 0, .1, .1, 0, 0, .1 }; unsigned flags = cmGmmDiagFl ; unsigned M = 100; cmReal_t xM[ D*M ]; cmReal_t yV[ M ]; unsigned i,j; cmPlotSetup("MultDimGauss Test",1,1); cmGmm_t* p = cmGmmAlloc(c, NULL, K, D, gV, uM, sMM, flags ); if(0) { cmGmmPrint(p,true); for(i=0; i<10; i++) for(j=0; j<20; j+=2) { xM[(i*20)+j] = .1 * i;; xM[(i*20)+j + 1] = .1 * (j/2);; } // octave equivalent // x0= .1 * ones(1,10); // x = [ 0*x0 1*x0 2*x0 3*x0 4*x0 5*x0 6*x0 7*x0 8*x0 9*x0]; // x = [x; repmat([0:.1:1],1,10)]; // y = mvnpdf(x',[.3 .3],[.1 0; 0 .1]); plot(y); cmGmmEval(p,xM,M,yV,NULL); //cmVOR_PrintL( "xM\n", rpt, D, M, xM ); cmVOR_PrintL( "yV\n", rpt, 10, 10, yV ); //printf("y:%f\n",yV[0]); cmPlotLineD( NULL, NULL, yV, NULL, M, NULL, kSolidPlotLineId ); } if(0) { cmReal_t yM[ D*M ]; cmReal_t yMt[ M*D ]; cmReal_t uMt[ p->K*D]; unsigned iterCnt = 10; //srand( time(NULL) ); cmGmmGenerate( p, yM, M ); p->uflags = 0; // turn off diagonal condition if( cmGmmTrain3( p, yM, M, &iterCnt ) != cmOkRC ) return; cmCtxPrint(c,"iterCnt:%i\n",iterCnt); cmGmmPrint( p, true ); cmVOR_Transpose(yMt, yM, D, M ); //cmVOR_PrintL("yMt\n",vReportFunc,M,D,yMt); cmPlotLineD(NULL, yMt, yMt+M, NULL, M, "blue", kAsteriskPlotPtId ); cmVOR_Transpose( uMt, p->uM, D, p->K); cmVOR_PrintL("uMt:\n", p->obj.err.rpt, p->K, p->D, uMt ); cmPlotLineD(NULL, uMt, uMt+p->K, NULL, p->D, "red", kXPlotPtId ); } if(1) { cmGmmFree(&p); cmReal_t cV0[] = { .7, .3 }; cmReal_t uM0[] = { .2, .1, .1, .2 }; cmReal_t sMM0[] = { .01, 0, 0, .01, .01, 0, 0, .01 }; unsigned flags = 0; K = 2; D = 2; cmGmm_t* p = cmGmmAlloc(c,NULL, K, D, cV0, uM0, sMM0, flags ); xM[0] = 0.117228; xM[1] = 0.110079; cmGmmEval(p,xM,1,yV,NULL); cmCtxPrint(c,"y: %f\n",yV[0]); } cmPlotDraw(); cmGmmFree(&p); cmCtxFree(&c); } //------------------------------------------------------------------------------------------------------------ cmChmm_t* cmChmmAlloc( cmCtx* c, cmChmm_t* ap, unsigned stateN, unsigned mixN, unsigned dimN, const cmReal_t* iV, const cmReal_t* aM ) { cmChmm_t* p = cmObjAlloc(cmChmm_t,c,ap); if( stateN >0 && dimN > 0 ) if( cmChmmInit(p,stateN,mixN,dimN,iV,aM) != cmOkRC ) cmChmmFree(&p); return p; } cmRC_t cmChmmFree( cmChmm_t** pp ) { cmRC_t rc = cmOkRC; cmChmm_t* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmChmmFinal(p)) != cmOkRC ) return rc; cmMemPtrFree(&p->iV); cmMemPtrFree(&p->aM); cmMemPtrFree(&p->bV); cmMemPtrFree(&p->bM); cmObjFree(pp); return cmOkRC; } cmRC_t cmChmmInit( cmChmm_t* p, unsigned stateN, unsigned mixN, unsigned dimN, const cmReal_t* iV, const cmReal_t* aM ) { cmRC_t rc; unsigned i; if((rc = cmChmmFinal(p)) != cmOkRC ) return rc; // iV[] aM /* unsigned n = stateN + (stateN*stateN); p->iV = cmArrayResizeZ(c, &p->memA, n, cmReal_t ); p->aM = p->iV + stateN; */ //cmArrayResizeVZ(c,&p->memA, cmReal_t, &p->iV,stateN, &p->aM, stateN*stateN, NULL ); p->iV = cmMemResizeZ( cmReal_t, p->iV, stateN ); p->aM = cmMemResizeZ( cmReal_t, p->aM, stateN * stateN ); p->bV = cmMemResizeZ( cmGmm_t*, p->bV, stateN ); p->N = stateN; p->K = mixN; p->D = dimN; if( iV != NULL ) cmVOR_Copy(p->iV,p->N,iV); if( aM != NULL ) cmVOR_Copy(p->aM,p->N*p->N,aM); for(i=0; iN; ++i) p->bV[i] = cmGmmAlloc( p->obj.ctx, NULL, p->K, p->D, NULL, NULL, NULL, 0 ); //p->mfp = cmCtxAllocDebugFile( p->obj.ctx,"chmm"); return cmOkRC; } cmRC_t cmChmmFinal( cmChmm_t* p ) { if( p != NULL ) { unsigned i; for(i=0; iN; ++i) cmGmmFree( &p->bV[i] ); cmMemPtrFree(&p->bM); //if( p->mfp != NULL ) // cmCtxFreeDebugFile(p->obj.ctx,&p->mfp); } return cmOkRC; } cmRC_t cmChmmRandomize( cmChmm_t* p, const cmReal_t* oM, unsigned T ) { cmRC_t rc; unsigned i; unsigned N = p->N; // randomize the initial state probabilities cmVOR_Random( p->iV, N, 0.0, 1.0 ); cmVOR_NormalizeProbability( p->iV, N ); // randomize the state transition matrix cmVOR_Random( p->aM, N*N, 0.0, 1.0 ); for(i=0; iaM + i, N, N ); // rows of aM must sum to 1.0 if((rc = cmGmmRandomize( p->bV[i], oM, T )) != cmOkRC) // randomize the GMM assoc'd with state i return rc; } cmMemPtrFree(&p->bM); // force bM[] to be recalculated return cmOkRC; } cmReal_t _cmChmmKmeansDist( void* userPtr, const cmReal_t* v0, const cmReal_t* v1, unsigned vn ) { return cmVOR_EuclidDistance(v0,v1,vn); } cmRC_t cmChmmSegKMeans( cmChmm_t* p, const cmReal_t* oM, unsigned T, cmReal_t threshProb, unsigned maxIterCnt, unsigned iterCnt ) { cmCtx* c = p->obj.ctx; cmRC_t rc = cmOkRC; unsigned i,j,k,t; unsigned N = p->N; unsigned K = p->K; unsigned D = p->D; //unsigned qV[T]; //cmReal_t alphaM[N*T]; //unsigned clusterIdxV[T]; //cmReal_t centroidM[D*N]; /* unsigned sz = 2*ALIGN_B(T,unsigned) + ALIGN_B(N*T,cmReal_t) + ALIGN_B(D*N,cmReal_t); cmArray mem; cmArrayAlloc(c, &mem); unsigned* qV = (unsigned*) cmArrayResize(c, &mem, sz, char); cmReal_t* alphaM = (cmReal_t*) (qV + ALIGN_T(T, unsigned)); unsigned* clusterIdxV = (unsigned*) (alphaM + ALIGN_T(N*T,cmReal_t)); cmReal_t* centroidM = (cmReal_t*) (clusterIdxV + ALIGN_T(T, unsigned)); */ unsigned* qV = cmMemAlloc( unsigned, T ); cmReal_t* alphaM = cmMemAlloc( cmReal_t, N*T); unsigned* clusterIdxV = cmMemAlloc( unsigned, T ); cmReal_t* centroidM = cmMemAlloc( cmReal_t, D*N); cmReal_t logPr = 0; bool reportFl = true; cmChmmRandomize(p,oM,T); // cluster the observations into N groups cmVOR_Kmeans( qV, centroidM, N, oM, D, T, NULL, 0, false, _cmChmmKmeansDist, NULL ); for(i=0; ibV[j]; // cluster all datapoints which were assigned to state j cmVOR_Kmeans( clusterIdxV, g->uM, K, oM, D, T, qV, j, false, _cmChmmKmeansDist, NULL ); // for each cluster for(k=0; kgV[k] = (cmReal_t)kN/jnV[j]; // the covar of the kth component is the sample covar of cluster k cmVOR_GaussCovariance(g->sMM + (k*D*D), D, oM, T, g->uM + (k*D), clusterIdxV, k ); } if((rc = _cmGmmUpdateCovar(g, g->sMM )) != cmOkRC ) goto errLabel; } if( i== 0 ) { // count transitions from i to j for(t=0; taM[ (qV[t+1]*N) + qV[t] ] += 1.0; for(j=0; jaM[ (k*N) + j ] /= jnV[j]; cmVOR_NormalizeProbabilityN(p->aM + j, N, N); cmGmmEval( p->bV[j], oM, 1, p->iV + j, NULL ); } } if((rc = cmChmmTrain(p, oM, T, iterCnt,0,0 )) != cmOkRC ) goto errLabel; // calculate the prob. that the new model generated the data cmReal_t logPr0 = cmChmmForward(p,oM,T,alphaM,NULL); cmReal_t dLogPr = logPr0 - logPr; if( reportFl ) cmCtxPrint(c,"pr:%f d:%f\n",logPr0,dLogPr); if( (dLogPr > 0) && (dLogPr < threshProb) ) break; logPr = logPr0; // fill qV[] with the state at each time t cmChmmDecode(p,oM,T,qV); } errLabel: cmMemPtrFree(&qV); cmMemPtrFree(&alphaM); cmMemPtrFree(&clusterIdxV); cmMemPtrFree(¢roidM); return rc; } cmRC_t cmChmmSetGmm( cmChmm_t* p, unsigned i, const cmReal_t* wV, const cmReal_t* uM, const cmReal_t* sMM, unsigned flags ) { assert( i < p->N); cmMemPtrFree(&p->bM); // force bM[] to be recalculated return cmGmmInit(p->bV[i],p->K,p->D,wV,uM,sMM,flags); } // Return the probability of the observation for each state. // oV[D] - multi-dim. observation data point // pV[N] - probability of this observation for each state void cmChmmObsProb( const cmChmm_t* p, const cmReal_t* oV, cmReal_t* prV ) { unsigned i; for(i=0; iN; ++i) cmGmmEval( p->bV[i], oV, 1, prV + i, NULL ); } // oM[D,T] - observation matrix // alphaM[N,T] - prob of being in each state and observtin oM(:,t) // bM[N,T] - (optional) state-observation probability matrix // logPrV[T] - (optional) record the log prob of the data given the model at each time step // Returns sum(logPrV[T]) cmReal_t cmChmmForward( const cmChmm_t* p, const cmReal_t* oM, unsigned T, cmReal_t* alphaM, cmReal_t* logPrV ) { unsigned t; cmReal_t logPr = 0; // calc the prob of starting in each state if( p->bM == NULL ) cmChmmObsProb( p, oM, alphaM ); else cmVOR_Copy( alphaM, p->N*T, p->bM ); cmVOR_MultVV( alphaM, p->N, p->iV ); cmReal_t s = cmVOR_Sum(alphaM,p->N); cmVOR_DivVS(alphaM,p->N,s); //cmVOR_PrintL("alpha:\n",p->obj.err.rpt,p->N,1,alphaM); for(t=1; tN]; cmReal_t* alphaV = alphaM + t*p->N; // calc the prob of the observation for each state if( p->bM == NULL ) cmChmmObsProb(p,oM + (t*p->D), alphaV ); // calc. the prob. of transitioning to each state at time t, from each state at t-1 cmVOR_MultVVM(tmp,p->N, alphaM + ((t-1)*p->N), p->N, p->aM ); // calc the joint prob of transitioning from each state to each state and observing O(t). cmVOR_MultVV(alphaV, p->N, tmp ); // scale the probabilities to prevent underflow s = cmVOR_Sum(alphaV,p->N); cmVOR_DivVS(alphaV,p->N,s); // track the log prob. of the model having generated the data up to time t. cmReal_t pr = log(s); if( logPrV != NULL ) logPrV[t] = pr; logPr += pr; } return logPr; } // oM[D,T] // betaM[N,T] void cmChmmBackward( const cmChmm_t* p, const cmReal_t* oM, unsigned T, cmReal_t* betaM ) { cmVOR_Fill(betaM,p->N*T,1.0); assert(T >= 2 ); int t = (int)T - 2; for(; t>=0; --t) { cmReal_t tmp[p->N]; if( p->bM == NULL ) cmChmmObsProb(p,oM+((t+1)*p->D), tmp ); else cmVOR_Copy(tmp,p->N,p->bM + ((t+1)*p->N)); cmVOR_MultVV(tmp,p->N,betaM + ((t+1)*p->N)); cmVOR_MultVMV(betaM+(t*p->N),p->N, p->aM, p->N, tmp ); cmVOR_NormalizeProbability(betaM+(t*p->N),p->N ); } } cmReal_t cmChmmCompare( const cmChmm_t* p0, const cmChmm_t* p1, unsigned T ) { assert(p0->D == p1->D); assert(p0->N == p1->N); cmReal_t oM[p0->D*T]; cmReal_t alphaM[p0->N*T]; cmChmmGenerate(p0,oM,T,NULL); cmReal_t logPr00 = cmChmmForward(p0,oM,T,alphaM,NULL); cmReal_t logPr01 = cmChmmForward(p1,oM,T,alphaM,NULL); cmChmmGenerate(p1,oM,T,NULL); cmReal_t logPr10 = cmChmmForward(p0,oM,T,alphaM,NULL); cmReal_t logPr11 = cmChmmForward(p1,oM,T,alphaM,NULL); cmReal_t d0 = (logPr01-logPr00)/T; cmReal_t d1 = (logPr10-logPr11)/T; return (d0+d1)/2; } cmRC_t cmChmmGenerate( const cmChmm_t* p, cmReal_t* oM, unsigned T, unsigned* sV ) { unsigned i,si; // use weighted random selection to choose an intitial state cmVOR_WeightedRandInt(&si, 1, p->iV, p->N ); for(i=0; ibV[si], oM + (i*p->D), 1 ); // choose the next state using the transition weights from the current state cmVOR_WeightedRandInt(&si, 1, p->aM + (si*p->N), p->N ); } return cmOkRC; } cmRC_t cmChmmDecode( cmChmm_t* p, const cmReal_t* oM, unsigned T, unsigned* yV ) { int i,j,t; unsigned N = p->N; //unsigned psiM[N*T]; //cmReal_t delta[N]; /* unsigned sz = ALIGN_B(N*T,unsigned) + ALIGN_B(N,cmReal_t); cmArray mem; cmArrayAlloc(c, &mem); unsigned* psiM = (unsigned*) cmArrayResize(c, &mem, sz, char); cmReal_t* delta = (cmReal_t*) (psiM + ALIGN_T(N*T,unsigned)); */ unsigned* psiM = cmMemAlloc( unsigned, N*T ); cmReal_t* delta= cmMemAlloc( cmReal_t, N ); // get the prob of starting in each state if( p->bM == NULL ) cmChmmObsProb( p, oM, delta ); else cmVOR_Copy( delta, N, p->bM ); cmVOR_MultVV( delta, p->N, p->iV ); cmVOR_NormalizeProbability(delta, p->N); for(t=1; taM; // calc. the most likely new state given the most likely prev state // and the transition matrix for(i=0; i mV[i] ) { mV[i] = v; psiM[ psiIdx ] = j; } } } // mV[] now holds the prob. of the max likelihood state at time t // for each possible state at t-1 // psiM[:,t] holds the index of the max likelihood state // condition the most likely new state on the observations if( p->bM == NULL ) cmChmmObsProb(p,oM + (t*p->D), delta); else cmVOR_Copy(delta, N, p->bM + (t*p->N) ); cmVOR_MultVV(delta, N, mV ); // condition it on the max. like current states cmVOR_NormalizeProbability( delta, N ); // normalize the prob. } // unwind psiM[] to form the max. likelihood state sequence yV[T-1] = cmVOR_MaxIndex(delta,N,1); for(t=T-2; t>=0; --t) yV[t] = psiM[ ((t+1)*N) + yV[t+1] ]; cmMemPtrFree(&psiM); cmMemPtrFree(&delta); return cmOkRC; } cmRC_t cmChmmTrain( cmChmm_t* p, const cmReal_t* oM, unsigned T, unsigned iterCnt, cmReal_t thresh, unsigned flags ) { cmRC_t rc = cmOkRC; unsigned i,j,k,t,d; unsigned iter; unsigned N = p->N; unsigned K = p->K; unsigned D = p->D; unsigned De2 = D * D; bool mixFl = !cmIsFlag(flags,kNoTrainMixCoeffChmmFl); bool meanFl = !cmIsFlag(flags,kNoTrainMeanChmmFl); bool covarFl = !cmIsFlag(flags,kNoTrainCovarChmmFl); bool bFl = mixFl | meanFl | covarFl; bool calcBFl = true; bool progFl = false; bool timeProgFl = false; cmReal_t progInc = 0.1; cmReal_t progFrac = 0; cmReal_t logProb = 0; //cmReal_t alphaM[N*T]; // alpha[N,T] //cmReal_t betaM[N*T]; // betaM[N,T] //cmReal_t logPrV[T]; //cmReal_t EpsM[N*N]; //cmReal_t BK[N*K*T]; //cmReal_t gamma_jk[N*K]; //cmReal_t uM[K*D*N]; //cmReal_t sMM[K*De2*N]; /* unsigned sz = ALIGN_T(N*T, cmReal_t) + ALIGN_T(N*T, cmReal_t) + ALIGN_T(T, cmReal_t) + ALIGN_T(N*N, cmReal_t) + ALIGN_T(N*K*T, cmReal_t) + ALIGN_T(N*K, cmReal_t) + ALIGN_T(K*D*N, cmReal_t) + ALIGN_T(K*De2*N,cmReal_t); cmArray mem; cmArrayAlloc(c, &mem); cmReal_t* alphaM = cmArrayResize(c, &mem, sz, cmReal_t); // alpha[N,T] cmReal_t* betaM = alphaM + ALIGN_T(N*T, cmReal_t); // betaM[N,T] cmReal_t* logPrV = betaM + ALIGN_T(N*T, cmReal_t); cmReal_t* EpsM = logPrV + ALIGN_T(T, cmReal_t); cmReal_t* BK = EpsM + ALIGN_T(N*N, cmReal_t); cmReal_t* gamma_jk = BK + ALIGN_T(N*K*T,cmReal_t); cmReal_t* uM = gamma_jk + ALIGN_T(N*K, cmReal_t); cmReal_t* sMM = uM + ALIGN_T(K*D*N,cmReal_t); */ cmReal_t* alphaM = cmMemAlloc( cmReal_t, N*T ); cmReal_t* betaM = cmMemAlloc( cmReal_t, N*T ); cmReal_t* logPrV = cmMemAlloc( cmReal_t, T ); cmReal_t* EpsM = cmMemAlloc( cmReal_t, N*N ); cmReal_t* BK = cmMemAlloc( cmReal_t, N*K*T ); cmReal_t* gamma_jk = cmMemAlloc( cmReal_t, N*K ); cmReal_t* uM = cmMemAlloc( cmReal_t, K*D*N ); cmReal_t* sMM = cmMemAlloc( cmReal_t, K*De2*N ); if( thresh <=0 ) thresh = 0.0001; //cmArrayResizeZ(c,&p->memC,N*T,cmReal_t); p->bM = cmMemResizeZ( cmReal_t, p->bM, N*T); for(iter=0; iterbV[i], oM + (t*D), 1, p->bM + (t*N) + i, BK + (t*N*K) + (i*K) ); } } // alpha[N,T] is prob. of transitioning forward to each state given the observed data cmReal_t logProb0 = cmChmmForward( p, oM, T, alphaM, logPrV ); // check for convergence cmReal_t dLogProb = labs(logProb0-logProb) / ((labs(logProb0)+labs(logProb)+cmReal_EPSILON)/2); if( dLogProb < thresh ) break; logProb = logProb0; // betaM[N,T] is prob of transitioning backward from each state given the observed data cmChmmBackward(p, oM, T, betaM ); if(progFl) cmCtxPrint(p->obj.ctx,"%i (%f) ",iter+1, dLogProb ); if(timeProgFl) progFrac = progInc; // for each time step for(t=0; taM[ i + (j*N) ]) + log(p->bM[ ((t+1)*N) + j ]) + log(betaM[ ((t+1)*N) + j ])); } cmVOR_NormalizeProbability( E, N*N ); cmVOR_AddVV( EpsM, N*N, E ); // If t==0 then update the initial state prob's if( t == 0 ) { for(i=0; iiV[i] = cmVOR_SumN(EpsM+i, N, N); assert( cmVOR_IsNormal(p->iV,N) ); } if( bFl ) { // // Calculate gamma_jk[] // cmReal_t gtjk[N*K]; // gamma_jk[N,K] at time t cmReal_t abV[N]; // // (alphaM[j,t] * betaM[j:t]) / (sum(alphaM[:,t] * betaM[:,t])) cmVOR_MultVVV(abV,N,alphaM + t*N, betaM+t*N); cmReal_t abSum = cmVOR_Sum(abV,N); if( abSum<=0 ) assert(abSum>0); cmVOR_DivVS(abV,N,abSum); for(j=0; jbV[j]->uM + (k*D)); cmVOR_MultMMM( dM, D, D, dV, dV, 1 ); cmVOR_MultVS( dM, De2, c ); cmVOR_AddVV( sV, De2, dM ); } if( meanFl ) { // mean numerator b[j].uM[k] for(d=0; d= floor(T*progFrac)) ) { cmCtxPrint(p->obj.ctx,"%i ", (unsigned)round(progFrac*100) ); progFrac+=progInc; } } // end time loop for(i=0; iaM[ i + (j*N) ] = EpsM[ i + (j*N) ] / den; if( bFl ) { // update the mean, covariance and mix coefficient cmGmm_t* g = p->bV[i]; const cmReal_t* uV = uM + (i*D*K); const cmReal_t* sMV = sMM + (i*De2*K); for(k=0; kuM + (k*D), D, uV, gjk ); if( covarFl ) cmVOR_DivVVS(g->sMM + (k*De2), De2, sMV, gjk ); if( mixFl ) g->gV[k] = gjk / cmVOR_SumN( gamma_jk + i, K, N ); } if((rc = _cmGmmUpdateCovar(g,g->sMM)) != cmOkRC ) goto errLabel; } } assert( cmVOR_IsNormalZ(p->aM,N*N) ); if( timeProgFl ) cmCtxPrint(p->obj.ctx,"\n"); } // end iter loop if( progFl) cmCtxPrint(p->obj.ctx,"\n"); if( p->mfp != NULL ) { // first line is iV[N] cmMtxFileRealExec(p->mfp,p->iV,p->N); // next N lines are aM[N,N] for(i=0; iN; ++i) cmMtxFileRealExecN(p->mfp,p->aM + i,p->N,p->N); // next T lines are bM[T,N] if( p->bM != NULL ) for(i=0; imfp, p->bM + (i*p->N),p->N); } errLabel: cmMemPtrFree(&alphaM); cmMemPtrFree(&betaM); cmMemPtrFree(&logPrV); cmMemPtrFree(&EpsM); cmMemPtrFree(&BK); cmMemPtrFree(&gamma_jk); cmMemPtrFree(&uM); cmMemPtrFree(&sMM); return rc; } void cmChmmPrint( cmChmm_t* p ) { unsigned i; cmCtxPrint(p->obj.ctx,"======================================== \n"); cmVOR_PrintL("iV: ", p->obj.err.rpt, 1, p->N, p->iV); cmVOR_PrintL("aM:\n", p->obj.err.rpt, p->N, p->N, p->aM); for(i=0; iN; ++i) { cmCtxPrint(p->obj.ctx,"bV[%i] ----------------- %i \n",i,i); cmGmmPrint(p->bV[i],false); } } void cmChmmTestForward( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ) { cmReal_t oM[] = { 0.117228, 0.110079, 0.154646, 0.210436, 0.947468, 0.558136, 0.202023, 0.138123, 0.929933, 0.456102, 0.897566, 0.685078, 0.945177, 0.663145, 0.272399, 0.055107, 0.863386, 0.621546, 0.217545, 0.274709, 0.838777, 0.650038, 0.134966, 0.159472, 0.053990, 0.264051, 0.884269, 0.550019, 0.764787, 0.554484, 0.114771, 0.077518, 0.835121, 0.606137, 0.070733, 0.120015, 0.819814, 0.588482, 0.105511, 0.197699, 0.824778, 0.533047, 0.945223, 0.511411, 0.126971, 0.050083, 0.869497, 0.567737, 0.144866, 0.197363, 0.985726, 0.590402, 0.181094, 0.192827, 0.162179, 0.155297, 1.034691, 0.513413, 0.220708, 0.036158, 0.750061, 0.671224, 0.246971, 0.093246, 0.997567, 0.680491, 0.916887, 0.530981, 0.022328, 0.121969, 0.794031, 0.618081, 0.845066, 0.625512, 0.174731, 0.094773, 0.968665, 0.652435, 0.932484, 0.388081, 0.202732, 0.148710, 0.911307, 0.637139, 0.211127, 0.201362, 0.138152, 0.057290, 0.819132, 0.579888, 0.135625, 0.176140, 0.146017, 0.157853, 0.950319, 0.624150, 0.285064, 0.038825, 0.716844, 0.575189, 0.907433, 0.504946, 0.219772, 0.129993, 0.076507, 0.193079, 0.808906, 0.548409, 0.880892, 0.523950, 0.758099, 0.636729, 1.014017, 0.557120, 0.277888, 0.181492, 0.877588, 0.508634, 0.251266, 0.225890, 0.990904, 0.482949, 0.999899, 0.534579, 0.904179, 0.707349, 0.952879, 0.617955, 0.172068, 0.151984, 1.026262, 0.662600, 0.812003, 0.430856, 0.173393, 0.017885, 0.099370, 0.146661, 0.785785, 0.564333, 0.698222, 0.449299, 0.276539, 0.225314, 0.799271, 0.618159, 0.098813, 0.090839, 0.883666, 0.554150, 0.274934, 0.185403, 0.200419, 0.109972, 0.925076, 0.608610, 0.864486, 0.348689, 0.176733, 0.136235, 0.967278, 0.656875, 0.986994, 0.659877, 1.015618, 0.596549, 0.689903, 0.528107, 0.978238, 0.630989, 0.269847, 0.144358, 0.092303, 0.139894, 0.168185, 0.095327, 0.897767, 0.584203, 0.068316, 0.018452, 0.953395, 0.530545, 0.266405, 0.173987, 0.233845, 0.205276, 0.900060, 0.477108, 0.052909, 0.053077, 0.885850, 0.496546, 0.268494, 0.104785, 1.041405, 0.655079, 1.055915, 0.697988, 0.181569, 0.146840 }; unsigned i; cmReal_t iV[] = { .5 , .5}; cmReal_t A[] = { .3, .6, .7, .4 }; cmReal_t cV0[] = { .7, .3 }; cmReal_t uM0[] = { .2, .1, .1, .2 }; cmReal_t sMM0[]= { .01, 0, 0, .01, .01, 0, 0, .01 }; cmReal_t cV1[] = { .2, .8 }; cmReal_t uM1[] = { .8, .9, .9, .5 }; cmReal_t sMM1[]= { .01, 0, 0, .01, .01, 0, 0, .01 }; unsigned T = 100; unsigned N = 2; unsigned K = 2; unsigned D = 2; cmReal_t alphaM[N*T]; cmReal_t betaM[N*T]; cmReal_t logPrV[T]; unsigned qV[T]; unsigned sV[T]; cmReal_t oMt[T*D]; // scale covariance cmVOR_MultVS(sMM0,D*D*K,1); cmVOR_MultVS(sMM1,D*D*K,1); cmCtx c; cmCtxAlloc(&c,rpt,lhH,stH); cmChmm_t* p = cmChmmAlloc(&c,NULL,N,K,D,iV,A); cmChmmSetGmm(p,0,cV0,uM0,sMM0,0); cmChmmSetGmm(p,1,cV1,uM1,sMM1,0); cmChmmPrint(p); cmChmmGenerate(p, oM, T, sV ); cmChmmForward( p, oM, T, alphaM,logPrV ); //cmVOR_PrintL("logPrV:\n",rpt,1,T,logPrV); cmCtxPrint(&c,"log prob:%f\n", cmVOR_Sum(logPrV,T)); cmChmmBackward( p, oM, T, betaM ); //cmVOR_PrintL("beta:\n",rpt,N,T,betaM); cmChmmDecode(p,oM,T,qV); cmVOU_PrintL("sV:\n",rpt,1,T,sV); cmVOU_PrintL("qV:\n",rpt,1,T,qV); unsigned d=0; for(i=0; ih = cmChmmAlloc( p->obj.ctx, NULL, 0, 0, 0, NULL, NULL ); if( chromaM != NULL && T > 0 ) if( cmChordInit(p,chromaM,T) != cmOkRC ) cmChordFree(&p); p->N = N; p->D = D; p->S = kTonalSpaceDimCnt; /* // iv[N] aM[N*N] uM[D*N] sMM[D*D*N] phiM[D*S] tsxxxV[S] unsigned n = ALIGN_T(N, cmReal_t) + ALIGN_T(N*N, cmReal_t) + ALIGN_T(D*N, cmReal_t) + ALIGN_T(D*D*N,cmReal_t) + ALIGN_T(D*S, cmReal_t) + 2*ALIGN_T(S, cmReal_t); p->iV = cmArrayResizeZ(c, &p->memA, n, cmReal_t); p->aM = p->iV + ALIGN_T(N, cmReal_t); p->uM = p->aM + ALIGN_T(N*N, cmReal_t); p->sMM = p->uM + ALIGN_T(D*N, cmReal_t); p->phiM = p->sMM + ALIGN_T(D*D*N,cmReal_t); p->tsMeanV = p->phiM + ALIGN_T(D*S, cmReal_t); p->tsVarV = p->tsMeanV + ALIGN_T(S, cmReal_t); */ p->iV = cmMemAllocZ( cmReal_t, N ); p->aM = cmMemAllocZ( cmReal_t, N*N); p->uM = cmMemAllocZ( cmReal_t, D*N); p->sMM = cmMemAllocZ( cmReal_t, D*D*N ); p->phiM = cmMemAllocZ( cmReal_t, D*S); p->tsMeanV = cmMemAllocZ( cmReal_t, S ); p->tsVarV = cmMemAllocZ( cmReal_t, S ); // initialize iV[N] (HMM initial state probabilities) cmVOR_Fill(p->iV,N,1.0/N); // initialize aM[N,N] (HMM transition matrix) cmReal_t epsilon = 0.01; cmReal_t CMaj2any[] = { 12, 2, 8, 6, 4, 10, 0, 10, 4, 6, 8, 2, 5, 5, 9, 1, 11, 3, 7, 7, 3, 11, 1, 9 }; for(i=0; iaM+(i*N), N, CMaj2any ); cmVOR_Rotate( CMaj2any, N, 1 ); } cmVOR_AddVS(p->aM, N*N, epsilon); cmVOR_DivVS(p->aM, N*N, ( (N/2)*(N/2) ) + (N*epsilon) ); //cmVOR_PrintL("A:\n",p->obj.err.rpt,N,N,A); // initialize sMM[D*D,N] (HMM covariance matrices) cmReal_t diagMV[] = { 1, 0.2, 0.2, 0.2, 1.0, 0.2, 0.2, 1.0, 0.2, 0.2, 0.2, 0.2 }; cmReal_t diagmV[] = { 1, 0.2, 0.2, 1.0, 0.2, 0.2, 0.2, 1.0, 0.2, 0.2, 0.2, 0.2 }; cmReal_t Maj[D*D]; cmReal_t Min[D*D]; cmVOR_DiagZ(Maj,D,diagMV); Maj[ (4*D) + 0 ] = 0.6; Maj[ (0*D) + 4 ] = 0.6; Maj[ (7*D) + 0 ] = 0.8; Maj[ (0*D) + 7 ] = 0.8; Maj[ (7*D) + 4 ] = 0.8; Maj[ (4*D) + 7 ] = 0.8; cmVOR_DiagZ(Min,D,diagmV); Min[ (3*D) + 0 ] = 0.6; Min[ (0*D) + 3 ] = 0.6; Min[ (7*D) + 0 ] = 0.8; Min[ (0*D) + 7 ] = 0.8; Min[ (7*D) + 3 ] = 0.8; Min[ (3*D) + 7 ] = 0.8; cmReal_t* sM = p->sMM; for(i=0; iobj.err.rpt,D,D,Maj); cmVOR_PrintL("Min:\n",p->obj.err.rpt,D,D,Min); for(i=0; iobj.err.rpt,D,D,sMM + (i*D*D)); } */ // initialize uM[D,N] (HMM GMM mean vectors) cmVOR_Fill(p->uM,D*N,0); for(i=0; iuM[ (i * D) + i ] = 1; p->uM[ (i * D) + medM ] = 1; p->uM[ (i * D) + dom ] = 1; p->uM[ ((i+D) * D) + i ] = 1; p->uM[ ((i+D) * D) + medm ] = 1; p->uM[ ((i+D) * D) + dom ] = 1; } cmVOR_AddVS(p->uM,D*N,0.01); for(i=0; iuM + (i*D), D); // initialize phiM[D,S] cmReal_t phi[D*S]; for(i=0,j=0; iphiM,phi,D,S); return p; } cmRC_t cmChordFree( cmChord** pp ) { cmRC_t rc = cmOkRC; cmChord* p = *pp; if( pp == NULL || *pp == NULL ) return cmOkRC; if((rc = cmChordFinal(p)) != cmOkRC ) return rc; cmChmmFree( &p->h ); cmMemPtrFree(&p->iV); cmMemPtrFree(&p->aM); cmMemPtrFree(&p->uM); cmMemPtrFree(&p->sMM); cmMemPtrFree(&p->phiM); cmMemPtrFree(&p->tsMeanV); cmMemPtrFree(&p->tsVarV); cmMemPtrFree(&p->chromaM); cmMemPtrFree(&p->tsM); cmMemPtrFree(&p->cdtsV); cmObjFree(pp); return rc; } cmRC_t cmChordInit( cmChord* p, const cmReal_t* chromaM, unsigned T ) { cmRC_t rc = cmOkRC; unsigned i; unsigned N = p->N; // count of states unsigned K = 1; // count of components per mixture unsigned D = p->D; // dimensionality of the observation vector unsigned S = p->S; // cmReal_t alpha = 6.63261; // alpha norm coeff if((rc = cmChordFinal(p)) != cmOkRC ) return rc; // Create the hidden markov model cmChmmInit( p->h, N, K, D, p->iV, p->aM); // load the GMM's for each markov state cmReal_t mixCoeff = 1.0; bool diagFl = false; for(i=0; ih, i, &mixCoeff, p->uM + (i*D), p->sMM+(i*D*D), diagFl )) != cmOkRC ) return rc; // Allocate memory // chromaM[D,T] tsM[S,T] cdtsV[T] /* unsigned n = ALIGN_T(D*T,cmReal_t) + ALIGN_T(S*T,cmReal_t) + ALIGN_T(T,cmReal_t); p->chromaM = cmArrayResizeZ(c, &p->memB, n, cmReal_t); p->tsM = p->chromaM + ALIGN_T(D*T,cmReal_t); p->cdtsV = p->tsM + ALIGN_T(S*T,cmReal_t); p->T = T; */ p->chromaM = cmMemResizeZ( cmReal_t, p->chromaM, p->D*T ); p->tsM = cmMemResizeZ( cmReal_t, p->tsM, p->S*T ); p->cdtsV = cmMemResizeZ( cmReal_t, p->cdtsV, p->D*T ); p->T = T; // Allocate local memory // qV[], triadIntV[] triadSeqV[] tsNormsV[] /* n = 2*ALIGN_B(T,unsigned) + ALIGN_B(T,int) + ALIGN_B(T,cmReal_t); cmArray mem; cmArrayAlloc(c, &mem); unsigned* qV = (unsigned*) cmArrayResize(c, &mem, n, char); unsigned* triadSeqV = (unsigned*) (qV + ALIGN_T(T,unsigned)); int* triadIntV = (int*) (triadSeqV + ALIGN_T(T,unsigned)); cmReal_t* tsNormsV = (cmReal_t*) (triadIntV + ALIGN_T(T,int)); */ //unsigned qV[T]; //unsigned triadSeqV[T]; //int triadIntV[T]; //cmReal_t tsNormsV[T]; unsigned* qV = cmMemAlloc( unsigned, T ); unsigned* triadSeqV = cmMemAlloc( unsigned, T ); int* triadIntV = cmMemAlloc( int, T ); cmReal_t* tsNormsV = cmMemAlloc( cmReal_t, T ); // Take the alpha norm of chroma and store the result in p->chromaM[] for(i=0; ichromaM[i] = cmVOR_AlphaNorm( chromaM + (i*D), D, alpha); cmVOR_DivVVS(p->chromaM,D*T,chromaM, cmVOR_AlphaNorm(p->chromaM,T,alpha)); // Train the HMM iniital state prob. p->h->iV[] and transition matrix p->h->aM[] unsigned flags = kNoTrainMixCoeffChmmFl | kNoTrainMeanChmmFl | kNoTrainCovarChmmFl; unsigned iterCnt = 40; if( chromaM != NULL && T > 0 ) if((rc = cmChmmTrain(p->h, p->chromaM, p->T, iterCnt, 0, flags )) != cmOkRC ) goto errLabel; // Find the most likely chords using a Viterbi decoding of the chroma. cmChmmDecode(p->h,p->chromaM,T,qV); // Reorder the chord sequence cmcording to circle of fifths unsigned map[] = {0, 14, 4, 18, 8, 22, 12, 2, 16, 6, 20, 10, 17, 7, 21, 11, 1, 15, 5, 19, 9, 23, 13, 3 }; for(i=0; iobj.err.rpt,1,T,qV); // Smooth the chord sequence with a median filter. cmVOU_MedianFilt(qV,T,3,triadSeqV,1); //cmVOU_PrintL("triadSeqV:\n",p->obj.err.rpt,1,T,triadSeqV); // Calculate the chord change distance on the circle of fifths. int d = 0; for(i=0; i 0 ) triadIntV[i-1] = (d < 0 ? -1 : 1) * v; if( i + 1 < T) d = triadSeqV[i+1] - triadSeqV[i]; } // Project chroma into a 6D tonal space. cmVOR_MultMMM( p->tsM,S,T,p->phiM,p->chromaM,D); // Find the norm of p->tsM[6,T] cmVOR_Fill(tsNormsV,T,0); for(i=0; itsM + (i*S), p->tsM + (i*S), S ); cmVOR_PowVS(tsNormsV,T,0.5); // Take the cosine distance. p->cdtsV[0] = 1; for(i=1; icdtsV[i] = cmVOR_MultSumVV( p->tsM + ((i-1)*S), p->tsM + (i*S), S ); for(i=0; icdtsV[i+1] /= tsNormsV[i] * tsNormsV[i+1]; //cmVOR_PrintL("tsNormsV:\n",p->obj.err.rpt,1,T,tsNormsV); //cmVOR_PrintL("CDTS:\n", p->obj.err.rpt,1,T,p->cdtsV); p->triadSeqMode = cmVOU_Mode(triadSeqV,T); p->triadSeqVar = cmVOU_Variance(triadSeqV,T,NULL); p->triadIntMean = cmVOI_Mean(triadIntV,T); p->triadIntVar = cmVOI_Variance(triadIntV,T,&p->triadIntMean); cmVOR_MeanM( p->tsMeanV, p->tsM, S, T, 1 ); cmVOR_VarianceM( p->tsVarV, p->tsM, S, T, p->tsMeanV, 1); p->cdtsMean = cmVOR_Mean( p->cdtsV, T ); p->cdtsVar = cmVOR_Variance( p->cdtsV, T, &p->cdtsMean ); /* cmReal_t tsMt[T*S]; cmKbRecd kb; cmPlotInitialize(NULL); cmPlotSetup("Chords",1,1); cmCtxPrint(c,"%s\n","press any key"); //cmPlotLineD( NULL, NULL, p->cdtsV, NULL, T, NULL, kSolidPlotLineId ); cmVOR_Transpose(tsMt,p->tsM,S,T); cmPlotLineMD(NULL, tsMt, NULL, T, S, kSolidPlotLineId); cmPlotDraw(); cmKeyPress(&kb); cmPlotFinalize(); */ errLabel: cmMemPtrFree(&qV); cmMemPtrFree(&triadSeqV); cmMemPtrFree(&triadIntV); cmMemPtrFree(&tsNormsV); return rc; } cmRC_t cmChordFinal( cmChord* p ) { return cmOkRC; } void cmChordTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ) { cmCtx c; cmCtxAlloc(&c,rpt,lhH,stH); cmChord* p = cmChordAlloc(&c,NULL,NULL,0); cmChordFree(&p); }