From c734464b0ef1c9b03921f6e44a88c3eaaf1a97c9 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Fri, 29 May 2015 11:21:16 -0700 Subject: [PATCH 01/19] cmAudioPort.c : cmApTest() now accepts sample rate as a command line arg.. --- cmAudioPort.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmAudioPort.c b/cmAudioPort.c index c4bc94f..8237887 100644 --- a/cmAudioPort.c +++ b/cmAudioPort.c @@ -363,6 +363,8 @@ void cmApReport( cmRpt_t* rpt ) } } + + //cmApAlsaDeviceReport(rpt); } /// [cmAudioPortExample] @@ -668,6 +670,7 @@ int cmApPortTest( bool runFl, cmRpt_t* rpt, int argc, const char* argv[] ) runFl = _cmApGetOpt(argc,argv,"-p",!runFl,true)?false:true; + r.srate = _cmApGetOpt(argc,argv,"-r",44100,false); r.chIdx = _cmApGetOpt(argc,argv,"-a",0,false); r.chCnt = _cmApGetOpt(argc,argv,"-c",2,false); r.bufCnt = _cmApGetOpt(argc,argv,"-b",3,false); @@ -685,7 +688,6 @@ int cmApPortTest( bool runFl, cmRpt_t* rpt, int argc, const char* argv[] ) r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",2,false); r.phase = 0; r.frqHz = 2000; - r.srate = 44100; r.bufInIdx = 0; r.bufOutIdx = 0; r.bufFullCnt = 0; From ba5cd463f0387255885b9c05b2a0f6f2ab17aa49 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Fri, 29 May 2015 11:22:44 -0700 Subject: [PATCH 02/19] cmProc2.h : Changed name of cmFIRTest() to cmFIRTest0(). Added cmFIRTest1(). --- cmProc2.c | 37 ++++++++++++++++++++++++++++++++++--- cmProc2.h | 7 ++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/cmProc2.c b/cmProc2.c index cf51911..7bc4051 100644 --- a/cmProc2.c +++ b/cmProc2.c @@ -823,7 +823,7 @@ cmRC_t cmFIRInitKaiser( cmFIR* p, unsigned procSmpCnt, double srate, double pass // in practice the ripple must be equal in the stop and pass band - so take the minimum between the two double d = cmMin(dPass,dStop); - // convert the ripple bcmk to db + // convert the ripple back to db double A = -20 * log10(d); // compute the kaiser alpha coeff @@ -914,7 +914,7 @@ cmRC_t cmFIRExec( cmFIR* p, const cmSample_t* sbp, unsigned sn ) // calc the output sample while( cbpoutV, 1, f->outN ); + cmVectArrayWriteMatrixS(ctx, sfn, x, 1, N ); + + cmFIRFree(&f); + +} + //------------------------------------------------------------------------------------------------------------ diff --git a/cmProc2.h b/cmProc2.h index 169c594..5f52342 100644 --- a/cmProc2.h +++ b/cmProc2.h @@ -190,8 +190,9 @@ extern "C" { cmRC_t cmFIRInitSinc( cmFIR* p, unsigned procSmpCnt, double srate, unsigned sincSmpCnt, double fcHz, unsigned flags, const double* wndV ); cmRC_t cmFIRFinal( cmFIR* p ); cmRC_t cmFIRExec( cmFIR* p, const cmSample_t* sp, unsigned sn ); - void cmFIRTest(); - + void cmFIRTest0( cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH ); + void cmFIRTest1( cmCtx* ctx ); + //------------------------------------------------------------------------------------------------------------ // Apply a generic function to a windowed signal with a one sample hop size. @@ -771,7 +772,7 @@ extern "C" { //------------------------------------------------------------------------------------------------------------ - // cmVectArray buffers row vectors of arbitrary lenght in memory. + // cmVectArray buffers row vectors of arbitrary length in memory. // The buffers may then be access using the cmVectArrayGetXXX() functions. // The entire contents of the file may be written to a file using atVectArrayWrite(). // The file may then be read in back into memory using cmVectArrayAllocFromFile() From f48cc2e7f772156907b0bc7e72069dd05abf4124 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Fri, 29 May 2015 11:49:29 -0700 Subject: [PATCH 03/19] cmAudioPortAlsa.c : Added _cmApDevReportFormats(). Added, but disabled, _cmApS24_3BE*(). Added i/oSignFl and i/oSwapFl to device record. Changed sample format selection algorithm to use fmt[]. --- linux/cmAudioPortAlsa.c | 166 ++++++++++++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 22 deletions(-) diff --git a/linux/cmAudioPortAlsa.c b/linux/cmAudioPortAlsa.c index 35b9a2c..fb2435a 100644 --- a/linux/cmAudioPortAlsa.c +++ b/linux/cmAudioPortAlsa.c @@ -40,11 +40,17 @@ typedef struct devRecd_str snd_async_handler_t* ahandler; unsigned srate; // device sample rate - unsigned iChCnt; // ch count + unsigned iChCnt; // ch count unsigned oChCnt; unsigned iBits; // bits per sample - unsigned oBits; + unsigned oBits; + + bool iSignFl; // sample type is signed + bool oSignFl; + + bool iSwapFl; // swap the sample bytes + bool oSwapFl; unsigned iSigBits; // significant bits in each sample beginning unsigned oSigBits; // with the most sig. bit. @@ -362,6 +368,77 @@ void _cmApDevRtReport( cmRpt_t* rpt, cmApDevRecd_t* drp ) } +void _cmApDevReportFormats( cmRpt_t* rpt, snd_pcm_hw_params_t* hwParams ) +{ + snd_pcm_format_mask_t* mask; + + snd_pcm_format_t fmt[] = + { + SND_PCM_FORMAT_S8, + SND_PCM_FORMAT_U8, + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_U16_LE, + SND_PCM_FORMAT_U16_BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_S24_BE, + SND_PCM_FORMAT_U24_LE, + SND_PCM_FORMAT_U24_BE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_U32_LE, + SND_PCM_FORMAT_U32_BE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_FLOAT64_LE, + SND_PCM_FORMAT_FLOAT64_BE, + SND_PCM_FORMAT_IEC958_SUBFRAME_LE, + SND_PCM_FORMAT_IEC958_SUBFRAME_BE, + SND_PCM_FORMAT_MU_LAW, + SND_PCM_FORMAT_A_LAW, + SND_PCM_FORMAT_IMA_ADPCM, + SND_PCM_FORMAT_MPEG, + SND_PCM_FORMAT_GSM, + SND_PCM_FORMAT_SPECIAL, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_U24_3LE, + SND_PCM_FORMAT_U24_3BE, + SND_PCM_FORMAT_S20_3LE, + SND_PCM_FORMAT_S20_3BE, + SND_PCM_FORMAT_U20_3LE, + SND_PCM_FORMAT_U20_3BE, + SND_PCM_FORMAT_S18_3LE, + SND_PCM_FORMAT_S18_3BE, + SND_PCM_FORMAT_U18_3LE, + SND_PCM_FORMAT_U18_3BE, + SND_PCM_FORMAT_G723_24, + SND_PCM_FORMAT_G723_24_1B, + SND_PCM_FORMAT_G723_40, + SND_PCM_FORMAT_G723_40_1B, + SND_PCM_FORMAT_DSD_U8, + //SND_PCM_FORMAT_DSD_U16_LE, + //SND_PCM_FORMAT_DSD_U32_LE, + //SND_PCM_FORMAT_DSD_U16_BE, + //SND_PCM_FORMAT_DSD_U32_BE, + SND_PCM_FORMAT_UNKNOWN + }; + + snd_pcm_format_mask_alloca(&mask); + + snd_pcm_hw_params_get_format_mask(hwParams,mask); + + cmRptPrintf(rpt,"Formats: " ); + + int i; + for(i=0; fmt[i]!=SND_PCM_FORMAT_UNKNOWN; ++i) + if( snd_pcm_format_mask_test(mask, fmt[i] )) + cmRptPrintf(rpt,"%s%s",snd_pcm_format_name(fmt[i]), snd_pcm_format_cpu_endian(fmt[i]) ? " " : " (swap) "); + + cmRptPrintf(rpt,"\n"); + +} + void _cmApDevReport( cmRpt_t* rpt, cmApDevRecd_t* drp ) { bool inputFl = true; @@ -377,7 +454,7 @@ void _cmApDevReport( cmRpt_t* rpt, cmApDevRecd_t* drp ) { if( ((inputFl==true) && (drp->flags&kInFl)) || (((inputFl==false) && (drp->flags&kOutFl)))) { - const char* ioLabel = inputFl ? "In" : "Out"; + const char* ioLabel = inputFl ? "In " : "Out"; // attempt to open the sub-device if((err = snd_pcm_open(&pcmH,drp->nameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 ) @@ -435,6 +512,8 @@ void _cmApDevReport( cmRpt_t* rpt, cmApDevRecd_t* drp ) ioLabel,minChCnt,maxChCnt,minSrate,maxSrate,minPeriodFrmCnt,maxPeriodFrmCnt,minBufFrmCnt,maxBufFrmCnt, (snd_pcm_hw_params_is_half_duplex(hwParams) ? "yes" : "no"), (snd_pcm_hw_params_is_joint_duplex(hwParams) ? "yes" : "no")); + + _cmApDevReportFormats( rpt, hwParams ); } if((err = snd_pcm_close(pcmH)) < 0) @@ -610,6 +689,28 @@ void _cmApStateRecover( snd_pcm_t* pcmH, cmApDevRecd_t* drp, bool inputFl ) } +void _cmApS24_3BE_to_Float( const char* x, cmApSample_t* y, unsigned n ) +{ + unsigned i; + for(i=0; i> 16); + y[i*3+1] = (char)((s & 0x00ff00) >> 8); + y[i*3+0] = (char)((s & 0x0000ff) >> 0); + } +} + // Returns count of frames written on success or < 0 on error; // set smpPtr to NULL to write a buffer of silence @@ -648,9 +749,13 @@ int _cmApWriteBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, const cmApSample_t* sp, case 24: { + // for use w/ MBox + //_cmApS24_3BE_from_Float(sp, obuf, ep-sp ); + int* dp = (int*)obuf; while( sp < ep ) *dp++ = (int)(*sp++ * 0x7fffff); + } break; @@ -696,7 +801,6 @@ int _cmApWriteBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, const cmApSample_t* sp, } - // Returns frames read on success or < 0 on error. // Set smpPtr to NULL to read the incoming buffer and discard it int _cmApReadBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, cmApSample_t* smpPtr, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits ) @@ -729,7 +833,6 @@ int _cmApReadBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, cmApSample_t* smpPtr, uns // setup the return buffer cmApSample_t* dp = smpPtr; - cmApSample_t* ep = dp + cmMin(smpCnt,err*chCnt); switch(bits) @@ -752,6 +855,8 @@ int _cmApReadBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, cmApSample_t* smpPtr, uns case 24: { + // For use with MBox + //_cmApS24_3BE_to_Float(buf, dp, ep-dp ); int* sp = (int*)buf; while(dp < ep) *dp++ = ((cmApSample_t)*sp++) / 0x7fffff; @@ -819,7 +924,7 @@ void _cmApStaticAsyncHandler( snd_async_handler_t* ahandler ) while( (avail = snd_pcm_avail_update(pcmH)) >= (snd_pcm_sframes_t)frmCnt ) { - // Handle inpuut + // Handle input if( inputFl ) { // read samples from the device @@ -1024,7 +1129,21 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, snd_pcm_uframes_t bufferFrameCnt; unsigned bits = 0; int sig_bits = 0; + bool signFl = true; + bool swapFl = false; cmApRoot_t* p = drp->rootPtr; + + snd_pcm_format_t fmt[] = + { + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_S24_BE, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S16_BE, + }; // setup input, then output device @@ -1041,7 +1160,6 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, if( _cmApDevShutdown(p, drp, inputFl ) != kOkApRC ) retFl = false; - // attempt to open the sub-device if((err = snd_pcm_open(&pcmH,drp->nameStr, inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)) < 0 ) retFl = _cmApDevSetupError(p,err,inputFl,drp,"Unable to open the PCM handle"); @@ -1075,23 +1193,23 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, if((err = snd_pcm_hw_params_set_access(pcmH,hwParams,SND_PCM_ACCESS_RW_INTERLEAVED )) < 0 ) retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set access to: RW Interleaved"); - - // select the widest possible sample width - if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S32)) >= 0 ) - bits = 32; + + // select the format width + int j; + int fmtN = sizeof(fmt)/sizeof(fmt[0]); + for(j=0; j= 0 ) + break; + + if( j == fmtN ) + retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set format to: S16"); else { - if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S24)) >= 0 ) - bits = 24; - else - { - if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S16)) >= 0 ) - bits = 16; - else - retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set format to: S16"); - } + bits = snd_pcm_format_width(fmt[j]); // bits per sample + signFl = snd_pcm_format_signed(fmt[j]); + swapFl = !snd_pcm_format_cpu_endian(fmt[j]); } - + sig_bits = snd_pcm_hw_params_get_sbits(hwParams); snd_pcm_uframes_t ps_min,ps_max; @@ -1167,6 +1285,8 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, { drp->iBits = bits; drp->iSigBits = sig_bits; + drp->iSignFl = signFl; + drp->iSwapFl = swapFl; drp->iPcmH = pcmH; drp->iBuf = cmMemResizeZ( cmApSample_t, drp->iBuf, actFpC * drp->iChCnt ); drp->iFpC = actFpC; @@ -1175,6 +1295,8 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, { drp->oBits = bits; drp->oSigBits = sig_bits; + drp->oSignFl = signFl; + drp->oSwapFl = swapFl; drp->oPcmH = pcmH; drp->oBuf = cmMemResizeZ( cmApSample_t, drp->oBuf, actFpC * drp->oChCnt ); drp->oFpC = actFpC; @@ -1448,7 +1570,7 @@ cmApRC_t cmApAlsaInitialize( cmRpt_t* rpt, unsigned baseApDevIdx ) // this device uses this subdevice in the current direction dr.flags += inputFl ? kInFl : kOutFl; - printf("%s in:%i chs:%i rate:%i\n",dr.nameStr,inputFl,*chCntPtr,rate); + //printf("%s in:%i chs:%i rate:%i\n",dr.nameStr,inputFl,*chCntPtr,rate); } From 346915b450ca17c226b1f297fb76e54a1dd772b4 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 1 Jun 2015 12:50:32 -0400 Subject: [PATCH 04/19] cmProc.c: Chnaged labs() to fabs() in calc of 'dLogProb' in cmChmmTrain(). --- cmProc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmProc.c b/cmProc.c index 1d167a1..8531a04 100644 --- a/cmProc.c +++ b/cmProc.c @@ -4393,7 +4393,7 @@ cmRC_t cmChmmTrain( cmChmm_t* p, const cmReal_t* oM, unsigned T, unsigned ite 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); + cmReal_t dLogProb = fabs(logProb0-logProb) / ((fabs(logProb0)+fabs(logProb)+cmReal_EPSILON)/2); if( dLogProb < thresh ) break; From cc5aade9689c1e97a9ea18784d0e9de748eb4be7 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 1 Jun 2015 12:51:18 -0400 Subject: [PATCH 05/19] cmProc2.c : changes abs() to fabsf() in cmExpanderExec(). --- cmProc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmProc2.c b/cmProc2.c index 7bc4051..55c7406 100644 --- a/cmProc2.c +++ b/cmProc2.c @@ -5711,7 +5711,7 @@ cmRC_t cmExpanderExec( cmExpander* p, cmSample_t* x, cmSample_t* y, unsigne for(i=0; irmsV[p->rmsIdx] = abs(x[i]); + p->rmsV[p->rmsIdx] = fabsf(x[i]); if( ++p->rmsIdx >= p->rmsN ) p->rmsIdx = 0; From 2e815b6046e4ae47e5bca62f7c3ad31ca0724287 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Mon, 8 Jun 2015 09:13:41 -0700 Subject: [PATCH 06/19] cmProc2.h/c : Fixed bug in _cmVectArrayWriteMatrix() which caused the resulting file to be misformatted. Added dcumenation to cmVectArray. --- cmProc2.c | 2 +- cmProc2.h | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/cmProc2.c b/cmProc2.c index 55c7406..ab9f6e2 100644 --- a/cmProc2.c +++ b/cmProc2.c @@ -4085,7 +4085,7 @@ cmRC_t _cmVectArrayWriteMatrix( cmCtx* ctx, const char* fn, unsigned flags, cons memcpy(vv + ci*tbc, v + ci*rn*tbc, tbc ); // append the row to the VectArray - if((rc = cmVectArrayAppendV(p,v,cn)) != cmOkRC ) + if((rc = cmVectArrayAppendV(p,vv,cn)) != cmOkRC ) { rc = cmCtxRtCondition(&p->obj,rc,"Vector append failed in %s().",__FUNCTION__); goto errLabel; diff --git a/cmProc2.h b/cmProc2.h index 5f52342..206c598 100644 --- a/cmProc2.h +++ b/cmProc2.h @@ -838,8 +838,12 @@ extern "C" { unsigned cmVectArrayMaxRowCount( const cmVectArray_t* p ); // Store a new vector by appending it to the end of the internal vector list. - // Note that the true type of v[] in the call to cmVectArrayAppendV() must match + // Note: + // 1. The true type of v[] in the call to cmVectArrayAppendV() must match // the data type set in p->flags. + // 2. The 'vn' argument to atVectArrayAppendV() is an element count not + // a byte count. The size of each element is determined by the data type + // as set by atVectArrayAlloc(). cmRC_t cmVectArrayAppendV( cmVectArray_t* p, const void* v, unsigned vn ); cmRC_t cmVectArrayAppendS( cmVectArray_t* p, const cmSample_t* v, unsigned vn ); cmRC_t cmVectArrayAppendR( cmVectArray_t* p, const cmReal_t* v, unsigned vn ); @@ -858,8 +862,12 @@ extern "C" { unsigned cmVectArrayForEachS( cmVectArray_t* p, unsigned idx, unsigned cnt, cmVectArrayForEachFuncS_t func, void* arg ); // Write the vector v[vn] in the VectArray file format. - // Note that the true type of v[] in cmVectArrayWriteVectoV() must match the + // Note: + // 1. The true type of v[] in cmVectArrayWriteVectoV() must match the // data type set in the 'flags' parameter. + // 2. The 'vn' argument to atVectArrayWriteVectorV() is an element count not + // a byte count. The size of each element is determined by the data type + // as set by atVectArrayAlloc(). cmRC_t cmVectArrayWriteVectorV( cmCtx* ctx, const char* fn, const void* v, unsigned vn, unsigned flags ); cmRC_t cmVectArrayWriteVectorS( cmCtx* ctx, const char* fn, const cmSample_t* v, unsigned vn ); cmRC_t cmVectArrayWriteVectorR( cmCtx* ctx, const char* fn, const cmReal_t* v, unsigned vn ); @@ -869,8 +877,12 @@ extern "C" { cmRC_t cmVectArrayWriteVectorU( cmCtx* ctx, const char* fn, const unsigned* v, unsigned vn ); // Write the column-major matrix m[rn,cn] to the file 'fn'. - // Note that the true type of m[] in cmVectArrayWriteMatrixV() must match the + // Notes: + // 1. The true type of m[] in cmVectArrayWriteMatrixV() must match the // data type set in the 'flags' parameter. + // 2. The 'rn','cn' arguments to atVectWriteMatrixV() is are element counts not + // byte counts. The size of each element is determined by the data type + // as set by atVectArrayAlloc(). cmRC_t cmVectArrayWriteMatrixV( cmCtx* ctx, const char* fn, const void* m, unsigned rn, unsigned cn, unsigned flags ); cmRC_t cmVectArrayWriteMatrixS( cmCtx* ctx, const char* fn, const cmSample_t* m, unsigned rn, unsigned cn ); cmRC_t cmVectArrayWriteMatrixR( cmCtx* ctx, const char* fn, const cmReal_t* m, unsigned rn, unsigned cn ); From 2f95f6f329b70e51ca1a18b4d75965f5e705bcdf Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 26 Jun 2015 18:54:47 -0400 Subject: [PATCH 07/19] cmProc2.c : Removed use of oSpecVa from cmDspSpecDist. --- cmProc2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmProc2.c b/cmProc2.c index ab9f6e2..b5fb3d9 100644 --- a/cmProc2.c +++ b/cmProc2.c @@ -5691,7 +5691,7 @@ cmRC_t cmExpanderInit( cmExpander* p, p->envV[atkN+i] = p->rlsLvl + (G*i/rlsN); } - printf("rmsN:%i atkN:%i rlsN:%i thr:%f %f rls:%f %f\n",p->rmsN,atkN,rlsN,threshDb,p->threshLvl,rlsDb,p->rlsLvl); + //printf("rmsN:%i atkN:%i rlsN:%i thr:%f %f rls:%f %f\n",p->rmsN,atkN,rlsN,threshDb,p->threshLvl,rlsDb,p->rlsLvl); //for(i=0; ienvN; ++i) // printf("%i %f\n",i,p->envV[i]); @@ -5941,7 +5941,7 @@ cmSpecDist_t* cmSpecDistAlloc( cmCtx* ctx,cmSpecDist_t* ap, unsigned procSmpCnt, cmSpecDist_t* p = cmObjAlloc( cmSpecDist_t, ctx, ap ); //p->iSpecVa = cmVectArrayAlloc(ctx,kRealVaFl); - p->oSpecVa = cmVectArrayAlloc(ctx,kRealVaFl); + //p->oSpecVa = cmVectArrayAlloc(ctx,kRealVaFl); if( procSmpCnt != 0 ) { @@ -5962,7 +5962,7 @@ cmRC_t cmSpecDistFree( cmSpecDist_t** pp ) cmSpecDistFinal(p); //cmVectArrayFree(&p->iSpecVa); - cmVectArrayFree(&p->oSpecVa); + //cmVectArrayFree(&p->oSpecVa); cmMemPtrFree(&p->hzV); cmMemPtrFree(&p->iSpecM); cmMemPtrFree(&p->oSpecM); @@ -6086,7 +6086,7 @@ cmRC_t cmSpecDistFinal(cmSpecDist_t* p ) cmRC_t rc = cmOkRC; //cmVectArrayWrite(p->iSpecVa, "/home/kevin/temp/frqtrk/iSpec.va"); - cmVectArrayWrite(p->oSpecVa, "/home/kevin/temp/expand/oSpec.va"); + //cmVectArrayWrite(p->oSpecVa, "/home/kevin/temp/expand/oSpec.va"); cmPvAnlFree(&p->pva); cmPvSynFree(&p->pvs); From cead889078d05f7050ce5432a970b4cca1a4a6ca Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 26 Jun 2015 18:55:27 -0400 Subject: [PATCH 08/19] cmDspPgm.c : Added gain control to 'sine' test pgm. --- dsp/cmDspPgm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dsp/cmDspPgm.c b/dsp/cmDspPgm.c index 39a3a20..0a67855 100644 --- a/dsp/cmDspPgm.c +++ b/dsp/cmDspPgm.c @@ -334,6 +334,7 @@ cmDspRC_t _cmDspSysPgm_PlaySine( cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, useBuiltInFl ? 1 : 3 ); cmDspInst_t* om0p = cmDspSysAllocInst(h,"AMeter","Out", 0); + cmDspInst_t* gain= cmDspSysAllocInst( h,"Scalar", "Gain", 5, kNumberDuiId, 0.0, 10.0, 0.01, 0.0); cmDspSysConnectAudio(h, php, "out", wtp, "phs" ); // phasor -> wave table cmDspSysConnectAudio(h, wtp, "out", ao0p, "in" ); // wave table -> audio out @@ -341,6 +342,9 @@ cmDspRC_t _cmDspSysPgm_PlaySine( cmDspSysH_t h, void** userPtrPtr ) cmDspSysConnectAudio(h, wtp, "out", om0p, "in" ); cmDspSysInstallCb( h, chp, "val", ao0p, "ch", NULL); + cmDspSysInstallCb( h, gain, "val", ao0p, "gain", NULL); + cmDspSysInstallCb( h, gain, "val", ao1p, "gain", NULL); + return kOkDspRC; } From d22cf3aa562dbe76e6e7620848936596a2ef5dab Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 26 Jun 2015 18:56:25 -0400 Subject: [PATCH 09/19] cmDspPgmKr.c : Changed label of MidiFilePlayer 'mu' output to 'id' in 'time-line' patch. --- dsp/cmDspPgmKr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index b8ccf64..2595de4 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -382,7 +382,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmErr_t err; krRsrc_t r; bool fragFl = false; - bool useWtFl = false; + bool useWtFl = true; bool useChain1Fl = true; bool useInputEqFl = false; bool useInCompFl = true; @@ -1048,7 +1048,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, siRt, "f-out-1", sfp, "smpidx",NULL ); // leave siRt.f-out-1 unconnected because it should be ignored in 'simulate mode' - cmDspSysInstallCb(h, mfp, "mu", muRt, "f-in", NULL ); + cmDspSysInstallCb(h, mfp, "id", muRt, "f-in", NULL ); cmDspSysInstallCb(h, muRt, "f-out-1", sfp, "muid", NULL ); // leave muRt.f-out-1 unconnected because it should be ignored in 'simulate mode' From c262a44e7290ac7db6e7923475e6e1db54f2eb22 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 26 Jun 2015 18:57:18 -0400 Subject: [PATCH 10/19] cmDspKr.c : Changed error message to warning in _cmDspRecdPlayParseRsrc(). --- dsp/cmDspKr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsp/cmDspKr.c b/dsp/cmDspKr.c index 19df767..3b0ff10 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -2534,7 +2534,7 @@ cmDspRC_t _cmDspRecdPlayParseRsrc( cmDspCtx_t* ctx, cmDspInst_t* inst, cmRecdPla if( jnp == NULL || cmJsonIsArray(jnp)==false ) { // this is really a warning - the object does not require preloaded segments. - cmDspInstErr(ctx,inst,kRsrcNotFoundDspRC,"The 'recdPlay' resource used to define pre-loaded segments was not found."); + cmDspInstErr(ctx,inst,kRsrcNotFoundDspRC,"Warning: The 'recdPlay' resource used to define pre-loaded segments was not found."); return kOkDspRC; } From 032d359a90d51ade7c3311bc1960aaf3b645f3a3 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 3 Jul 2015 12:36:27 -0400 Subject: [PATCH 11/19] cmMath.h/c : Added cmLFSR() and cmGenGoldCode(). --- cmMath.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- cmMath.h | 37 ++++++++++++++++ 2 files changed, 166 insertions(+), 2 deletions(-) diff --git a/cmMath.c b/cmMath.c index 028354e..f740b1b 100644 --- a/cmMath.c +++ b/cmMath.c @@ -1,5 +1,10 @@ #include "cmPrefix.h" #include "cmGlobal.h" +#include "cmRpt.h" +#include "cmErr.h" +#include "cmCtx.h" +#include "cmMem.h" +#include "cmMallocDebug.h" #include "cmFloatTypes.h" #include "cmMath.h" #include // u_char @@ -464,6 +469,128 @@ bool cmIsCloseU( unsigned x0, unsigned x1, double eps ) { if( x0 == x1 ) return true; - - return abs(x0-x1)/(x0+x1) < eps; + if( x0 > x1 ) + return (x0-x1)/(x0+x1) < eps; + else + return (x1-x0)/(x0+x1) < eps; +} + +//================================================================= + +// cmLFSR() implementation based on note at bottom of: +// http://www.ece.cmu.edu/~koopman/lfsr/index.html +void cmLFSR( unsigned lfsrN, unsigned tapMask, unsigned seed, unsigned* yV, unsigned yN ) +{ + assert( 0 < lfsrN && lfsrN < 32 ); + + unsigned i; + for(i=0; i> 1) ^ tapMask; + else + seed = (seed >> 1); + + } +} + +bool cmMLS_IsBalanced( const unsigned* xV, int xN) +{ + int a = 0; + unsigned i; + + for(i=0; ilfsrN) - 1. +// Note that values of 'lfsrN' and the 'poly_coeffx' must be carefully selected such that +// they will produce a MLS. For example to generate a MLS with length 31 set 'lfsrN' to 5 and +// then select poly_coeff from two different elements of the set {0x12 0x14 0x17 0x1B 0x1D 0x1E}. +// See http://www.ece.cmu.edu/~koopman/lfsr/index.html for a complete set of MSL polynomial +// coefficients for given LFSR lengths. +// Returns false if insufficient balanced pairs exist. +bool cmGenGoldCodes( unsigned lfsrN, unsigned poly_coeff0, unsigned poly_coeff1, unsigned goldN, int* yM, unsigned mlsN ); + #endif From b1ff1dfb078317cc16045aa140eec1bd8a950e70 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 3 Jul 2015 12:36:54 -0400 Subject: [PATCH 12/19] cmProc5.h/c : Added cmGoldCode. --- cmProc5.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmProc5.h | 69 +++++++++++++++++ 2 files changed, 289 insertions(+) diff --git a/cmProc5.c b/cmProc5.c index beaf543..22c6324 100644 --- a/cmProc5.c +++ b/cmProc5.c @@ -16,7 +16,11 @@ #include "cmProcObj.h" #include "cmProcTemplate.h" #include "cmMath.h" +#include "cmFile.h" +#include "cmTime.h" +#include "cmMidi.h" #include "cmProc.h" +#include "cmProc2.h" #include "cmProc5.h" #include "cmVectOps.h" @@ -123,3 +127,219 @@ cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* inpV, unsigned procSmpCn } +//======================================================================================================================= +double _cmGoldSigSinc( double t, double T ) +{ + double x = t/T; + return x == 0 ? 1.0 : sin(M_PI*x)/(M_PI*x); +} + +void _cmGoldSigRaisedCos( cmSample_t* yV, int yN, double sPc, double beta ) +{ + int i; + + for(i=0; ia.samplesPerChip; + int osf = p->a.rcosOSFact; + + // for each bit in the spreading-code + for(i=0; imlsN; ++i) + { + int j = (i*sPc) + sPc/2; // index into bbV[] of center of impulse response + int k = j - (sPc*osf)/2; // index into bbV[] of start of impulse response + int h; + + // for each sample in the impulse response + for(h=0; hrcosN; ++h,++k) + { + + while( k<0 ) + k += p->sigN; + + while( k>=p->sigN ) + k -= p->sigN; + + p->ch[chIdx].bbV[k] += p->ch[chIdx].pnV[i] * p->rcosV[h]; + } + } +} + +void _cmGoldSigModulate( cmGoldSig_t* p, unsigned chIdx ) +{ + unsigned i; + double rps = 2.0 * M_PI * p->a.carrierHz / p->a.srate; + cmSample_t* yV = p->ch[chIdx].mdV; + cmSample_t* bbV = p->ch[chIdx].bbV; + + for(i=0; isigN; ++i) + yV[ i ] = bbV[i]*cos(rps*i) + bbV[i]*sin(rps*i); + + // apply a half Hann envelope to the onset/offset of the id signal + if( p->a.envMs > 0 ) + { + unsigned wndMs = p->a.envMs * 2; + unsigned wndN = wndMs * p->a.srate / 1000; + wndN += wndN % 2 ? 0 : 1; // force the window length to be odd + unsigned wNo2 = wndN/2 + 1; + cmSample_t wndV[ wndN ]; + cmVOS_Hann(wndV,wndN); + cmVOS_MultVV(yV,wNo2,wndV); + cmVOS_MultVV(yV + p->sigN - wNo2, wNo2, wndV + wNo2 - 1); + } + +} + +cmGoldSig_t* cmGoldSigAlloc( cmCtx* ctx, cmGoldSig_t* p, const cmGoldSigArg_t* a ) +{ + cmGoldSig_t* op = cmObjAlloc(cmGoldSig_t,ctx,p); + + if( a != NULL ) + if( cmGoldSigInit(op,a) != cmOkRC ) + cmGoldSigFree(&op); + + return op; + +} + +cmRC_t cmGoldSigFree( cmGoldSig_t** pp ) +{ + cmRC_t rc = cmOkRC; + + if( pp == NULL || *pp == NULL ) + return rc; + + cmGoldSig_t* p = *pp; + + if((rc = cmGoldSigFinal(p)) != cmOkRC ) + return rc; + + unsigned i; + for(i=0; ia.chN; ++i) + { + cmMemFree(p->ch[i].bbV); + cmMemFree(p->ch[i].mdV); + } + + cmMemFree(p->ch); + cmMemFree(p->rcosV); + cmMemFree(p->pnM); + cmMemFree(p); + *pp = NULL; + + return rc; +} + +cmRC_t cmGoldSigInit( cmGoldSig_t* p, const cmGoldSigArg_t* a ) +{ + cmRC_t rc = cmOkRC; + unsigned i; + + p->a = *a; // store arg recd + p->ch = cmMemResizeZ(cmGoldSigCh_t,p->ch,a->chN); // alloc channel array + p->mlsN = (1 << a->lfsrN) - 1; // calc spreading code length + p->rcosN = a->samplesPerChip * a->rcosOSFact; // calc rcos imp. resp. length + p->rcosN += (p->rcosN % 2)==0; // force rcos imp. length odd + p->rcosV = cmMemResizeZ(cmSample_t,p->rcosV,p->rcosN); // alloc rcos imp. resp. vector + p->pnM = cmMemResizeZ(int,p->pnM,p->mlsN*a->chN); // alloc spreading-code mtx + p->sigN = p->mlsN * a->samplesPerChip; // calc audio signal length + + // generate spreading codes + if( cmGenGoldCodes(a->lfsrN, a->mlsCoeff0, a->mlsCoeff1, a->chN, p->pnM, p->mlsN ) == false ) + { + rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Unable to generate sufficient balanced Gold codes."); + goto errLabel; + } + + // generate the rcos impulse response + _cmGoldSigRaisedCos(p->rcosV,p->rcosN,a->samplesPerChip,a->rcosBeta); + + // for each channel + for(i=0; ichN; ++i) + { + // Note: if (i*p->mlsN) is set to 0 in the following line then all channels + // will use the same spreading code. + p->ch[i].pnV = p->pnM + (i*p->mlsN); // get ch. spreading code + p->ch[i].bbV = cmMemResizeZ(cmSample_t,p->ch[i].bbV,p->sigN); // alloc baseband signal vector + p->ch[i].mdV = cmMemResizeZ(cmSample_t,p->ch[i].mdV,p->sigN); // alloc output audio vector + + // Convolve spreading code with rcos impulse reponse to form baseband signal. + _cmGoldSigConv(p, i ); + + // Modulate baseband signal to carrier frq. and apply attack/decay envelope. + _cmGoldSigModulate(p, i ); + } + + errLabel: + if((rc = cmErrLastRC(&p->obj.err)) != cmOkRC ) + cmGoldSigFree(&p); + + return rc; +} + +cmRC_t cmGoldSigFinal( cmGoldSig_t* p ) +{ return cmOkRC; } + +cmRC_t cmGoldSigWrite( cmCtx* ctx, cmGoldSig_t* p, const char* fn ) +{ + cmVectArray_t* vap = NULL; + unsigned i; + + vap = cmVectArrayAlloc(ctx,kSampleVaFl); + + for(i=0; ia.chN; ++i) + { + cmVectArrayAppendS(vap,p->ch[i].bbV,p->sigN); + cmVectArrayAppendS(vap,p->ch[i].mdV,p->sigN); + } + + cmVectArrayWrite(vap,fn); + + cmVectArrayFree(&vap); + + return cmOkRC; +} + + +cmRC_t cmGoldSigGen( cmGoldSig_t* p, unsigned chIdx, unsigned prefixN, unsigned dsN, unsigned *bsiV, unsigned bsiN, double noiseGain, cmSample_t** yVRef, unsigned* yNRef ) +{ + unsigned yN = prefixN + bsiN * (p->sigN + dsN); + cmSample_t* yV = cmMemAllocZ(cmSample_t,yN); + unsigned i; + + cmVOS_Random(yV, yN, -noiseGain, noiseGain ); + + for(i=0; isigN + dsN); + + cmVOS_AddVV(yV + bsiV[i], p->sigN, p->ch[chIdx].mdV ); + } + + if( yVRef != NULL ) + *yVRef = yV; + + if( yNRef != NULL ) + *yNRef = yN; + + return cmOkRC; +} + + + diff --git a/cmProc5.h b/cmProc5.h index 927d158..8213f98 100644 --- a/cmProc5.h +++ b/cmProc5.h @@ -39,7 +39,76 @@ extern "C" { cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* in, unsigned procSmpCnt, double* outV, unsigned chCnt ); + //======================================================================================================================= + // Gold Code Signal Generator + // + typedef struct + { + unsigned chN; // count of channels (each channel has a unique id) + double srate; // system sample rate (samples/second) + unsigned lfsrN; // linear feedback shift register (LFSR) length used to form Gold codes + unsigned mlsCoeff0; // LFSR coeff. 0 + unsigned mlsCoeff1; // LFSR coeff. 1 + unsigned samplesPerChip; // samples per spreading code bit + double rcosBeta; // raised cosine impulse response beta coeff. + unsigned rcosOSFact; // raised cosine impulse response oversample factor + double carrierHz; // carrier frequency + double envMs; // attack/decay envelope duration + } cmGoldSigArg_t; + + typedef struct + { + int* pnV; // pnV[ mlsN ] spread code (aliased from pnM[:,i]) + cmSample_t* bbV; // bbV[ sigN ] baseband signal at audio rate + cmSample_t* mdV; // mdV[ sigN ] modulated signal at audio rate + } cmGoldSigCh_t; + + typedef struct + { + cmObj obj; // + cmGoldSigArg_t a; // argument record + cmGoldSigCh_t* ch; // ch[ chN ] channel array + int* pnM; // pnM[mlsN,chN] (aliased to ch[].pnV) + cmSample_t* rcosV; // rcosV[rcosN] raised cosine impulse response + unsigned rcosN; // length of raised cosine impulse response + unsigned mlsN; // length of Gold codes (Maximum length sequence length) + unsigned sigN; // length of channel signals bbV[] and mdV[] + } cmGoldSig_t; + + + cmGoldSig_t* cmGoldSigAlloc( cmCtx* ctx, cmGoldSig_t* p, const cmGoldSigArg_t* a ); + cmRC_t cmGoldSigFree( cmGoldSig_t** pp ); + + cmRC_t cmGoldSigInit( cmGoldSig_t* p, const cmGoldSigArg_t* a ); + cmRC_t cmGoldSigFinal( cmGoldSig_t* p ); + + cmRC_t cmGoldSigWrite( cmCtx* ctx, cmGoldSig_t* p, const char* fn ); + + // Generate a signal consisting of underlying white noise with + // bsiN repeated copies of the id signal associated with + // channel 'chIdx'. Each discrete id signal copy is separated by 'dsN' samples. + // The signal will be prefixed with 'prefixN' samples of silence (noise). + // On return sets 'yVRef' to point to the generated signal and 'yNRef' + // to the count of samples in 'yVRef'. + // On error sets yVRef to NULL and yNRef to zero. + // The vector returned in 'yVRef' should be freed via atMemFree(). + // On return sets bsiV[bsiN] to the onset sample index of each id signal copy. + // The background noise signal is limited to the range -noiseGain to noiseGain. + cmRC_t cmGoldSigGen( + cmGoldSig_t* p, + unsigned chIdx, + unsigned prefixN, + unsigned dsN, + unsigned *bsiV, + unsigned bsiN, + double noiseGain, + cmSample_t** yVRef, + unsigned* yNRef ); + + cmRC_t cmGoldSigTest( cmCtx* ctx ); + + #ifdef __cplusplus } #endif From f481f7f62a5ea6ae9d197d79c9043a6bcbb2673c Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 3 Jul 2015 18:22:08 -0400 Subject: [PATCH 13/19] cmComplexTypes.h : Added complex arithmetic vector operations. --- cmComplexTypes.c | 42 ++++++++++++++++++++++++++++++++++++++++++ cmComplexTypes.h | 6 ++++++ 2 files changed, 48 insertions(+) create mode 100644 cmComplexTypes.c diff --git a/cmComplexTypes.c b/cmComplexTypes.c new file mode 100644 index 0000000..2929400 --- /dev/null +++ b/cmComplexTypes.c @@ -0,0 +1,42 @@ + + +void cmVOCR_MultVVV( cmComplexR_t* y, const cmComplex_t* x0, const cmComplexR_t* x1, unsigned n ) +{ + unsigned i; + for(i=0; i Date: Fri, 3 Jul 2015 18:22:52 -0400 Subject: [PATCH 14/19] cmProc5.h/c : Added cmPhat. Does not yet compile. --- cmProc5.c | 516 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmProc5.h | 85 +++++++++ 2 files changed, 601 insertions(+) diff --git a/cmProc5.c b/cmProc5.c index 22c6324..9816a3c 100644 --- a/cmProc5.c +++ b/cmProc5.c @@ -342,4 +342,520 @@ cmRC_t cmGoldSigGen( cmGoldSig_t* p, unsigned chIdx, unsigned prefixN, unsigned } +//======================================================================================================================= +cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ) +{ + cmPhat_t* op = cmObjAlloc(cmPhat_t,ctx,p); + // The FFT buffer and the delay line is at least twice the size of the + // id signal. This will guarantee that at least one complete id signal + // is inside the buffer. In practice it means that it is possible + // that there will be two id's in the buffer therefore if there are + // two correlation spikes it is important that we take the second. + p->fhN = cmNextPowerOfTwo(mult*hN); + + // allocate the FFT object + cmFftAllocSR(ctx,&p->fft,NULL,p->fhN,kToPolarFftFl); + + if( chN != 0 ) + if( cmPhatInit(op,chN,hN,alpha,mult,flags) != cmOkRC ) + cmPhatFree(&op); + + return op; + +} + +cmRC_t cmPhatFree( cmPhat_t** pp ) +{ + cmRC_t rc = cmOkRC; + + if( pp == NULL || *pp == NULL ) + return rc; + + cmPhat_t* p = *pp; + if((rc = cmPhatFinal(p)) != cmOkRC ) + return rc; + + cmMemFree(p->t0V); + cmMemFree(p->t1V); + cmMemFree(p->dV); + cmMemFree(p->xV); + cmMemFree(p->fhM); + cmMemFree(p->mhM); + cmMemFree(p->wndV); + cmObjFreeStatic(cmFftFreeSR, cmFftSR, p->fft); + cmVectArrayFree(&p->ftVa); + cmObjFree(pp); + + return rc; + +} + + +cmRC_t cmPhatInit( cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ) +{ + cmRC_t rc = cmOkRC; + if((rc = cmPhatFinal(cmOkRC)) != cmOkRC ) + return rc; + + p->fhN = cmNextPowerOfTwo(mult*hN); + + if((cmFftInitSR(&p->fft, NULL, p->fhN, kToPolarFftFl)) != cmOkRC ) + return rc; + + p->alpha = alpha; + p->flags = flags; + + // allocate the delay line + p->dV = cmMemResizeZ(cmSample_t,p->dV,p->fhN); + p->di = 0; + + // allocate the linear buffer + p->xV = cmMemResizeZ(cmSample_t,p->xV,p->fhN); + p->t0V = cmMemResizeZ(cmComplexR_t,p->t0V,p->fhN); + p->t1V = cmMemResizeZ(cmComplexR_t,p->t1V,p->fhN); + + // allocate the window function + p->wndV = cmMemResizeZ(cmSample_t,p->wndV,p->fhN); + cmVOS_Hann(p->wndV,p->fhN); + + // allocate the signal id matrix + p->chN = chN; + p->hN = hN; + p->binN = p->fft.binCnt; //atFftRealBinCount(p->fftH); + p->fhM = cmMemResizeZ(cmComplexR_t, p->fhM, p->fhN * chN); + p->mhM = cmMemResizeZ(float, p->mhM, p->binN * chN); + cmPhatReset(p); + + //if( cmIsFlag(p->flags,kDebugAtPhatFl)) + // cmVectArrayAlloc(ctx, &p->ftVa, kSampleVaFl ); + //else + // p->ftVa = NULL; + + return rc; + +} + +cmRC_t cmPhatFinal( cmPhat_t* p ) +{ return cmOkRC; } + +cmRC_t cmPhatReset( cmPhat_t* p ) +{ + p->di = 0; + p->absIdx = 0; + cmVOS_Zero(p->dV,p->fhN); + return cmOkRC; +} + +cmRC_t cmPhatSetId( cmPhat_t* p, unsigned chIdx, const cmSample_t* hV, unsigned hN ) +{ + unsigned i; + assert( chIdx < p->chN ); + assert( hN == p->hN ); + + // Allocate a window vector + cmSample_t* wndV = cmMemAllocZ(cmSample_t,hN); + cmVOS_Hann(wndV,hN); + + // get ptr to output column in p->fhM[]. + cmComplexR_t* yV = p->fhM + (chIdx*p->fhN); + + // Zero pad hV[hN] to p->fhN; + assert( hN <= p->fhN ); + cmVOS_Zero(p->xV,p->fhN); + cmVOS_Copy(p->xV,hV,hN); + + // Apply the window function to the id signal + if(atIsFlag(p->flags,kHannAtPhatFl) ) + cmVOS_MultVVV(p->xV,hV,wndV,hN); + + // take FFT of id signal. The result is in fft->complexV and fft->magV,phsV + cmFftExecSR(p->fft, p->xV, p->fhN ); + + // Store the magnitude of the id signal + //atFftComplexAbs(p->mhM + (chIdx*p->binN), yV, p->binN); + cmVOR_Copy(p->mhM + (chIdx*p->binN), p->fft->magV, p->binN ); + + // Scale the magnitude + cmVOS_MultVS( p->mhM + (chIdx*p->binN), p->binN, p->alpha); + + // store the complex conjugate of the FFT result in yV[] + //atFftComplexConj(yV,p->binN); + for(i=0; ibinN; ++i) + yV[i].i = -(p->fft->complexV[i].i); + + cmMemFree(wndV); + + return kOkAtRC; +} + +cmSample_t* _cmPhatReadVector( cmCtx* ctx, cmPhat_t* p, const char* fn, unsigned* vnRef ) +{ + cmVectArray_t* vap = NULL; + cmSample_t* v = NULL; + + // instantiate a VectArray from a file + if( cmVectArrayAllocFromFile(ctx, &vap, fn ) != kOkAtRC ) + { + atErrMsg(&p->obj.err,kFileReadFailAtRC,"Id component vector file read failed '%s'.",fn); + goto errLabel; + } + + // get the count of elements in the vector + *vnRef = cmVectArrayEleCount(vap); + + // allocate memory to hold the vector + v = cmMemAlloc(&p->obj.err,cmSample_t,*vnRef); + + // copy the vector from the vector array object into v[] + if( cmVectArrayGetF(vap,v,vnRef) != kOkAtRC ) + { + cmMemFree(v); + v = NULL; + atErrMsg(&p->obj.err,kFileReadFailAtRC,"Id component vector copy out failed '%s'.",fn); + goto errLabel; + } + + cmRptPrintf(p->obj.err.rpt,"%i : %s",*vnRef,fn); + + + errLabel: + cmVectArrayFree(&vap); + + return v; +} + + +cmRC_t cmPhatExec( cmPhat_t* p, const cmSample_t* xV, unsigned xN ) +{ + unsigned n = atMin(xN,p->fhN-p->di); + + // update the delay line + cmVOS_Copy(p->dV+p->di,xV,n); + + if( n < xN ) + cmVOS_Copy(p->dV,xV+n,xN-n); + + p->di = atModIncr(p->di,xN,p->fhN); + + // p->absIdx is the absolute sample index associated with di + p->absIdx += xN; + + return kOkAtRC; +} + + +void cmPhatChExec( + cmPhat_t* p, + unsigned chIdx, + unsigned sessionId, + unsigned roleId) +{ + + unsigned n0 = p->fhN - p->di; + unsigned n1 = p->fhN - n0; + + // Linearize the delay line into xV[] + cmVOS_Copy(p->xV, p->dV + p->di, n0 ); + cmVOS_Copy(p->xV+n0, p->dV, n1 ); + + if( atIsFlag(p->flags,kDebugAtPhatFl)) + cmVectArrayAppendS(p->ftVa, p->xV, p->fhN ); + + // apply a window function to the incoming signal + if( atIsFlag(p->flags,kHannAtPhatFl) ) + cmVOS_MultVV(p->xV,p->fhN,p->wndV); + + // Take the FFT of the delay line. + // p->t0V[p->binN] = fft(p->xV) + //atFftRealForward(p->fftH, p->xV, p->fhN, p->t0V, p->binN ); + cmFftExecSR(p->fft, p->xV, p->fhN ); + + // Calc. the Cross Power Spectrum (aka cross spectral density) of the + // input signal with the id signal. + // Note that the CPS is equivalent to the Fourier Transform of the + // cross-correlation of the two signals. + // t0V[] *= p->fhM[:,chIdx] + //atFftComplexMult( p->t0V, p->fhM + (chIdx * p->fhN), p->binN ); + cmVOCR_MultVVV( p->t0V, p->fft->complexV, p->fhM + (chIdx * p->fhN), p->binN) + + // Calculate the magnitude of the CPS. + // xV[] = | t0V[] | + cmVOCR_Abs( p->xV, p->t0V, p->binN ); + + // Weight the CPS by the scaled magnitude of the id signal + // (we want to emphasize the limited frequencies where the + // id signal contains energy) + // t0V[] *= p->mhM[:,chIdx] + if( p->alpha > 0 ) + cmVOCR_MultR_VV( p->t0V, p->mhM + (chIdx*p->binN), p->binN); + + // Divide through by the magnitude of the CPS + // This has the effect of whitening the spectram and thereby + // minimizing the effect of the magnitude correlation + // while maximimizing the effect of the phase correlation. + // + // t0V[] /= xV[] + cmVOCR_DivR_VV( p->t0V, p->xV, p->binN ); + + // Take the IFFT of the weighted CPS to recover the cross correlation. + // xV[] = IFFT(t0V[]) + + + //// ***** atFftRealInverse( p->fftH, p->t0V, p->xV, p->fhN ); + + // Shift the correlation spike to mark the end of the id + cmVOS_Rotate( p->xV, p->fhN, -((int)p->hN) ); + + // normalize by the length of the correlation + cmVOS_DivVS(p->xV,p->fhN,p->fhN); + + if( atIsFlag(p->flags,kDebugAtPhatFl)) + { + cmVectArrayAppendS(p->ftVa, p->xV, p->fhN ); + + cmSample_t v[] = { sessionId, roleId }; + cmVectArrayAppendS(p->ftVa, v, sizeof(v)/sizeof(v[0])); + } + +} + +cmRC_t cmPhatWrite( cmPhat_t* p, const char* dirStr ) +{ + cmRC_t rc = kOkAtRC; + + if( atIsFlag(p->flags, kDebugAtPhatFl)) + { + char* path = NULL; + + if( p->ftVa != NULL ) + if((rc = cmVectArrayWrite(p->ftVa, path = atMakePath(&p->obj.err,path,"cmPhatFT","va",dirStr,NULL) )) != kOkAtRC ) + rc = atErrMsg(&p->obj.err,rc,"PHAT debug file write failed."); + + cmMemFree(path); + } + + return rc; +} + + +cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) +{ + cmRC_t rc = kOkAtRC; + atSignalArg_t sa; + atSignal_t* s = NULL; + cmPhat_t* p = NULL; + char* path = NULL; + unsigned dspFrmCnt = 256; + unsigned listenDelaySmp = 8196; + double noiseGain = 0.05; + unsigned chIdx = 0; + cmSample_t* yV = NULL; + unsigned yN = 0; + double phatAlpha = 0.5; + unsigned phatMult = 4.0; + double nonLinExpo = 4.0; + cmVectArray_t* outVA = NULL; + cmVectArray_t* inVA = NULL; + cmVectArray_t* statusVA = NULL; + unsigned bsiN = 4; + unsigned bsiV[bsiN]; // known signal onset in absolute samples + unsigned esiV[bsiN]; // known signal offset + unsigned lsiV[bsiN]; // end of listen time (when cmPhatChExec()) is run. + unsigned dsiV[bsiN]; // detection time + unsigned i,j; + + sa.chN = 1; + sa.srate = 44100.0; + sa.lfsrN = 8; + sa.mlsCoeff0 = 0x8e; + sa.mlsCoeff1 = 0x96; + sa.samplesPerChip = 64; + sa.rcosBeta = 0.5; + sa.rcosOSFact = 4; + sa.carrierHz = 17000.0; + sa.envMs = 50.0; + + // allocate the the id signals + if( atSignalAlloc( ctx, &s, &sa ) != kOkAtRC ) + return atErrMsg(&ctx->err, kTestFailAtRC, "Signal allocate failed."); + + // set the post signal listen delay to half the signal length + listenDelaySmp = s->sigN/2; + + // allocate a PHAT detector + if( cmPhatAlloc(ctx,&p,sa.chN,s->sigN, phatAlpha, phatMult, kDebugAtPhatFl ) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "PHAT allocate failed."); + goto errLabel; + } + + // register an id signal with the PHAT detector + if( cmPhatSetId(p, chIdx, s->ch[chIdx].mdV, s->sigN ) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "PHAT setId failed."); + goto errLabel; + } + + // generate an input test signal containing bsiN id signals + if( atSignalGen(s,chIdx,p->fhN,s->sigN,bsiV,bsiN,noiseGain,&yV,&yN) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err,kTestFailAtRC,"Signal generation failed."); + goto errLabel; + } + + // bsiV[] now holds signal onsets. Set esiV[] to signal offsets. + atVOU_AddVVS(esiV,bsiV,bsiN,s->sigN ); + + // set lsiV[] to end-of-listen location + atVOU_AddVVS(lsiV,esiV,bsiN,listenDelaySmp); + + // zero the detection vector + atVOU_Zero(dsiV,bsiN); + + // allocate a vector array to record the PHAT input signals + if( cmVectArrayAlloc(ctx,&inVA,kSampleVaFl) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray inVA alloc failed."); + goto errLabel; + } + + // allocate a vector array to record the PHAT correlation output signals + if( cmVectArrayAlloc(ctx,&outVA,kSampleVaFl) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA alloc failed."); + goto errLabel; + } + + // allocate a vector array to record the PHAT status + if( cmVectArrayAlloc(ctx,&statusVA,kSampleVaFl) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray statusVA alloc failed."); + goto errLabel; + } + + + // for each 'dspFrmCnt' samples in the input signal + for(i=0,j=0; jxV,p->fhN,nonLinExpo); + + // locate the corr. peak inside the listening window + // (the detection window is last 'detectWndSmp' samples in the corr. vector ) + unsigned detectWndSmp = 2*listenDelaySmp; + dsiV[j] = cmVOS_ArgMax( p->xV + p->fhN - detectWndSmp, detectWndSmp); + + // convert the pk index to absolute time + dsiV[j] = i + dspFrmCnt - detectWndSmp + dsiV[j]; + + // sig beg sig end detect begin dtct end detect + cmSample_t v[] = { bsiV[j], esiV[j], lsiV[j]-detectWndSmp, lsiV[j], dsiV[j] }; + + // store the detection information + cmVectArrayAppendS(statusVA,v,sizeof(v)/sizeof(v[0])); + + // store the correlation output vector + cmVectArrayAppendS(outVA,p->xV,p->fhN); + + j += 1; + } + } + + // write inVA + if( cmVectArrayWrite(inVA,path = atMakePath(&ctx->err,path,"phatIn","va",dirStr,NULL)) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA write failed."); + goto errLabel; + } + + // write outVA + if( cmVectArrayWrite(outVA,path = atMakePath(&ctx->err,path,"phatOut","va",dirStr,NULL)) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA write failed."); + goto errLabel; + } + + // write statusVA + if( cmVectArrayWrite(statusVA,path = atMakePath(&ctx->err,path,"phatStatus","va",dirStr,NULL)) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray statusVA write failed."); + goto errLabel; + } + + errLabel: + cmVectArrayFree(&outVA); + cmVectArrayFree(&inVA); + + if( cmPhatFree(&p) != kOkAtRC ) + atErrMsg(&ctx->err,kTestFailAtRC,"PHAT free failed."); + + if( atSignalFree(&s) != kOkAtRC ) + atErrMsg(&ctx->err,kTestFailAtRC,"Signal free failed."); + + return rc; +} + +cmRC_t cmPhatTest2( cmCtx* ctx ) +{ + cmRC_t rc = kOkAtRC; + cmPhat_t* p = NULL; + unsigned hN = 16; + float alpha = 1.0; + unsigned mult = 4; + + cmSample_t hV[] = { 4,3,2,1, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + cmSample_t x0V[] = { 4,3,2,1, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + cmSample_t x1V[] = { 0,0,0,0, 4,3,2,1, 0,0,0,0, 0,0,0,0 }; + cmSample_t x2V[] = { 0,0,0,0, 0,0,0,0, 4,3,2,1, 0,0,0,0 }; + cmSample_t x3V[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 4,3,2,1 }; + + cmSample_t* xV[] = { x0V, x1V, x2V, x3V }; + unsigned chN = sizeof(xV)/sizeof(xV[0]); + unsigned i; + + if(cmPhatAlloc(ctx,&p,chN,hN,alpha,mult,kNoFlagsAtPhatFl) != kOkAtRC ) + { + rc = atErrMsg(&ctx->err,kTestFailAtRC,"cmPhatAlloc() failed."); + goto errLabel; + } + + for(i=0; ierr,kTestFailAtRC,"cmPhatSetId() failed."); + + + for(i=0; ierr,kTestFailAtRC,"cmPhatExec() failed."); + goto errLabel; + } + + cmPhatChExec(p, i, -1, -1); + cmVOS_PrintL(&ctx->printRpt,"x:",p->xV,1,p->fhN); + } + + + errLabel: + + cmPhatFree(&p); + + + return rc; +} diff --git a/cmProc5.h b/cmProc5.h index 8213f98..b7a9e5d 100644 --- a/cmProc5.h +++ b/cmProc5.h @@ -108,6 +108,91 @@ extern "C" { cmRC_t cmGoldSigTest( cmCtx* ctx ); + + //======================================================================================================================= + // Phase aligned transform generalized cross correlator + // + + // Flags for use with the 'flags' argument to cmPhatAlloc() + enum + { + kNoFlagsAtPhatFl= 0x00, + kDebugAtPhatFl = 0x01, // generate debugging file + kHannAtPhatFl = 0x02 // apply a hann window function to the id/audio signals prior to correlation. + }; + + typedef struct + { + cmObj obj; + cmFftSR fft; + + float alpha; + unsigned flags; + + cmComplexR_t* fhM; // fhM[fhN,chN] FT of each id signal stored in complex form + float* mhM; // mhM[binN,chN] magnitude of each fhM column + unsigned chN; // count of id signals + unsigned fhN; // length of each FT id signal (fft->xN) + unsigned binN; // length of each mhM column (fft->xN/2); + unsigned hN; // length of each time domain id signal (hN<=fhN/2) + + unsigned absIdx; // abs. sample index of p->di + + cmSample_t* dV; // dV[fhN] delay line + unsigned di; // next input into delay line + + cmSample_t* xV; // xV[fhN] linear delay buffer + cmComplexR_t* t0V; // t0V[fhN] + cmComplexR_t* t1V; // t1V[fhN] + + cmSample_t* wndV; + + cmVectArray_t* ftVa; + + } cmPhat_t; + + + // Allocate a PHAT based multi-channel correlator. + // 'chN' is the maximum count of id signals to be set via cmPhatSetId(). + // 'hN' is the the length of the id signal in samples. + // 'alpha' weight used to emphasize the frequencies where the + // id signal contains energy. + // 'mult' * 'hN' is the correlation length (fhN) + // 'flags' See kDebugAtPhatFl and kWndAtPhatFl. + cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* pp, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ); + cmRC_t cmPhatFree( cmPhat_t** pp ); + + cmRC_t cmPhatInit( cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ); + cmRC_t cmPhatFinal( cmPhat_t* p ); + + // Zero the audio delay line and reset the current input sample (di) + // and absolute time index (absIdx) to 0. + cmRC_t cmPhatReset( cmPhat_t* p ); + + // Register an id signal with the correlator. + cmRC_t cmPhatSetId( cmPhat_t* p, unsigned chIdx, const cmSample_t* hV, unsigned hN ); + + // Update the correlators internal delay buffer. + cmRC_t cmPhatExec( cmPhat_t* p, const cmSample_t* xV, unsigned xN ); + + // Set p->xV[0:fhN-1] to the correlation function based on + // correlation between the current audio delay line d[] and + // the id signal in fhM[:,chIdx]. + // 'sessionId' and 'roleId' are only used to label the + // data stored in the debug file and may be set to any + // arbitrary value if the debug files are not being generated. + void cmPhatChExec( + cmPhat_t* p, + unsigned chIdx, + unsigned sessionId, + unsigned roleId); + + + cmRC_t cmPhatWrite( cmPhat_t* p, const char* dirStr ); + + cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirFn ); + cmRC_t cmPhatTest2( cmCtx* ctx ); + #ifdef __cplusplus } From 7669faceba2a717328205724a2ec1110db2bc611 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 16 Jul 2015 18:58:55 -0400 Subject: [PATCH 15/19] cmComplexTypes.h/c : Added cmVOCR_MultVFV() and cmVOCR_DivVFV(). Implemented cmVOCR_Abs(). --- cmComplexTypes.c | 44 +++++++++++++++++++++++++++++++------------- cmComplexTypes.h | 10 ++++++++-- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/cmComplexTypes.c b/cmComplexTypes.c index 2929400..c8f5a11 100644 --- a/cmComplexTypes.c +++ b/cmComplexTypes.c @@ -1,42 +1,60 @@ +#include "cmPrefix.h" +#include "cmGlobal.h" +#include "cmFloatTypes.h" +#include "cmComplexTypes.h" - -void cmVOCR_MultVVV( cmComplexR_t* y, const cmComplex_t* x0, const cmComplexR_t* x1, unsigned n ) +void cmVOCR_MultVVV( cmComplexR_t* y, const cmComplexS_t* x0, const cmComplexR_t* x1, unsigned n ) { unsigned i; for(i=0; i Date: Thu, 16 Jul 2015 19:01:10 -0400 Subject: [PATCH 16/19] cmProc5.h/c : Many changes and additions to cmPhat. (still needs IFFT update to be fully implemented) --- cmProc5.c | 157 ++++++++++++++++++++++++++++-------------------------- cmProc5.h | 3 +- 2 files changed, 84 insertions(+), 76 deletions(-) diff --git a/cmProc5.c b/cmProc5.c index 9816a3c..aacee7b 100644 --- a/cmProc5.c +++ b/cmProc5.c @@ -343,25 +343,26 @@ cmRC_t cmGoldSigGen( cmGoldSig_t* p, unsigned chIdx, unsigned prefixN, unsigned //======================================================================================================================= -cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ) +cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* ap, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ) { - cmPhat_t* op = cmObjAlloc(cmPhat_t,ctx,p); + cmPhat_t* p = cmObjAlloc(cmPhat_t,ctx,ap); // The FFT buffer and the delay line is at least twice the size of the // id signal. This will guarantee that at least one complete id signal // is inside the buffer. In practice it means that it is possible // that there will be two id's in the buffer therefore if there are // two correlation spikes it is important that we take the second. - p->fhN = cmNextPowerOfTwo(mult*hN); + unsigned fhN = cmNextPowerOfTwo(mult*hN); // allocate the FFT object - cmFftAllocSR(ctx,&p->fft,NULL,p->fhN,kToPolarFftFl); + cmFftAllocSR(ctx,&p->fft,NULL,fhN,kToPolarFftFl); + cmIFftAllocRS(ctx,&p->ifft,fhN/2 + 1 ); if( chN != 0 ) - if( cmPhatInit(op,chN,hN,alpha,mult,flags) != cmOkRC ) - cmPhatFree(&op); + if( cmPhatInit(p,chN,hN,alpha,mult,flags) != cmOkRC ) + cmPhatFree(&p); - return op; + return p; } @@ -384,6 +385,7 @@ cmRC_t cmPhatFree( cmPhat_t** pp ) cmMemFree(p->mhM); cmMemFree(p->wndV); cmObjFreeStatic(cmFftFreeSR, cmFftSR, p->fft); + cmObjFreeStatic(cmIFftFreeRS, cmIFftRS, p->ifft); cmVectArrayFree(&p->ftVa); cmObjFree(pp); @@ -403,6 +405,9 @@ cmRC_t cmPhatInit( cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsig if((cmFftInitSR(&p->fft, NULL, p->fhN, kToPolarFftFl)) != cmOkRC ) return rc; + if((cmFftInitRS(&p->ifft, NULL, p->fft->binCnt )) != cmOkRC ) + return rc; + p->alpha = alpha; p->flags = flags; @@ -463,18 +468,18 @@ cmRC_t cmPhatSetId( cmPhat_t* p, unsigned chIdx, const cmSample_t* hV, unsigned // Zero pad hV[hN] to p->fhN; assert( hN <= p->fhN ); cmVOS_Zero(p->xV,p->fhN); - cmVOS_Copy(p->xV,hV,hN); + cmVOS_Copy(p->xV,hN,hV); // Apply the window function to the id signal - if(atIsFlag(p->flags,kHannAtPhatFl) ) - cmVOS_MultVVV(p->xV,hV,wndV,hN); + if(cmIsFlag(p->flags,kHannAtPhatFl) ) + cmVOS_MultVVV(p->xV,hN,hV,wndV); // take FFT of id signal. The result is in fft->complexV and fft->magV,phsV - cmFftExecSR(p->fft, p->xV, p->fhN ); + cmFftExecSR(&p->fft, p->xV, p->fhN ); // Store the magnitude of the id signal //atFftComplexAbs(p->mhM + (chIdx*p->binN), yV, p->binN); - cmVOR_Copy(p->mhM + (chIdx*p->binN), p->fft->magV, p->binN ); + cmVOF_CopyR(p->mhM + (chIdx*p->binN), p->binN, p->fft.magV ); // Scale the magnitude cmVOS_MultVS( p->mhM + (chIdx*p->binN), p->binN, p->alpha); @@ -482,22 +487,23 @@ cmRC_t cmPhatSetId( cmPhat_t* p, unsigned chIdx, const cmSample_t* hV, unsigned // store the complex conjugate of the FFT result in yV[] //atFftComplexConj(yV,p->binN); for(i=0; ibinN; ++i) - yV[i].i = -(p->fft->complexV[i].i); + yV[i] = cmCconjR(p->fft.complexV[i]); cmMemFree(wndV); - return kOkAtRC; + return cmOkRC; } cmSample_t* _cmPhatReadVector( cmCtx* ctx, cmPhat_t* p, const char* fn, unsigned* vnRef ) { cmVectArray_t* vap = NULL; cmSample_t* v = NULL; + cmRC_t rc = cmOkRC; // instantiate a VectArray from a file - if( cmVectArrayAllocFromFile(ctx, &vap, fn ) != kOkAtRC ) + if( (vap = cmVectArrayAllocFromFile(ctx, fn )) == NULL ) { - atErrMsg(&p->obj.err,kFileReadFailAtRC,"Id component vector file read failed '%s'.",fn); + rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Id component vector file read failed '%s'.",fn); goto errLabel; } @@ -505,14 +511,14 @@ cmSample_t* _cmPhatReadVector( cmCtx* ctx, cmPhat_t* p, const char* fn, unsigned *vnRef = cmVectArrayEleCount(vap); // allocate memory to hold the vector - v = cmMemAlloc(&p->obj.err,cmSample_t,*vnRef); + v = cmMemAlloc(cmSample_t,*vnRef); // copy the vector from the vector array object into v[] - if( cmVectArrayGetF(vap,v,vnRef) != kOkAtRC ) + if((rc = cmVectArrayGetF(vap,v,vnRef)) != cmOkRC ) { cmMemFree(v); v = NULL; - atErrMsg(&p->obj.err,kFileReadFailAtRC,"Id component vector copy out failed '%s'.",fn); + rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Id component vector copy out failed '%s'.",fn); goto errLabel; } @@ -528,20 +534,20 @@ cmSample_t* _cmPhatReadVector( cmCtx* ctx, cmPhat_t* p, const char* fn, unsigned cmRC_t cmPhatExec( cmPhat_t* p, const cmSample_t* xV, unsigned xN ) { - unsigned n = atMin(xN,p->fhN-p->di); + unsigned n = cmMin(xN,p->fhN-p->di); // update the delay line - cmVOS_Copy(p->dV+p->di,xV,n); + cmVOS_Copy(p->dV+p->di,n,xV); if( n < xN ) - cmVOS_Copy(p->dV,xV+n,xN-n); + cmVOS_Copy(p->dV,xN-n,xV+n); - p->di = atModIncr(p->di,xN,p->fhN); + p->di = cmModIncr(p->di,xN,p->fhN); // p->absIdx is the absolute sample index associated with di p->absIdx += xN; - return kOkAtRC; + return cmOkRC; } @@ -556,20 +562,20 @@ void cmPhatChExec( unsigned n1 = p->fhN - n0; // Linearize the delay line into xV[] - cmVOS_Copy(p->xV, p->dV + p->di, n0 ); - cmVOS_Copy(p->xV+n0, p->dV, n1 ); + cmVOS_Copy(p->xV, n0, p->dV + p->di ); + cmVOS_Copy(p->xV+n0, n1, p->dV ); - if( atIsFlag(p->flags,kDebugAtPhatFl)) + if( cmIsFlag(p->flags,kDebugAtPhatFl)) cmVectArrayAppendS(p->ftVa, p->xV, p->fhN ); // apply a window function to the incoming signal - if( atIsFlag(p->flags,kHannAtPhatFl) ) + if( cmIsFlag(p->flags,kHannAtPhatFl) ) cmVOS_MultVV(p->xV,p->fhN,p->wndV); // Take the FFT of the delay line. // p->t0V[p->binN] = fft(p->xV) //atFftRealForward(p->fftH, p->xV, p->fhN, p->t0V, p->binN ); - cmFftExecSR(p->fft, p->xV, p->fhN ); + cmFftExecSR(&p->fft, p->xV, p->fhN ); // Calc. the Cross Power Spectrum (aka cross spectral density) of the // input signal with the id signal. @@ -577,7 +583,7 @@ void cmPhatChExec( // cross-correlation of the two signals. // t0V[] *= p->fhM[:,chIdx] //atFftComplexMult( p->t0V, p->fhM + (chIdx * p->fhN), p->binN ); - cmVOCR_MultVVV( p->t0V, p->fft->complexV, p->fhM + (chIdx * p->fhN), p->binN) + cmVOCR_MultVVV( p->t0V, p->fft.complexV, p->fhM + (chIdx * p->fhN), p->binN); // Calculate the magnitude of the CPS. // xV[] = | t0V[] | @@ -588,7 +594,7 @@ void cmPhatChExec( // id signal contains energy) // t0V[] *= p->mhM[:,chIdx] if( p->alpha > 0 ) - cmVOCR_MultR_VV( p->t0V, p->mhM + (chIdx*p->binN), p->binN); + cmVOCR_MultVFV( p->t0V, p->mhM + (chIdx*p->binN), p->binN); // Divide through by the magnitude of the CPS // This has the effect of whitening the spectram and thereby @@ -596,11 +602,11 @@ void cmPhatChExec( // while maximimizing the effect of the phase correlation. // // t0V[] /= xV[] - cmVOCR_DivR_VV( p->t0V, p->xV, p->binN ); + cmVOCR_DivVFV( p->t0V, p->xV, p->binN ); // Take the IFFT of the weighted CPS to recover the cross correlation. // xV[] = IFFT(t0V[]) - + cmIFftExecRS( p->ifft, ); //// ***** atFftRealInverse( p->fftH, p->t0V, p->xV, p->fhN ); @@ -610,7 +616,7 @@ void cmPhatChExec( // normalize by the length of the correlation cmVOS_DivVS(p->xV,p->fhN,p->fhN); - if( atIsFlag(p->flags,kDebugAtPhatFl)) + if( cmIsFlag(p->flags,kDebugAtPhatFl)) { cmVectArrayAppendS(p->ftVa, p->xV, p->fhN ); @@ -622,28 +628,28 @@ void cmPhatChExec( cmRC_t cmPhatWrite( cmPhat_t* p, const char* dirStr ) { - cmRC_t rc = kOkAtRC; + cmRC_t rc = cmOkRC; - if( atIsFlag(p->flags, kDebugAtPhatFl)) + if( cmIsFlag(p->flags, kDebugAtPhatFl)) { - char* path = NULL; + const char* path = NULL; if( p->ftVa != NULL ) - if((rc = cmVectArrayWrite(p->ftVa, path = atMakePath(&p->obj.err,path,"cmPhatFT","va",dirStr,NULL) )) != kOkAtRC ) - rc = atErrMsg(&p->obj.err,rc,"PHAT debug file write failed."); + if((rc = cmVectArrayWrite(p->ftVa, path = cmFsMakeFn(path,"cmPhatFT","va",dirStr,NULL) )) != cmOkRC ) + rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"PHAT debug file write failed."); - cmMemFree(path); + cmFsFreeFn(path); } return rc; } - +#ifdef NOTDEF cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) { - cmRC_t rc = kOkAtRC; - atSignalArg_t sa; - atSignal_t* s = NULL; + cmRC_t rc = cmOkRC; + cmGoldSigArg_t sa; + cmGoldSig_t* s = NULL; cmPhat_t* p = NULL; char* path = NULL; unsigned dspFrmCnt = 256; @@ -677,30 +683,30 @@ cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) sa.envMs = 50.0; // allocate the the id signals - if( atSignalAlloc( ctx, &s, &sa ) != kOkAtRC ) - return atErrMsg(&ctx->err, kTestFailAtRC, "Signal allocate failed."); + if( (s = cmGoldSigAlloc( ctx, NULL, &sa ) == NULL ) + return cmErrMsg(&ctx->err, cmSubSysFailRC, "Signal allocate failed."); // set the post signal listen delay to half the signal length listenDelaySmp = s->sigN/2; // allocate a PHAT detector - if( cmPhatAlloc(ctx,&p,sa.chN,s->sigN, phatAlpha, phatMult, kDebugAtPhatFl ) != kOkAtRC ) + if( (p = cmPhatAlloc(ctx,NULL,sa.chN,s->sigN, phatAlpha, phatMult, kDebugAtPhatFl ) == NULL ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "PHAT allocate failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "PHAT allocate failed."); goto errLabel; } // register an id signal with the PHAT detector - if( cmPhatSetId(p, chIdx, s->ch[chIdx].mdV, s->sigN ) != kOkAtRC ) + if( cmPhatSetId(p, chIdx, s->ch[chIdx].mdV, s->sigN ) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "PHAT setId failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "PHAT setId failed."); goto errLabel; } // generate an input test signal containing bsiN id signals - if( atSignalGen(s,chIdx,p->fhN,s->sigN,bsiV,bsiN,noiseGain,&yV,&yN) != kOkAtRC ) + if( atSignalGen(s,chIdx,p->fhN,s->sigN,bsiV,bsiN,noiseGain,&yV,&yN) != cmOkRC ) { - rc = atErrMsg(&ctx->err,kTestFailAtRC,"Signal generation failed."); + rc = cmErrMsg(&ctx->err,cmSubSysFailRC,"Signal generation failed."); goto errLabel; } @@ -714,23 +720,23 @@ cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) atVOU_Zero(dsiV,bsiN); // allocate a vector array to record the PHAT input signals - if( cmVectArrayAlloc(ctx,&inVA,kSampleVaFl) != kOkAtRC ) + if( cmVectArrayAlloc(ctx,&inVA,kSampleVaFl) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray inVA alloc failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray inVA alloc failed."); goto errLabel; } // allocate a vector array to record the PHAT correlation output signals - if( cmVectArrayAlloc(ctx,&outVA,kSampleVaFl) != kOkAtRC ) + if( cmVectArrayAlloc(ctx,&outVA,kSampleVaFl) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA alloc failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray outVA alloc failed."); goto errLabel; } // allocate a vector array to record the PHAT status - if( cmVectArrayAlloc(ctx,&statusVA,kSampleVaFl) != kOkAtRC ) + if( cmVectArrayAlloc(ctx,&statusVA,kSampleVaFl) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray statusVA alloc failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray statusVA alloc failed."); goto errLabel; } @@ -775,23 +781,23 @@ cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) } // write inVA - if( cmVectArrayWrite(inVA,path = atMakePath(&ctx->err,path,"phatIn","va",dirStr,NULL)) != kOkAtRC ) + if( cmVectArrayWrite(inVA,path = atMakePath(&ctx->err,path,"phatIn","va",dirStr,NULL)) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA write failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray outVA write failed."); goto errLabel; } // write outVA - if( cmVectArrayWrite(outVA,path = atMakePath(&ctx->err,path,"phatOut","va",dirStr,NULL)) != kOkAtRC ) + if( cmVectArrayWrite(outVA,path = atMakePath(&ctx->err,path,"phatOut","va",dirStr,NULL)) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray outVA write failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray outVA write failed."); goto errLabel; } // write statusVA - if( cmVectArrayWrite(statusVA,path = atMakePath(&ctx->err,path,"phatStatus","va",dirStr,NULL)) != kOkAtRC ) + if( cmVectArrayWrite(statusVA,path = atMakePath(&ctx->err,path,"phatStatus","va",dirStr,NULL)) != cmOkRC ) { - rc = atErrMsg(&ctx->err, kTestFailAtRC, "vectArray statusVA write failed."); + rc = cmErrMsg(&ctx->err, cmSubSysFailRC, "vectArray statusVA write failed."); goto errLabel; } @@ -799,18 +805,18 @@ cmRC_t cmPhatTest1( cmCtx* ctx, const char* dirStr ) cmVectArrayFree(&outVA); cmVectArrayFree(&inVA); - if( cmPhatFree(&p) != kOkAtRC ) - atErrMsg(&ctx->err,kTestFailAtRC,"PHAT free failed."); + if( cmPhatFree(&p) != cmOkRC ) + cmErrMsg(&ctx->err,cmSubSysFailRC,"PHAT free failed."); - if( atSignalFree(&s) != kOkAtRC ) - atErrMsg(&ctx->err,kTestFailAtRC,"Signal free failed."); + if( atSignalFree(&s) != cmOkRC ) + cmErrMsg(&ctx->err,cmSubSysFailRC,"Signal free failed."); return rc; } cmRC_t cmPhatTest2( cmCtx* ctx ) { - cmRC_t rc = kOkAtRC; + cmRC_t rc = cmOkRC; cmPhat_t* p = NULL; unsigned hN = 16; float alpha = 1.0; @@ -826,24 +832,24 @@ cmRC_t cmPhatTest2( cmCtx* ctx ) unsigned chN = sizeof(xV)/sizeof(xV[0]); unsigned i; - if(cmPhatAlloc(ctx,&p,chN,hN,alpha,mult,kNoFlagsAtPhatFl) != kOkAtRC ) + if(cmPhatAlloc(ctx,&p,chN,hN,alpha,mult,kNoFlagsAtPhatFl) != cmOkRC ) { - rc = atErrMsg(&ctx->err,kTestFailAtRC,"cmPhatAlloc() failed."); + rc = cmErrMsg(&ctx->err,cmSubSysFailRC,"cmPhatAlloc() failed."); goto errLabel; } for(i=0; ierr,kTestFailAtRC,"cmPhatSetId() failed."); + if( cmPhatSetId(p,i,hV,hN) != cmOkRC ) + rc = cmErrMsg(&ctx->err,cmSubSysFailRC,"cmPhatSetId() failed."); for(i=0; ierr,kTestFailAtRC,"cmPhatExec() failed."); + rc = cmErrMsg(&ctx->err,cmSubSysFailRC,"cmPhatExec() failed."); goto errLabel; } @@ -859,3 +865,4 @@ cmRC_t cmPhatTest2( cmCtx* ctx ) return rc; } +#endif diff --git a/cmProc5.h b/cmProc5.h index b7a9e5d..722b574 100644 --- a/cmProc5.h +++ b/cmProc5.h @@ -125,6 +125,7 @@ extern "C" { { cmObj obj; cmFftSR fft; + cmIFftRS ifft; float alpha; unsigned flags; @@ -159,7 +160,7 @@ extern "C" { // id signal contains energy. // 'mult' * 'hN' is the correlation length (fhN) // 'flags' See kDebugAtPhatFl and kWndAtPhatFl. - cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* pp, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ); + cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ); cmRC_t cmPhatFree( cmPhat_t** pp ); cmRC_t cmPhatInit( cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags ); From a59041336a663d5f2d261c7e8f4aa14ba0aed873 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 16 Jul 2015 19:01:37 -0400 Subject: [PATCH 17/19] cmProc2.h/c : Added cmVectArrayWriteDirFn(). --- cmProc2.c | 8 ++++++++ cmProc2.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cmProc2.c b/cmProc2.c index b5fb3d9..cb9c379 100644 --- a/cmProc2.c +++ b/cmProc2.c @@ -3997,6 +3997,14 @@ cmRC_t cmVectArrayWrite( cmVectArray_t* p, const char* fn ) return rc; } +cmRC_t cmVectArrayWriteDirFn(cmVectArray_t* p, const char* dir, const char* fn ) +{ + assert( dir!=NULL && fn!=NULL ); + const cmChar_t* path = cmFsMakeFn( dir, fn, NULL, NULL ); + cmRC_t rc = cmVectArrayWrite(p,path); + cmFsFreeFn(path); + return rc; +} cmRC_t cmVectArrayPrint( cmVectArray_t* p, cmRpt_t* rpt ) { diff --git a/cmProc2.h b/cmProc2.h index 206c598..3ca481d 100644 --- a/cmProc2.h +++ b/cmProc2.h @@ -853,7 +853,8 @@ extern "C" { cmRC_t cmVectArrayAppendU( cmVectArray_t* p, const unsigned* v, unsigned vn ); // Write a vector array in a format that can be read by readVectArray.m. - cmRC_t cmVectArrayWrite( cmVectArray_t* p, const char* fn ); + cmRC_t cmVectArrayWrite( cmVectArray_t* p, const char* fn ); + cmRC_t cmVectArrayWriteDirFn(cmVectArray_t* p, const char* dir, const char* fn ); // Print the vector array to rpt. cmRC_t cmVectArrayPrint( cmVectArray_t* p, cmRpt_t* rpt ); From 01505d751a8b66ede8d906cf2b75f0028dbed896 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 16 Jul 2015 19:01:54 -0400 Subject: [PATCH 18/19] cmMath.h/c : Added cmModIncr(). --- cmMath.c | 14 ++++++++++++++ cmMath.h | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/cmMath.c b/cmMath.c index f740b1b..72ce7fd 100644 --- a/cmMath.c +++ b/cmMath.c @@ -154,6 +154,20 @@ unsigned cmPrevOddU( unsigned v ) { return cmIsOddU(v) ? v : v-1; } unsigned cmNextEvenU( unsigned v ) { return cmIsEvenU(v) ? v : v+1; } unsigned cmPrevEvenU( unsigned v ) { return cmIsEvenU(v) ? v : v-1; } +unsigned cmModIncr(int idx, int delta, int maxN ) +{ + int sum = idx + delta; + + if( sum >= maxN ) + return sum - maxN; + + if( sum < 0 ) + return maxN + sum; + + return sum; +} + + // modified bessel function of first kind, order 0 // ref: orfandis appendix B io.m double cmBessel0( double x ) diff --git a/cmMath.h b/cmMath.h index 57d96ea..b80716e 100644 --- a/cmMath.h +++ b/cmMath.h @@ -15,6 +15,12 @@ unsigned cmPrevOddU( unsigned v ); unsigned cmNextEvenU( unsigned v ); unsigned cmPrevEvenU( unsigned v ); +/// Increment or decrement 'idx' by 'delta' always wrapping the result into the range +/// 0 to (maxN-1). +/// 'idx': initial value +/// 'delta': incremental amount +/// 'maxN' - 1 : maximum return value. +unsigned cmModIncr(int idx, int delta, int maxN ); // modified bessel function of first kind, order 0 // ref: orfandis appendix B io.m From 8e7afa1be6c3f1645b9ac87b19402df838e91894 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 16 Jul 2015 19:02:14 -0400 Subject: [PATCH 19/19] Makefile.am : Added cmComplexType.c. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 1a29e63..43f22bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ cmHDR = cmSRC = cmHDR += src/libcm/cmErr.h src/libcm/cmCtx.h src/libcm/cmRpt.h src/libcm/cmGlobal.h src/libcm/cmComplexTypes.h src/libcm/cmFloatTypes.h src/libcm/cmPrefix.h -cmSRC += src/libcm/cmErr.c src/libcm/cmCtx.c src/libcm/cmRpt.c src/libcm/cmGlobal.c +cmSRC += src/libcm/cmErr.c src/libcm/cmCtx.c src/libcm/cmRpt.c src/libcm/cmGlobal.c src/libcm/cmComplexTypes.c cmHDR += src/libcm/cmSerialize.h src/libcm/cmSymTbl.h src/libcm/cmHashTbl.h src/libcm/cmFileSys.h src/libcm/cmFile.h cmSRC += src/libcm/cmSerialize.c src/libcm/cmSymTbl.c src/libcm/cmHashTbl.c src/libcm/cmFileSys.c src/libcm/cmFile.c