//| Copyright: (C) 2009-2020 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #ifndef cmProc_h #define cmProc_h #ifdef __cplusplus extern "C" { #endif //( { file_desc:"Processor Library 1" kw:[proclib]} //) //( { label:cmAudioFileRd file_desc:"Audio file reader based on cmAudioFile" kw:[proc] } typedef struct { cmObj obj; cmAudioFileH_t h; // audio file handle cmAudioFileInfo_t info; // audio file info record unsigned chIdx; cmSample_t* outV; // buffer of audio from last read unsigned outN; // length of outV in samples cmChar_t* fn; // name of audio file unsigned lastReadFrmCnt; // count of samples actually read on last read bool eofFl; unsigned begFrmIdx; unsigned endFrmIdx; unsigned curFrmIdx; // frame index of the next frame to read cmMtxFile* mfp; } cmAudioFileRd; // set p to NULL to dynamically allocate the object // fn and chIdx are optional - set fn to NULL to allocate the reader without opening a file. // If fn is valid then chIdx must also be valid. // Set 'endSmpIdx' to cmInvalidIdx to return the entire signal in cmAudioFileRdRead(). // Set 'endSmpIdx' to 0 to return all samples between 0 and the end of the file. cmAudioFileRd* cmAudioFileRdAlloc( cmCtx* c, cmAudioFileRd* p, unsigned procSmpCnt, const char* fn, unsigned chIdx, unsigned begSmpIdx, unsigned endSmpIdx ); cmRC_t cmAudioFileRdFree( cmAudioFileRd** p ); cmRC_t cmAudioFileRdOpen( cmAudioFileRd* p, unsigned procSmpCnt, const cmChar_t* fn, unsigned chIdx, unsigned begSmpIdx, unsigned endSmpIdx ); cmRC_t cmAudioFileRdClose( cmAudioFileRd* p ); // Returns cmEofRC if the end of file is encountered. cmRC_t cmAudioFileRdRead( cmAudioFileRd* p ); cmRC_t cmAudioFileRdSeek( cmAudioFileRd* p, unsigned frmIdx ); // Find the overall minimum, maximum, and mean sample values without changing the current file location. cmRC_t cmAudioFileRdMinMaxMean( cmAudioFileRd* p, unsigned chIdx, cmSample_t* minPtr, cmSample_t* maxPtr, cmSample_t* meanPtr ); //) //( { label:cmShiftBuf file_desc:"Audio shift buffer processor" kw:[proc] } //------------------------------------------------------------------------------------------------------------ // The buffer is intended to synchronize sample block rates between processes and to provide an overlapped // input buffer. typedef struct cmShiftBuf_str { cmObj obj; unsigned bufSmpCnt; // wndSmpCnt + hopSmpCnt cmSample_t* bufV; // bufV[bufSmpCnt] all other pointers use this memory cmSample_t* outV; // output window outV[ outN ] unsigned outN; // outN == wndSmpCnt unsigned procSmpCnt; // input sample count unsigned wndSmpCnt; // output sample count unsigned hopSmpCnt; // count of samples to shift the buffer by on each call to cmShiftExec() cmSample_t* inPtr; // ptr to location in outV[] to recv next sample bool fl; // reflects the last value returned by cmShiftBufExec(). } cmShiftBuf; // Set p to NULL to dynamically allocate the object. hopSmpCnt must be <= wndSmpCnt. cmShiftBuf* cmShiftBufAlloc( cmCtx* c, cmShiftBuf* p, unsigned procSmpCnt, unsigned wndSmpCnt, unsigned hopSmpCnt ); cmRC_t cmShiftBufFree( cmShiftBuf** p ); cmRC_t cmShiftBufInit( cmShiftBuf* p, unsigned procSmpCnt, unsigned wndSmpCnt, unsigned hopSmpCnt ); cmRC_t cmShiftBufFinal( cmShiftBuf* p ); // Returns true if a new hop is ready to be read otherwise returns false. // In general cmShiftBufExec() should be called in a loop until it returns false. // Note that 'sp' and 'sn' are ignored except for the first call after the function returns false. // This means that when called in a loop 'sp' and 'sn' are only used on the first time through the loop. // When procSmpCnt is less than hopSmpCnt the loop will only execute when at least wndSmpCnt // new samples have been buffered. // When procSmpCnt is greater than hopSmpCnt the loop will execute multiple times until less // than wndSmpCnt new samples are available. // Note that 'sn' must always be less than or equal to procSmpCnt. // // Example: // while( fill(sp,sn) ) // fill sp[] with sn samples // { // // shift by hopSmpCnt samples on all passes - insert new samples on first pass // while( cmShiftBufExec(p,sp,sn) ) // proc(p->outV,p->outN); // process p->outV[wndSmpCnt] // } bool cmShiftBufExec( cmShiftBuf* p, const cmSample_t* sp, unsigned sn ); void cmShiftBufTest( cmCtx* c ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmWindowFunc file_desc:"Fourier Transform window function generator." kw:[proc]} enum { kInvalidWndId = 0x000, kHannWndId = 0x001, kHammingWndId = 0x002, kTriangleWndId = 0x004, kKaiserWndId = 0x008, kHannMatlabWndId= 0x010, kUnityWndId = 0x020, kWndIdMask = 0x0ff, kNormByLengthWndFl = 0x100, // mult by 1/wndSmpCnt kNormBySumWndFl = 0x200, // mult by wndSmpCnt/sum(wndV) kSlRejIsBetaWndFl = 0x400 // kaiserSideLobeRejectDb param. is actually kaiser beta arg. }; typedef struct { cmObj obj; unsigned wndId; unsigned flags; cmSample_t* wndV; cmSample_t* outV; unsigned outN; // same as wndSmpCnt double kslRejectDb; cmMtxFile* mfp; } cmWndFunc; // Set p to NULL to dynamically allocate the object // if wndId is set to a valid value this function will internally call cmWndFuncInit() cmWndFunc* cmWndFuncAlloc( cmCtx* c, cmWndFunc* p, unsigned wndId, unsigned wndSmpCnt, double kaierSideLobeRejectDb ); cmRC_t cmWndFuncFree( cmWndFunc** pp ); cmRC_t cmWndFuncInit( cmWndFunc* p, unsigned wndId, unsigned wndSmpCnt, double kaiserSideLobeRejectDb ); cmRC_t cmWndFuncFinal( cmWndFunc* p ); cmRC_t cmWndFuncExec( cmWndFunc* p, const cmSample_t* sp, unsigned sn ); void cmWndFuncTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmSpecDelay file_desc:"Spectral frame delay. A circular buffer for spectral (or other fixed length) vectors." kw:[proc]} typedef struct { cmObj obj; cmSample_t* bufPtr; unsigned maxDelayCnt; int inIdx; unsigned outN; // outN == binCnt } cmSpecDelay; // Set p to NULL to dynamically allocate the object. // Allocate a spectral frame delay capable of delaying for 'maxDelayCnt' hops and // where each vector contains 'binCnt' elements. cmSpecDelay* cmSpecDelayAlloc( cmCtx* c, cmSpecDelay* p, unsigned maxDelayCnt, unsigned binCnt ); cmRC_t cmSpecDelayFree( cmSpecDelay** p ); cmRC_t cmSpecDelayInit( cmSpecDelay* p, unsigned maxDelayCnt, unsigned binCnt ); cmRC_t cmSpecDelayFinal(cmSpecDelay* p ); // Give an input vector to the delay. 'sn' must <= binCnt cmRC_t cmSpecDelayExec( cmSpecDelay* p, const cmSample_t* sp, unsigned sn ); // Get a pointer to a delayed vector. 'delayCnt' indicates the length of the delay in hops. // (e.g. 1 is the previous hop, 2 is two hops previous, ... ) const cmSample_t* cmSpecDelayOutPtr(cmSpecDelay* p, unsigned delayCnt ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmFilter file_desc:"General purpose, LTI, Octave compatible, filter." kw:[proc] } typedef struct cmFilter_str { cmObj obj; cmReal_t* a; // feedback coeff's int an; // count of fb coeff's cmReal_t* b; // feedforward coeff's int bn; // count of ff coeffs' cmReal_t* d; // delay int di; // int cn; // length of delay cmReal_t b0; // 1st feedforward coeff cmSample_t* outSmpV; // signal output vector cmReal_t* outRealV; unsigned outN; // length of outV (procSmpCnt) } cmFilter; // d[dn] is the initial value of the delay line where dn = max(an,bn)-1. // Set d to NULL to intialize the delays to 0. cmFilter* cmFilterAlloc( cmCtx* c, cmFilter* p, const cmReal_t* b, unsigned bn, const cmReal_t* a, unsigned an, unsigned procSmpCnt, const cmReal_t* d ); cmFilter* cmFilterAllocEllip( cmCtx* c, cmFilter* p, cmReal_t srate, cmReal_t passHz, cmReal_t stopHz, cmReal_t passDb, cmReal_t stopDb, unsigned procSmpCnt, const cmReal_t* d ); cmRC_t cmFilterFree( cmFilter** pp ); cmRC_t cmFilterInit( cmFilter* p, const cmReal_t* b, unsigned bn, const cmReal_t* a, unsigned an, unsigned procSmpCnt, const cmReal_t* d ); 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 ); cmRC_t cmFilterFinal( cmFilter* p ); // If y==NULL or yn==0 then the output is sent to p->outV[p->outN]. // This function can safely filter a signal in plcme therefore it is allowable for x[] and y[] to refer to the same memory. // If x[] overlaps y[] then y must be <= x. cmRC_t cmFilterExecS( cmFilter* p, const cmSample_t* x, unsigned xn, cmSample_t* y, unsigned yn ); cmRC_t cmFilterExecR( cmFilter* p, const cmReal_t* x, unsigned xn, cmReal_t* y, unsigned yn ); 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 ); // Perform forward-reverse filtering. cmRC_t cmFilterFilterS(cmCtx* c, const cmReal_t bb[], unsigned bn, const cmReal_t aa[], unsigned an, const cmSample_t* x, unsigned xn, cmSample_t* y, unsigned yn ); cmRC_t cmFilterFilterR(cmCtx* c, const cmReal_t bb[], unsigned bn, const cmReal_t aa[], unsigned an, const cmReal_t* x, unsigned xn, cmReal_t* y, unsigned yn ); void cmFilterTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); void cmFilterFilterTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmComplexDetect file_desc:"Complex domain onset detection function." kw:[proc] } typedef struct { cmObj obj; cmSpecDelay phsDelay; cmSpecDelay magDelay; unsigned binCnt; cmSample_t out; //cmMtxFile* mfp; //unsigned cdfSpRegId; } cmComplexDetect; // Set p to NULL to dynamically allocate the object. cmComplexDetect* cmComplexDetectAlloc(cmCtx* c, cmComplexDetect* p, unsigned binCnt ); cmRC_t cmComplexDetectFree( cmComplexDetect** pp); cmRC_t cmComplexDetectInit( cmComplexDetect* p, unsigned binCnt ); cmRC_t cmComplexDetectFinal(cmComplexDetect* p); cmRC_t cmComplexDetectExec( cmComplexDetect* p, const cmSample_t* magV, const cmSample_t* phsV, unsigned binCnt ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmComplexOnset file_desc:"Complex onset detection function" kw:[proc]} typedef struct { cmObj obj; double threshold; unsigned medSmpCnt; unsigned frmCnt; // expected number of frames to store unsigned dfi; cmSample_t* df; cmSample_t* fdf; cmSample_t onrate; //cmMtxFile* mfp; } cmComplexOnset; cmComplexOnset* cmComplexOnsetAlloc( cmCtx* c, cmComplexOnset* p, unsigned procSmpCnt, double srate, unsigned medFiltWndSmpCnt, double threshold, unsigned frameCnt ); cmRC_t cmComplexOnsetFree( cmComplexOnset** pp); cmRC_t cmComplexOnsetInit( cmComplexOnset* p, unsigned procSmpCnt, double srate, unsigned medFiltWndSmpCnt, double threshold, unsigned frameCnt ); cmRC_t cmComplexOnsetFinal( cmComplexOnset* p); cmRC_t cmComplexOnsetExec( cmComplexOnset* p, cmSample_t cdf ); cmRC_t cmComplexOnsetCalc( cmComplexOnset* p ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmMfcc file_desc:"Mel Frequency Cepstral Coefficient (MFCC) measurement function." kw:[proc] } typedef struct { cmObj obj; unsigned melBandCnt; unsigned dctCoeffCnt; unsigned binCnt; cmReal_t* melM; cmReal_t* dctM; cmReal_t* outV; unsigned outN; // outN == dctCoeffCnt cmMtxFile* mfp; unsigned mfccSpRegId; // cmStatsProc regId } cmMfcc; cmMfcc* cmMfccAlloc( cmCtx* c, cmMfcc* p, double srate, unsigned melBandCnt, unsigned dctCoeffCnt, unsigned binCnt ); cmRC_t cmMfccFree( cmMfcc** pp ); cmRC_t cmMfccInit( cmMfcc* p, double srate, unsigned melBandCnt, unsigned dctCoeffCnt, unsigned binCnt ); cmRC_t cmMfccFinal( cmMfcc* p ); cmRC_t cmMfccExecPower( cmMfcc* p, const cmReal_t* magPowV, unsigned binCnt ); cmRC_t cmMfccExecAmplitude( cmMfcc* p, const cmReal_t* magAmpV, unsigned binCnt ); void cmMfccTest(); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmSones file_desc:"Sones measurement function." kw:[proc] } typedef struct { cmObj obj; cmReal_t* ttmV; // Terhardt outer ear filter cmReal_t* sfM; // Shroeder spreading function unsigned* barkIdxV; // Bark to bin map unsigned* barkCntV; // cmReal_t* outV; // specific loudness in sones unsigned outN; // outN == barkBandCnt; cmReal_t overallLoudness; // overall loudness in sones unsigned binCnt; // expected length of incoming power spectrum unsigned barkBandCnt; // count of bark bands unsigned flags; // cmMtxFile* mfp; unsigned sonesSpRegId; unsigned loudSpRegId; } cmSones; enum { kDontUseEqlLoudSonesFl=0x00, kUseEqlLoudSonesFl=0x01 }; cmSones* cmSonesAlloc( cmCtx* c, cmSones* p, double srate, unsigned barkBandCnt, unsigned binCnt, unsigned flags ); cmRC_t cmSonesFree( cmSones** pp ); cmRC_t cmSonesInit( cmSones* p, double srate, unsigned barkBandCnt, unsigned binCnt, unsigned flags ); cmRC_t cmSonesFinal( cmSones* p ); cmRC_t cmSonesExec( cmSones* p, const cmReal_t* magPowV, unsigned binCnt ); void cmSonesTest(); //------------------------------------------------------------------------------------------------------------ //) //( { label: cmAudioOffsetScale file_desc:"Audio signal pre-processing normalizer." kw:[proc] } typedef struct { cmObj obj; unsigned cBufCnt; unsigned cBufCurCnt; unsigned cBufIdx; double cBufSum; unsigned cCntSum; cmReal_t* cBufPtr; unsigned* cCntPtr; cmSample_t offset; double dBref; cmSample_t* outV; unsigned outN; // (outN == procSmpCnt) unsigned flags; cmMtxFile* mfp; } cmAudioOffsetScale; // This processor adds an offset to an audio signal and scales into dB (SPL) using one of two techniques // 1) Measures the effective sound pressure (via RMS) and then scales the signal to the reference dB (SPL) // In this case dBref is commonly set to 70. See Timony, 2004, Implementing Loudness Models in Matlab. // // 2) treats the dBref as the maximum dB (SPL) and scales the signal by this amount without regard // measured signal level. In this case dBref is commonly set to 96 (max. dB (SPL) value for 16 bits) // and rmsWndSecs is ignored. // // Note that setting rmsWndSecs to zero has the effect of using procSmpCnt as the window length. enum { kNoAudioScaleFl=0x01, kRmsAudioScaleFl=0x02, kFixedAudioScaleFl=0x04 }; cmAudioOffsetScale* cmAudioOffsetScaleAlloc( cmCtx* c, cmAudioOffsetScale* p, unsigned procSmpCnt, double srate, cmSample_t offset, double rmsWndSecs, double dBref, unsigned flags ); cmRC_t cmAudioOffsetScaleFree( cmAudioOffsetScale** pp ); cmRC_t cmAudioOffsetScaleInit( cmAudioOffsetScale* p, unsigned procSmpCnt, double srate, cmSample_t offset, double rmsWndSecs, double dBref, unsigned flags ); cmRC_t cmAudioOffsetScaleFinal( cmAudioOffsetScale* p ); cmRC_t cmAudioOffsetScaleExec( cmAudioOffsetScale* p, const cmSample_t* sp, unsigned sn ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmSpecMeas file_desc:"Measure a signals RMS, High-Frequency Content, Spectral Centroid, and Spectral Spread." kw:[proc]} typedef struct { cmObj obj; cmReal_t* rmsV; cmReal_t* hfcV; cmReal_t* scnV; cmReal_t rmsSum; cmReal_t hfcSum; cmReal_t scnSum; cmReal_t ssSum; cmReal_t rms; // RMS output cmReal_t hfc; // high-frequency content output cmReal_t sc; // spectral centroid output cmReal_t ss; // spectral spread output unsigned binCnt; unsigned flags; unsigned wndFrmCnt; unsigned frameIdx; unsigned frameCnt; double binHz; cmMtxFile* mfp; unsigned rmsSpRegId; unsigned hfcSpRegId; unsigned scSpRegId; unsigned ssSpRegId; } cmSpecMeas; // Set wndFrmCnt to the number of spectral frames to take the measurement over. // Setting wndFrmCnt to 1 has the effect of calculating the value on the current frame only. // Set flags = kWholeSigSpecMeasFl to ignore wndFrmCnt and calculate the result on the entire signal. // In effect this treats the entire signal as the length of the measurement window. enum { kWholeSigSpecMeasFl=0x00, kUseWndSpecMeasFl=0x01 }; cmSpecMeas* cmSpecMeasAlloc( cmCtx* c, cmSpecMeas* p, double srate, unsigned binCnt, unsigned wndFrmCnt, unsigned flags ); cmRC_t cmSpecMeasFree( cmSpecMeas** pp ); cmRC_t cmSpecMeasInit( cmSpecMeas* p, double srate, unsigned binCnt, unsigned wndFrmCnt, unsigned flags ); cmRC_t cmSpecMeasFinal( cmSpecMeas* p ); cmRC_t cmSpecMeasExec( cmSpecMeas* p, const cmReal_t* magPowV, unsigned binCnt ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmSigMeas file_desc:"Measure a time domain signals zero crossing rate." kw:[proc]} typedef struct { cmObj obj; cmShiftBuf* sbp; // shift buffer used internally if procSmpCnt < measSmpCnt cmShiftBuf shiftBuf; double srate; // cmReal_t zcr; // zero crossing rate per second cmSample_t zcrDelay; // used internally by zero crossing count algorithm unsigned measSmpCnt; // length of measurement window in samples unsigned procSmpCnt; // expected number of samples per call to exec unsigned zcrSpRegId; cmMtxFile* mfp; } cmSigMeas; // procSmpCnt must be <= measSmpCnt cmSigMeas* cmSigMeasAlloc( cmCtx* c, cmSigMeas* p, double srate, unsigned procSmpCnt, unsigned measSmpCnt ); cmRC_t cmSigMeasFree( cmSigMeas** pp ); cmRC_t cmSigMeasInit( cmSigMeas* p, double srate, unsigned procSmpCnt, unsigned measSmpCnt ); cmRC_t cmSigMeasFinal( cmSigMeas* p ); cmRC_t cmSigMeasExec( cmSigMeas* p, const cmSample_t* sigV, unsigned smpCnt ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmSRC file_desc:"Sample rate converter" kw:[proc] } typedef struct { cmObj obj; cmFilter filt; cmSample_t* outV; unsigned outN; unsigned upFact; unsigned dnFact; unsigned upi; unsigned dni; cmMtxFile* mfp; } cmSRC; // The srate paramater is the sample rate of the source signal provided via cmSRCExec() cmSRC* cmSRCAlloc( cmCtx* c, cmSRC* p, double srate, unsigned procSmpCnt, unsigned upFact, unsigned dnFact ); cmRC_t cmSRCFree( cmSRC** pp ); cmRC_t cmSRCInit( cmSRC* p, double srate, unsigned procSmpCnt, unsigned upFact, unsigned dnFact ); cmRC_t cmSRCFinal( cmSRC* p ); cmRC_t cmSRCExec( cmSRC* p, const cmSample_t* sp, unsigned sn ); void cmSRCTest(); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmConstQ file_desc:"Contant-Q transform." kw:[proc] } typedef struct { cmObj obj; cmComplexR_t* fiV; cmComplexR_t* foV; cmComplexR_t* skM; // skM[ wndSmpCnt, constQBinCnt ] unsigned* skBegV; // skBegV[ constQBinCnt ] indexes used to decrease the size of the mtx mult in cmConstQExex() unsigned* skEndV; // skEndV[ constQBinCnt ] unsigned wndSmpCnt; // window length of the complex FFT required to feed this transform unsigned constQBinCnt; // count of bins in the const Q output unsigned binsPerOctave; // cmComplexR_t* outV; // outV[ constQBinCnt ] cmReal_t* magV; // outV[ constQBinCnt ] cmMtxFile* mfp; } cmConstQ; cmConstQ* cmConstQAlloc( cmCtx* c, cmConstQ* p, double srate, unsigned minMidiPitch, unsigned maxMidiPitch, unsigned binsPerOctave, double thresh ); cmRC_t cmConstQFree( cmConstQ** pp ); cmRC_t cmConstQInit( cmConstQ* p, double srate, unsigned minMidiPitch, unsigned maxMidiPitch, unsigned binsPerOctave, double thresh ); cmRC_t cmConstQFinal( cmConstQ* p ); cmRC_t cmConstQExec( cmConstQ* p, const cmComplexR_t* ftV, unsigned binCnt ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmTuneHpcp file_desc:"Generate a tuned chromagram." kw:[proc]} typedef struct { cmObj obj; cmReal_t* hpcpM; // hpcpM[ frameCnt , binsPerOctave ] - stored hpcp cmReal_t* fhpcpM;// fhpcpM[ binsPerOctave, frameCnt ] - filtered hpcp (note transposed relative to hpcpA) unsigned* histV; // histM[ binsPerOctave/12 ] cmReal_t* outM; // outM[ 12, frameCnt ]; unsigned histN; // binsPerOctave/12 unsigned binsPerOctave; // const-q bins representing 1 octave unsigned constQBinCnt; // total count of const-q bins unsigned frameCnt; // expected count of hpcp vectors to store. unsigned frameIdx; // next column in hpcpM[] to receive input unsigned cqMinMidiPitch; unsigned medFiltOrder; cmReal_t* meanV; // meanV[12] cmReal_t* varV; // varV[12] cmMtxFile* mf0p; // debug files cmMtxFile* mf1p; cmMtxFile* mf2p; } cmHpcp; cmHpcp* cmTunedHpcpAlloc( cmCtx* c, cmHpcp* p, unsigned binsPerOctave, unsigned constQBinCnt, unsigned cqMinMidiPitch, unsigned frameCnt, unsigned medFiltOrder ); cmRC_t cmTunedHpcpFree( cmHpcp** pp ); cmRC_t cmTunedHpcpInit( cmHpcp* p, unsigned binsPerOctave, unsigned constQBinCnt, unsigned cqMinMidiPitch, unsigned frameCnt, unsigned medFiltOrder ); cmRC_t cmTunedHpcpFinal( cmHpcp* p ); cmRC_t cmTunedHpcpExec( cmHpcp* p, const cmComplexR_t* constQBinPtr, unsigned constQBinCnt ); cmRC_t cmTunedHpcpTuneAndFilter( cmHpcp* p); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmBeatHist file_desc:"Generate a beat candidate histogram." kw:[proc]} struct cmFftRR_str; struct cmIFftRR_str; typedef struct { cmObj obj; struct cmFftRR_str* fft; struct cmIFftRR_str* ifft; unsigned frmCnt; // 512 length of df unsigned maxLagCnt; // 128 length of longest CMF lag unsigned histBinCnt; // 15 count of histogram elements and rows in H[] unsigned hColCnt; // 128 count of columns in H[] cmReal_t* m; // m[ frmCnt x maxLagCnt ] cmReal_t* H; // histogram transformation mtx cmReal_t* df; // df[ frmCnt ] onset detection function cmReal_t* fdf; // fdf[ frmCnt ] filtered onset detection function unsigned dfi; // index next df[] location to receive an incoming value cmReal_t* histV; // histV[ histBinCnt ] histogram output cmMtxFile* mfp; } cmBeatHist; cmBeatHist* cmBeatHistAlloc( cmCtx* c, cmBeatHist* p, unsigned frmCnt ); cmRC_t cmBeatHistFree( cmBeatHist** pp ); cmRC_t cmBeatHistInit( cmBeatHist* p, unsigned frmCnt ); cmRC_t cmBeatHistFinal( cmBeatHist* p ); cmRC_t cmBeatHistExec( cmBeatHist* p, cmSample_t df ); cmRC_t cmBeatHistCalc( cmBeatHist* p ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmGmm file_desc"Gaussian Mixture Model containing N Gaussian PDF's each of dimension D." kw:[proc model]} typedef struct { cmObj obj; unsigned K; // count of components unsigned D; // dimensionality of each component cmReal_t* gV; // gM[ K ] mixture gain vector cmReal_t* uM; // uM[ D x K ] component mean column vectors cmReal_t* sMM; // sMM[D x D x K ] component covariance matrices - each column is a DxD matrix cmReal_t* isMM; // isMM[D x D x K] inverted covar matrices cmReal_t* uMM; // uMM[ D x D x K] upper triangle factor of chol(sMM) cmReal_t* logDetV;// detV[ K ] determinent of covar matrices cmReal_t* t; // t[ D x D ]scratch matrix used for training unsigned uflags; // user defined flags } cmGmm_t; enum { cmMdgNoFlags=0x0, cmGmmDiagFl=0x01, cmGmmSkipKmeansFl=0x02 }; cmGmm_t* cmGmmAlloc( cmCtx* c, cmGmm_t* p, unsigned N, unsigned D, const cmReal_t* gV, const cmReal_t* uM, const cmReal_t* sMM, unsigned flags ); cmRC_t cmGmmFree( cmGmm_t** pp ); cmRC_t cmGmmInit( cmGmm_t* p, unsigned N, unsigned D, const cmReal_t* gV, const cmReal_t* uM, const cmReal_t* sMM, unsigned flags ); cmRC_t cmGmmFinal( cmGmm_t* p ); // Estimate the parameters of the GMM using the training data in xM[p->D,xN]. // *iterCntPtr on input is the number of iterations with no change in class assignment to signal convergence. // *iterCntPtr on output is the total number of interations required to converge. cmRC_t cmGmmTrain( cmGmm_t* p, const cmReal_t* xM, unsigned xN, unsigned* iterCntPtr ); // Return a pointer to the feature vector at frmIdx containing D elements. typedef const cmReal_t* (*cmGmmReadFunc_t)( void* userPtr, unsigned colIdx ); // Same as cmGmmTrain() but uses a function to access the feature vector. // The optional matrix uM[D,K] contains the initial mean values or NULL if not used. // The optional flag array roFlV[K] is used to indicate read-only components and is only used // when the uM[] arg. is non-NULL. Set roFlV[i] to true to indicate that the mean value supplied by // the uM[] arg. should not be alterned by the training process. // If 'maxIterCnt' is positive then it is the maximum number of iterations the training process will make // otherwise it is ignored. cmRC_t cmGmmTrain2( cmGmm_t* p, cmGmmReadFunc_t readFunc, void* userFuncPtr, unsigned xN, unsigned* iterCntPtr, const cmReal_t* uM, const bool* roFlV, int maxIterCnt ); // Generate data yN data points from the GMM and store the result in yM[p->D,yN]. cmRC_t cmGmmGenerate( cmGmm_t* p, cmReal_t* yM, unsigned yN ); // Evaluate the probability of each column of xM[p->D,xN] and return the result in y[xN]. // If yM[xN,K] is non-NULL then the individual component prob. values are returned cmRC_t cmGmmEval( cmGmm_t* p, const cmReal_t* xM, unsigned xN, cmReal_t* yV, cmReal_t* yM); // Same as cmGmmEval() but uses a a function to access each data vector cmRC_t cmGmmEval2( cmGmm_t* p, cmGmmReadFunc_t readFunc, void* userFuncPtr, unsigned xN, cmReal_t* yV, cmReal_t* yM); // 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 ); void cmGmmPrint( cmGmm_t* p, bool detailsFl ); void cmGmmTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmChmm file_desc:"Continuous Hidden Markov Model" kw:[proc model]} typedef struct { cmObj obj; unsigned N; // count of states unsigned K; // count of components per mixture unsigned D; // dimensionality of the observation data cmReal_t* iV; // iV[ N ] initial state probability mtx cmReal_t* aM; // aM[ N x N] transition probability mtx cmGmm_t** bV; // bV[ N ] observation probability mtx (array of pointers to GMM's) cmReal_t* bM; // bM[ N,T] state-observation probability matrix cmMtxFile* mfp; } cmChmm_t; // Continuous HMM consisting of stateN states where the observations // associated with each state are generated by a Gaussian mixture PDF. // stateN - count of states // mixN - count of components in the mixtures // dimN - dimensionality of the observation data cmChmm_t* cmChmmAlloc( cmCtx* c, cmChmm_t* p, unsigned stateN, unsigned mixN, unsigned dimN, const cmReal_t* iV, const cmReal_t* aM ); cmRC_t cmChmmFree( cmChmm_t** pp ); cmRC_t cmChmmInit( cmChmm_t* p, unsigned stateN, unsigned mixN, unsigned dimN, const cmReal_t* iV, const cmReal_t* aM ); cmRC_t cmChmmFinal( cmChmm_t* p ); // Set the iV,aM and bV parameters to well-formed random values. cmRC_t cmChmmRandomize( cmChmm_t* p, const cmReal_t* oM, unsigned T ); // Train the HMM using segmental k-means to initialize the model parameters. // threshProb is the min change in fit between the data and the model above which the procedure will continue to iterate. // maxIterCnt is the maximum number of iterations the algorithm will make without regard for threshProb. // iterCnt is the value of iterCnt used in the call cmChmmTrain() on each iteration cmRC_t cmChmmSegKMeans( cmChmm_t* p, const cmReal_t* oM, unsigned T, cmReal_t threshProb, unsigned maxIterCnt, unsigned iterCnt ); cmRC_t cmChmmSetGmm( cmChmm_t* p, unsigned i, const cmReal_t* wV, const cmReal_t* uM, const cmReal_t* sMM, unsigned flags ); // oM[D,T] - observation matrix // alphaM[N,T] - prob of being in each state and observtin oM(:,t) // 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 ); void cmChmmBackward( const cmChmm_t* p, const cmReal_t* oM, unsigned T, cmReal_t* betaM ); // bM[N,T] the state-observation probability table is optional cmReal_t cmChmmCompare( const cmChmm_t* p0, const cmChmm_t* p1, unsigned T ); // Generate a series of observations. // oM[ p->D , T ] - output matrix // sV[ T ] - optional vector to record the state used to generate the ith observation. cmRC_t cmChmmGenerate( const cmChmm_t* p, cmReal_t* oM, unsigned T, unsigned* sV ); // Infer the HMM parameters (p->iV,p->aM,p->bV) from the observations oM[D,T] enum { kNoTrainMixCoeffChmmFl=0x01, kNoTrainMeanChmmFl=0x02, kNoTrainCovarChmmFl=0x04 }; cmRC_t cmChmmTrain( cmChmm_t* p, const cmReal_t* oM, unsigned T, unsigned iterCnt, cmReal_t thresh, unsigned flags ); // Determine the ML state sequence yV[T] given the observations oM[D,T]. cmRC_t cmChmmDecode( cmChmm_t* p, const cmReal_t* oM, unsigned T, unsigned* yV ); void cmChmmPrint( cmChmm_t* p ); void cmChmmTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); //------------------------------------------------------------------------------------------------------------ //) //( { label:cmChord file_desc:"HMM based chord recognizer." kw:[proc]} typedef struct { cmObj obj; cmChmm_t* h; // hmm unsigned N; // state count N=24 unsigned D; // data dimension D=12 unsigned S; // tonal space dim S=6 unsigned T; // frames in chromaM cmReal_t* iV; // iV[N] cmReal_t* aM; // aM[N,N] cmReal_t* uM; // uM[D,N] cmReal_t* sMM; // sMM[D*D,N] cmReal_t* phiM; // phiM[S,T] cmReal_t* chromaM; // chromaM[D,T] cmReal_t* tsM; // tsM[S,T] cmReal_t* cdtsV; // cdts[1,T] cmReal_t triadSeqMode; cmReal_t triadSeqVar; cmReal_t triadIntMean; cmReal_t triadIntVar; cmReal_t* tsMeanV; // tsMeanV[S]; cmReal_t* tsVarV; // tsVarV[S] cmReal_t cdtsMean; cmReal_t cdtsVar; } cmChord; cmChord* cmChordAlloc( cmCtx* c, cmChord* p, const cmReal_t* chromaM, unsigned T ); cmRC_t cmChordFree( cmChord** p ); cmRC_t cmChordInit( cmChord* p, const cmReal_t* chromaM, unsigned T ); cmRC_t cmChordFinal( cmChord* p ); void cmChordTest( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); //------------------------------------------------------------------------------------------------------------ //) #ifdef __cplusplus } #endif #endif