libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmProc5.c 31KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. #include "cmPrefix.h"
  4. #include "cmGlobal.h"
  5. #include "cmRpt.h"
  6. #include "cmErr.h"
  7. #include "cmCtx.h"
  8. #include "cmMem.h"
  9. #include "cmMallocDebug.h"
  10. #include "cmLinkedHeap.h"
  11. #include "cmFloatTypes.h"
  12. #include "cmComplexTypes.h"
  13. #include "cmFileSys.h"
  14. #include "cmJson.h"
  15. #include "cmSymTbl.h"
  16. #include "cmAudioFile.h"
  17. #include "cmText.h"
  18. #include "cmProcObj.h"
  19. #include "cmProcTemplate.h"
  20. #include "cmMath.h"
  21. #include "cmFile.h"
  22. #include "cmTime.h"
  23. #include "cmMidi.h"
  24. #include "cmProc.h"
  25. #include "cmProc2.h"
  26. #include "cmProc5.h"
  27. #include "cmVectOps.h"
  28. //=======================================================================================================================
  29. cmGoertzel* cmGoertzelAlloc( cmCtx* c, cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt, unsigned procSmpCnt, unsigned hopSmpCnt, unsigned wndSmpCnt )
  30. {
  31. cmGoertzel* op = cmObjAlloc(cmGoertzel,c,p);
  32. op->shb = cmShiftBufAlloc(c,NULL,0,0,0);
  33. if( srate > 0 )
  34. if( cmGoertzelInit(op,srate,fcHzV,chCnt,procSmpCnt,wndSmpCnt,hopSmpCnt) != cmOkRC )
  35. cmGoertzelFree(&op);
  36. return op;
  37. }
  38. cmRC_t cmGoertzelFree( cmGoertzel** pp )
  39. {
  40. cmRC_t rc = cmOkRC;
  41. if( pp==NULL || *pp==NULL )
  42. return rc;
  43. cmGoertzel* p = *pp;
  44. if((rc = cmGoertzelFinal(p)) != cmOkRC )
  45. return rc;
  46. cmShiftBufFree(&p->shb);
  47. cmMemFree(p->ch);
  48. cmMemFree(p->wnd);
  49. cmObjFree(pp);
  50. return rc;
  51. }
  52. cmRC_t cmGoertzelInit( cmGoertzel* p, double srate, const double* fcHzV, unsigned chCnt, unsigned procSmpCnt, unsigned hopSmpCnt, unsigned wndSmpCnt )
  53. {
  54. cmRC_t rc;
  55. unsigned i;
  56. if((rc = cmGoertzelFinal(p)) != cmOkRC )
  57. return rc;
  58. p->ch = cmMemResizeZ(cmGoertzelCh,p->ch,chCnt);
  59. p->chCnt = chCnt;
  60. p->srate = srate;
  61. p->wnd = cmMemResizeZ(cmSample_t,p->wnd,wndSmpCnt);
  62. cmVOS_Hann(p->wnd,wndSmpCnt);
  63. cmShiftBufInit(p->shb,procSmpCnt,wndSmpCnt,hopSmpCnt);
  64. for(i=0; i<p->chCnt; ++i)
  65. {
  66. cmGoertzelSetFcHz(p,i,fcHzV[i]);
  67. }
  68. return rc;
  69. }
  70. cmRC_t cmGoertzelFinal( cmGoertzel* p )
  71. { return cmOkRC; }
  72. cmRC_t cmGoertzelSetFcHz( cmGoertzel* p, unsigned chIdx, double hz )
  73. {
  74. assert( chIdx < p->chCnt );
  75. p->ch[chIdx].hz = hz;
  76. p->ch[chIdx].coeff = 2*cos(2*M_PI*hz/p->srate);
  77. return cmOkRC;
  78. }
  79. cmRC_t cmGoertzelExec( cmGoertzel* p, const cmSample_t* inpV, unsigned procSmpCnt, double* outV, unsigned chCnt )
  80. {
  81. unsigned i,j;
  82. while( cmShiftBufExec(p->shb,inpV,procSmpCnt) )
  83. {
  84. unsigned xn = p->shb->wndSmpCnt;
  85. cmSample_t x[ xn ];
  86. cmVOS_MultVVV(x,xn,p->wnd,p->shb->outV);
  87. for(i=0; i<chCnt; ++i)
  88. {
  89. cmGoertzelCh* ch = p->ch + i;
  90. ch->s2 = x[0];
  91. ch->s1 = x[1] + 2 * x[0] * ch->coeff;
  92. for(j=2; j<xn; ++j)
  93. {
  94. ch->s0 = x[j] + ch->coeff * ch->s1 - ch->s2;
  95. ch->s2 = ch->s1;
  96. ch->s1 = ch->s0;
  97. }
  98. outV[i] = ch->s2*ch->s2 + ch->s1*ch->s1 - ch->coeff * ch->s2 * ch->s1;
  99. }
  100. }
  101. return cmOkRC;
  102. }
  103. //=======================================================================================================================
  104. double _cmGoldSigSinc( double t, double T )
  105. {
  106. double x = t/T;
  107. return x == 0 ? 1.0 : sin(M_PI*x)/(M_PI*x);
  108. }
  109. void _cmGoldSigRaisedCos( cmSample_t* yV, int yN, double sPc, double beta )
  110. {
  111. int i;
  112. for(i=0; i<yN; ++i)
  113. {
  114. double t = i - yN/2;
  115. double den = 1 - (4*(beta*beta)*(t*t) / (sPc*sPc));
  116. double a;
  117. if(fabs(den) < 0.00001 )
  118. a = 1;
  119. else
  120. a = cos(M_PI * beta * t/ sPc ) / den;
  121. yV[i] = _cmGoldSigSinc(t,sPc) * a;
  122. }
  123. }
  124. void _cmGoldSigConv( cmGoldSig_t* p, unsigned chIdx )
  125. {
  126. int i;
  127. int sPc = p->a.samplesPerChip;
  128. int osf = p->a.rcosOSFact;
  129. // for each bit in the spreading-code
  130. for(i=0; i<p->mlsN; ++i)
  131. {
  132. int j = (i*sPc) + sPc/2; // index into bbV[] of center of impulse response
  133. int k = j - (sPc*osf)/2; // index into bbV[] of start of impulse response
  134. int h;
  135. // for each sample in the impulse response
  136. for(h=0; h<p->rcosN; ++h,++k)
  137. {
  138. while( k<0 )
  139. k += p->sigN;
  140. while( k>=p->sigN )
  141. k -= p->sigN;
  142. p->ch[chIdx].bbV[k] += p->ch[chIdx].pnV[i] * p->rcosV[h];
  143. }
  144. }
  145. }
  146. void _cmGoldSigModulate( cmGoldSig_t* p, unsigned chIdx )
  147. {
  148. unsigned i;
  149. double rps = 2.0 * M_PI * p->a.carrierHz / p->a.srate;
  150. cmSample_t* yV = p->ch[chIdx].mdV;
  151. cmSample_t* bbV = p->ch[chIdx].bbV;
  152. for(i=0; i<p->sigN; ++i)
  153. yV[ i ] = bbV[i]*cos(rps*i) + bbV[i]*sin(rps*i);
  154. // apply a half Hann envelope to the onset/offset of the id signal
  155. if( p->a.envMs > 0 )
  156. {
  157. unsigned wndMs = p->a.envMs * 2;
  158. unsigned wndN = wndMs * p->a.srate / 1000;
  159. wndN += wndN % 2 ? 0 : 1; // force the window length to be odd
  160. unsigned wNo2 = wndN/2 + 1;
  161. cmSample_t wndV[ wndN ];
  162. cmVOS_Hann(wndV,wndN);
  163. cmVOS_MultVV(yV,wNo2,wndV);
  164. cmVOS_MultVV(yV + p->sigN - wNo2, wNo2, wndV + wNo2 - 1);
  165. }
  166. }
  167. cmGoldSig_t* cmGoldSigAlloc( cmCtx* ctx, cmGoldSig_t* p, const cmGoldSigArg_t* a )
  168. {
  169. cmGoldSig_t* op = cmObjAlloc(cmGoldSig_t,ctx,p);
  170. op->fir = cmFIRAllocKaiser(ctx, NULL, 0, 0, 0, 0, 0, 0, 0 );
  171. if( a != NULL )
  172. if( cmGoldSigInit(op,a) != cmOkRC )
  173. cmGoldSigFree(&op);
  174. return op;
  175. }
  176. cmRC_t cmGoldSigFree( cmGoldSig_t** pp )
  177. {
  178. cmRC_t rc = cmOkRC;
  179. if( pp == NULL || *pp == NULL )
  180. return rc;
  181. cmGoldSig_t* p = *pp;
  182. if((rc = cmGoldSigFinal(p)) != cmOkRC )
  183. return rc;
  184. unsigned i;
  185. for(i=0; i<p->a.chN; ++i)
  186. {
  187. cmMemFree(p->ch[i].bbV);
  188. cmMemFree(p->ch[i].mdV);
  189. }
  190. cmFIRFree(&p->fir);
  191. cmMemFree(p->ch);
  192. cmMemFree(p->rcosV);
  193. cmMemFree(p->pnM);
  194. cmMemFree(p);
  195. *pp = NULL;
  196. return rc;
  197. }
  198. cmRC_t cmGoldSigInit( cmGoldSig_t* p, const cmGoldSigArg_t* a )
  199. {
  200. cmRC_t rc = cmOkRC;
  201. unsigned i;
  202. p->a = *a; // store arg recd
  203. p->ch = cmMemResizeZ(cmGoldSigCh_t,p->ch,a->chN); // alloc channel array
  204. p->mlsN = (1 << a->lfsrN) - 1; // calc spreading code length
  205. p->rcosN = a->samplesPerChip * a->rcosOSFact; // calc rcos imp. resp. length
  206. p->rcosN += (p->rcosN % 2)==0; // force rcos imp. length odd
  207. p->rcosV = cmMemResizeZ(cmSample_t,p->rcosV,p->rcosN); // alloc rcos imp. resp. vector
  208. p->pnM = cmMemResizeZ(int,p->pnM,p->mlsN*a->chN); // alloc spreading-code mtx
  209. p->sigN = p->mlsN * a->samplesPerChip; // calc audio signal length
  210. // generate spreading codes
  211. if( cmGenGoldCodes(a->lfsrN, a->mlsCoeff0, a->mlsCoeff1, a->chN, p->pnM, p->mlsN ) == false )
  212. {
  213. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Unable to generate sufficient balanced Gold codes.");
  214. goto errLabel;
  215. }
  216. // generate the rcos impulse response
  217. _cmGoldSigRaisedCos(p->rcosV,p->rcosN,a->samplesPerChip,a->rcosBeta);
  218. if(1)
  219. {
  220. double passHz = 20000.0;
  221. double stopHz = 17000.0;
  222. double passDb = 1.0;
  223. double stopDb = 90.0;
  224. unsigned flags = 0;
  225. if( cmFIRInitKaiser(p->fir, 64, a->srate, passHz, stopHz, passDb, stopDb, flags ) != cmOkRC )
  226. {
  227. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Unable to allocate internal FIR.");
  228. goto errLabel;
  229. }
  230. p->rcosN = p->fir->coeffCnt;
  231. p->rcosV = cmMemResizeZ(cmSample_t,p->rcosV,p->rcosN);
  232. cmVOS_CopyD(p->rcosV,p->rcosN,p->fir->coeffV);
  233. }
  234. // for each channel
  235. for(i=0; i<a->chN; ++i)
  236. {
  237. // Note: if (i*p->mlsN) is set to 0 in the following line then all channels
  238. // will use the same spreading code.
  239. p->ch[i].pnV = p->pnM + (i*p->mlsN); // get ch. spreading code
  240. p->ch[i].bbV = cmMemResizeZ(cmSample_t,p->ch[i].bbV,p->sigN); // alloc baseband signal vector
  241. p->ch[i].mdV = cmMemResizeZ(cmSample_t,p->ch[i].mdV,p->sigN); // alloc output audio vector
  242. // Convolve spreading code with rcos impulse reponse to form baseband signal.
  243. _cmGoldSigConv(p, i );
  244. // Modulate baseband signal to carrier frq. and apply attack/decay envelope.
  245. _cmGoldSigModulate(p, i );
  246. }
  247. errLabel:
  248. if((rc = cmErrLastRC(&p->obj.err)) != cmOkRC )
  249. cmGoldSigFree(&p);
  250. return rc;
  251. }
  252. cmRC_t cmGoldSigFinal( cmGoldSig_t* p )
  253. { return cmFIRFinal(p->fir); }
  254. cmRC_t cmGoldSigWrite( cmCtx* ctx, cmGoldSig_t* p, const char* fn )
  255. {
  256. cmVectArray_t* vap = NULL;
  257. unsigned i;
  258. vap = cmVectArrayAlloc(ctx,kSampleVaFl);
  259. for(i=0; i<p->a.chN; ++i)
  260. {
  261. cmVectArrayAppendS(vap,p->ch[i].bbV,p->sigN);
  262. cmVectArrayAppendS(vap,p->ch[i].mdV,p->sigN);
  263. }
  264. cmVectArrayWrite(vap,fn);
  265. cmVectArrayFree(&vap);
  266. return cmOkRC;
  267. }
  268. cmRC_t cmGoldSigGen( cmGoldSig_t* p, unsigned chIdx, unsigned prefixN, unsigned dsN, unsigned *bsiV, unsigned bsiN, double noiseGain, cmSample_t** yVRef, unsigned* yNRef )
  269. {
  270. unsigned yN = prefixN + bsiN * (p->sigN + dsN);
  271. cmSample_t* yV = cmMemAllocZ(cmSample_t,yN);
  272. unsigned i;
  273. cmVOS_Random(yV, yN, -noiseGain, noiseGain );
  274. for(i=0; i<bsiN; ++i)
  275. {
  276. bsiV[i] = prefixN + i*(p->sigN + dsN);
  277. cmVOS_AddVV(yV + bsiV[i], p->sigN, p->ch[chIdx].mdV );
  278. }
  279. if( yVRef != NULL )
  280. *yVRef = yV;
  281. if( yNRef != NULL )
  282. *yNRef = yN;
  283. return cmOkRC;
  284. }
  285. //=======================================================================================================================
  286. cmPhat_t* cmPhatAlloc( cmCtx* ctx, cmPhat_t* ap, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags )
  287. {
  288. cmPhat_t* p = cmObjAlloc(cmPhat_t,ctx,ap);
  289. // The FFT buffer and the delay line is at least twice the size of the
  290. // id signal. This will guarantee that at least one complete id signal
  291. // is inside the buffer. In practice it means that it is possible
  292. // that there will be two id's in the buffer therefore if there are
  293. // two correlation spikes it is important that we take the second.
  294. unsigned fhN = cmNextPowerOfTwo(mult*hN);
  295. // allocate the FFT object
  296. cmFftAllocSR(ctx,&p->fft,NULL,fhN,kToPolarFftFl);
  297. cmIFftAllocRS(ctx,&p->ifft,fhN/2 + 1 );
  298. // allocate the vect array
  299. p->ftVa = cmVectArrayAlloc(ctx, kSampleVaFl );
  300. if( chN != 0 )
  301. if( cmPhatInit(p,chN,hN,alpha,mult,flags) != cmOkRC )
  302. cmPhatFree(&p);
  303. return p;
  304. }
  305. cmRC_t cmPhatFree( cmPhat_t** pp )
  306. {
  307. cmRC_t rc = cmOkRC;
  308. if( pp == NULL || *pp == NULL )
  309. return rc;
  310. cmPhat_t* p = *pp;
  311. if((rc = cmPhatFinal(p)) != cmOkRC )
  312. return rc;
  313. cmMemFree(p->t0V);
  314. cmMemFree(p->t1V);
  315. cmMemFree(p->dV);
  316. cmMemFree(p->xV);
  317. cmMemFree(p->fhM);
  318. cmMemFree(p->mhM);
  319. cmMemFree(p->wndV);
  320. cmObjFreeStatic(cmFftFreeSR, cmFftSR, p->fft);
  321. cmObjFreeStatic(cmIFftFreeRS, cmIFftRS, p->ifft);
  322. cmVectArrayFree(&p->ftVa);
  323. cmObjFree(pp);
  324. return rc;
  325. }
  326. cmRC_t cmPhatInit( cmPhat_t* p, unsigned chN, unsigned hN, float alpha, unsigned mult, unsigned flags )
  327. {
  328. cmRC_t rc = cmOkRC;
  329. if((rc = cmPhatFinal(cmOkRC)) != cmOkRC )
  330. return rc;
  331. p->fhN = cmNextPowerOfTwo(mult*hN);
  332. if((cmFftInitSR(&p->fft, NULL, p->fhN, kToPolarFftFl)) != cmOkRC )
  333. return rc;
  334. if((cmIFftInitRS(&p->ifft, p->fft.binCnt )) != cmOkRC )
  335. return rc;
  336. p->alpha = alpha;
  337. p->flags = flags;
  338. // allocate the delay line
  339. p->dV = cmMemResizeZ(cmSample_t,p->dV,p->fhN);
  340. p->di = 0;
  341. // allocate the linear buffer
  342. p->xV = cmMemResizeZ(cmSample_t,p->xV,p->fhN);
  343. p->t0V = cmMemResizeZ(cmComplexR_t,p->t0V,p->fhN);
  344. p->t1V = cmMemResizeZ(cmComplexR_t,p->t1V,p->fhN);
  345. // allocate the window function
  346. p->wndV = cmMemResizeZ(cmSample_t,p->wndV,p->fhN);
  347. cmVOS_Hann(p->wndV,p->fhN);
  348. // allocate the signal id matrix
  349. p->chN = chN;
  350. p->hN = hN;
  351. p->binN = p->fft.binCnt; //atFftRealBinCount(p->fftH);
  352. p->fhM = cmMemResizeZ(cmComplexR_t, p->fhM, p->fhN * chN);
  353. p->mhM = cmMemResizeZ(float, p->mhM, p->binN * chN);
  354. cmPhatReset(p);
  355. if( cmIsFlag(p->flags,kDebugAtPhatFl))
  356. cmVectArrayClear(p->ftVa);
  357. return rc;
  358. }
  359. cmRC_t cmPhatFinal( cmPhat_t* p )
  360. { return cmOkRC; }
  361. cmRC_t cmPhatReset( cmPhat_t* p )
  362. {
  363. p->di = 0;
  364. p->absIdx = 0;
  365. cmVOS_Zero(p->dV,p->fhN);
  366. return cmOkRC;
  367. }
  368. cmRC_t cmPhatSetId( cmPhat_t* p, unsigned chIdx, const cmSample_t* hV, unsigned hN )
  369. {
  370. unsigned i;
  371. assert( chIdx < p->chN );
  372. assert( hN == p->hN );
  373. // Allocate a window vector
  374. cmSample_t* wndV = cmMemAllocZ(cmSample_t,hN);
  375. cmVOS_Hann(wndV,hN);
  376. // get ptr to output column in p->fhM[].
  377. cmComplexR_t* yV = p->fhM + (chIdx*p->fhN);
  378. // Zero pad hV[hN] to p->fhN;
  379. assert( hN <= p->fhN );
  380. cmVOS_Zero(p->xV,p->fhN);
  381. cmVOS_Copy(p->xV,hN,hV);
  382. // Apply the window function to the id signal
  383. if(cmIsFlag(p->flags,kHannAtPhatFl) )
  384. cmVOS_MultVVV(p->xV,hN,hV,wndV);
  385. // take FFT of id signal. The result is in fft->complexV and fft->magV,phsV
  386. cmFftExecSR(&p->fft, p->xV, p->fhN );
  387. // Store the magnitude of the id signal
  388. //atFftComplexAbs(p->mhM + (chIdx*p->binN), yV, p->binN);
  389. cmVOF_CopyR(p->mhM + (chIdx*p->binN), p->binN, p->fft.magV );
  390. // Scale the magnitude
  391. cmVOS_MultVS( p->mhM + (chIdx*p->binN), p->binN, p->alpha);
  392. // store the complex conjugate of the FFT result in yV[]
  393. //atFftComplexConj(yV,p->binN);
  394. for(i=0; i<p->binN; ++i)
  395. yV[i] = cmCconjR(p->fft.complexV[i]);
  396. cmMemFree(wndV);
  397. return cmOkRC;
  398. }
  399. cmSample_t* _cmPhatReadVector( cmCtx* ctx, cmPhat_t* p, const char* fn, unsigned* vnRef )
  400. {
  401. cmVectArray_t* vap = NULL;
  402. cmSample_t* v = NULL;
  403. cmRC_t rc = cmOkRC;
  404. // instantiate a VectArray from a file
  405. if( (vap = cmVectArrayAllocFromFile(ctx, fn )) == NULL )
  406. {
  407. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Id component vector file read failed '%s'.",fn);
  408. goto errLabel;
  409. }
  410. // get the count of elements in the vector
  411. *vnRef = cmVectArrayEleCount(vap);
  412. // allocate memory to hold the vector
  413. v = cmMemAlloc(cmSample_t,*vnRef);
  414. // copy the vector from the vector array object into v[]
  415. if((rc = cmVectArrayGetF(vap,v,vnRef)) != cmOkRC )
  416. {
  417. cmMemFree(v);
  418. v = NULL;
  419. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Id component vector copy out failed '%s'.",fn);
  420. goto errLabel;
  421. }
  422. cmRptPrintf(p->obj.err.rpt,"%i : %s",*vnRef,fn);
  423. errLabel:
  424. cmVectArrayFree(&vap);
  425. return v;
  426. }
  427. cmRC_t cmPhatExec( cmPhat_t* p, const cmSample_t* xV, unsigned xN )
  428. {
  429. unsigned n = cmMin(xN,p->fhN-p->di);
  430. // update the delay line
  431. cmVOS_Copy(p->dV+p->di,n,xV);
  432. if( n < xN )
  433. cmVOS_Copy(p->dV,xN-n,xV+n);
  434. p->di = cmModIncr(p->di,xN,p->fhN);
  435. // p->absIdx is the absolute sample index associated with di
  436. p->absIdx += xN;
  437. return cmOkRC;
  438. }
  439. void cmPhatChExec(
  440. cmPhat_t* p,
  441. unsigned chIdx,
  442. unsigned sessionId,
  443. unsigned roleId)
  444. {
  445. unsigned n0 = p->fhN - p->di;
  446. unsigned n1 = p->fhN - n0;
  447. // Linearize the delay line into xV[]
  448. cmVOS_Copy(p->xV, n0, p->dV + p->di );
  449. cmVOS_Copy(p->xV+n0, n1, p->dV );
  450. if( cmIsFlag(p->flags,kDebugAtPhatFl))
  451. cmVectArrayAppendS(p->ftVa, p->xV, p->fhN );
  452. // apply a window function to the incoming signal
  453. if( cmIsFlag(p->flags,kHannAtPhatFl) )
  454. cmVOS_MultVV(p->xV,p->fhN,p->wndV);
  455. // Take the FFT of the delay line.
  456. // p->t0V[p->binN] = fft(p->xV)
  457. //atFftRealForward(p->fftH, p->xV, p->fhN, p->t0V, p->binN );
  458. cmFftExecSR(&p->fft, p->xV, p->fhN );
  459. // Calc. the Cross Power Spectrum (aka cross spectral density) of the
  460. // input signal with the id signal.
  461. // Note that the CPS is equivalent to the Fourier Transform of the
  462. // cross-correlation of the two signals.
  463. // t0V[] *= p->fhM[:,chIdx]
  464. //atFftComplexMult( p->t0V, p->fhM + (chIdx * p->fhN), p->binN );
  465. cmVOCR_MultVVV( p->t0V, p->fft.complexV, p->fhM + (chIdx * p->fhN), p->binN);
  466. // Calculate the magnitude of the CPS.
  467. // xV[] = | t0V[] |
  468. cmVOCR_Abs( p->xV, p->t0V, p->binN );
  469. // Weight the CPS by the scaled magnitude of the id signal
  470. // (we want to emphasize the limited frequencies where the
  471. // id signal contains energy)
  472. // t0V[] *= p->mhM[:,chIdx]
  473. if( p->alpha > 0 )
  474. cmVOCR_MultVFV( p->t0V, p->mhM + (chIdx*p->binN), p->binN);
  475. // Divide through by the magnitude of the CPS
  476. // This has the effect of whitening the spectram and thereby
  477. // minimizing the effect of the magnitude correlation
  478. // while maximimizing the effect of the phase correlation.
  479. //
  480. // t0V[] /= xV[]
  481. cmVOCR_DivVFV( p->t0V, p->xV, p->binN );
  482. // Take the IFFT of the weighted CPS to recover the cross correlation.
  483. // xV[] = IFFT(t0V[])
  484. cmIFftExecRS( &p->ifft, p->t0V );
  485. // Normalize the result by the length of the transform.
  486. cmVOS_DivVVS( p->xV, p->fhN, p->ifft.outV, p->fhN );
  487. // Shift the correlation spike to mark the end of the id
  488. cmVOS_Rotate( p->xV, p->fhN, -((int)p->hN) );
  489. // normalize by the length of the correlation
  490. cmVOS_DivVS(p->xV,p->fhN,p->fhN);
  491. if( cmIsFlag(p->flags,kDebugAtPhatFl))
  492. {
  493. cmVectArrayAppendS(p->ftVa, p->xV, p->fhN );
  494. cmSample_t v[] = { sessionId, roleId };
  495. cmVectArrayAppendS(p->ftVa, v, sizeof(v)/sizeof(v[0]));
  496. }
  497. }
  498. cmRC_t cmPhatWrite( cmPhat_t* p, const char* dirStr )
  499. {
  500. cmRC_t rc = cmOkRC;
  501. if( cmIsFlag(p->flags, kDebugAtPhatFl))
  502. {
  503. const char* path = NULL;
  504. if( cmVectArrayCount(p->ftVa) )
  505. if((rc = cmVectArrayWrite(p->ftVa, path = cmFsMakeFn(path,"cmPhatFT","va",dirStr,NULL) )) != cmOkRC )
  506. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"PHAT debug file write failed.");
  507. cmFsFreeFn(path);
  508. }
  509. return rc;
  510. }
  511. //=======================================================================================================================
  512. //
  513. //
  514. cmReflectCalc_t* cmReflectCalcAlloc( cmCtx* ctx, cmReflectCalc_t* p, const cmGoldSigArg_t* gsa, float phat_alpha, unsigned phat_mult )
  515. {
  516. cmReflectCalc_t* op = cmObjAlloc(cmReflectCalc_t,ctx,p);
  517. cmRC_t rc = cmOkRC;
  518. // allocate the Gold code signal generator
  519. if( (op->gs = cmGoldSigAlloc(ctx,NULL,NULL)) == NULL )
  520. {
  521. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Gold sig allocate failed.");
  522. goto errLabel;
  523. }
  524. // allocate the PHAT object
  525. if( (op->phat = cmPhatAlloc(ctx,NULL,0,0,0,0,0)) == NULL )
  526. {
  527. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"PHAT allocate failed.");
  528. goto errLabel;
  529. }
  530. op->phVa = cmVectArrayAlloc(ctx,kSampleVaFl);
  531. op->xVa = cmVectArrayAlloc(ctx,kSampleVaFl);
  532. op->yVa = cmVectArrayAlloc(ctx,kSampleVaFl);
  533. // allocate 'this'
  534. if( gsa != NULL )
  535. rc = cmReflectCalcInit(op,gsa,phat_alpha,phat_mult);
  536. errLabel:
  537. if( rc != cmOkRC )
  538. cmReflectCalcFree(&op);
  539. return op;
  540. }
  541. cmRC_t cmReflectCalcFree( cmReflectCalc_t** pp )
  542. {
  543. cmRC_t rc = cmOkRC;
  544. if( pp == NULL || *pp == NULL )
  545. return rc;
  546. cmReflectCalc_t* p = *pp;
  547. cmReflectCalcWrite(p,"/Users/kevin/temp/kc");
  548. if((rc = cmReflectCalcFinal(p)) != cmOkRC )
  549. return rc;
  550. cmMemFree(p->t0V);
  551. cmMemFree(p->t1V);
  552. cmVectArrayFree(&p->phVa);
  553. cmVectArrayFree(&p->xVa);
  554. cmVectArrayFree(&p->yVa);
  555. cmGoldSigFree(&p->gs);
  556. cmPhatFree(&p->phat);
  557. cmMemFree(p);
  558. *pp = NULL;
  559. return rc;
  560. }
  561. cmRC_t cmReflectCalcInit( cmReflectCalc_t* p, const cmGoldSigArg_t* gsa, float phat_alpha, unsigned phat_mult )
  562. {
  563. cmRC_t rc;
  564. if((rc = cmReflectCalcFinal(p)) != cmOkRC )
  565. return rc;
  566. // initialize the Gold code signal generator
  567. if((rc = cmGoldSigInit(p->gs,gsa)) != cmOkRC )
  568. {
  569. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"Gold code signal initialize failed.");
  570. goto errLabel;
  571. }
  572. unsigned phat_chN = 1;
  573. unsigned phat_hN = p->gs->sigN;
  574. unsigned phat_flags = 0;
  575. unsigned phat_chIdx = 0;
  576. // initialize the PHAT
  577. if((rc = cmPhatInit(p->phat,phat_chN,phat_hN,phat_alpha,phat_mult,phat_flags)) != cmOkRC )
  578. {
  579. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"PHAT intialize failed.");
  580. goto errLabel;
  581. }
  582. // register a target signal with the PHAT
  583. if((rc = cmPhatSetId( p->phat, phat_chIdx, p->gs->ch[phat_chIdx].mdV, p->gs->sigN )) != cmOkRC )
  584. {
  585. rc = cmCtxRtCondition(&p->obj,cmSubSysFailRC,"PHAT signal registration failed.");
  586. goto errLabel;
  587. }
  588. p->xi = 0;
  589. p->tN = 5;
  590. p->t0V = cmMemResizeZ(unsigned,p->t0V,p->tN);
  591. p->t1V = cmMemResizeZ(unsigned,p->t1V,p->tN);
  592. p->ti = 0;
  593. p->t = 0;
  594. errLabel:
  595. return rc;
  596. }
  597. cmRC_t cmReflectCalcFinal( cmReflectCalc_t* p )
  598. {
  599. cmGoldSigFinal(p->gs);
  600. cmPhatFinal(p->phat);
  601. return cmOkRC;
  602. }
  603. /*
  604. cmRC_t cmReflectCalcExec( cmReflectCalc_t* p, const cmSample_t* xV, cmSample_t* yV, unsigned xyN )
  605. {
  606. unsigned i;
  607. // feed audio into the PHAT's buffer
  608. cmPhatExec(p->phat,xV,xyN);
  609. // fill the output buffer
  610. for(i=0; i<xyN; ++i,++p->xi)
  611. {
  612. if( p->xi < p->gs->sigN )
  613. yV[i] = p->gs->ch[0].mdV[p->xi];
  614. else
  615. yV[i] = 0;
  616. // if the PHAT has a complete buffer
  617. if( p->xi == p->phat->fhN )
  618. {
  619. p->xi = 0;
  620. // execute the correlation
  621. cmPhatChExec(p->phat,0,0,0);
  622. // p->phat->xV[fhN] now holds the correlation result
  623. if( p->phVa != NULL )
  624. cmVectArrayAppendS(p->phVa,p->phat->xV,p->phat->fhN );
  625. }
  626. }
  627. cmVectArrayAppendS(p->xVa,xV,xyN);
  628. cmVectArrayAppendS(p->yVa,yV,xyN);
  629. return cmOkRC;
  630. }
  631. */
  632. cmRC_t cmReflectCalcExec( cmReflectCalc_t* p, const cmSample_t* xV, cmSample_t* yV, unsigned xyN )
  633. {
  634. unsigned i;
  635. unsigned xyN0 = xyN;
  636. while(xyN0)
  637. {
  638. // feed audio into the PHAT's buffer
  639. unsigned di = p->phat->di;
  640. unsigned n = cmMin(xyN0,p->phat->fhN - di );
  641. cmPhatExec(p->phat,xV,n);
  642. if( di + n == p->phat->fhN )
  643. {
  644. // execute the correlation
  645. cmPhatChExec(p->phat,0,0,0);
  646. // p->phat->xV[fhN] now holds the correlation result
  647. // get the peak index
  648. p->t1V[p->ti] = cmVOS_MaxIndex(p->phat->xV,p->phat->fhN,1);
  649. printf("%i %i\n",p->t,p->t1V[p->ti]);
  650. p->ti = (p->ti + 1) % p->tN;
  651. // store the correlation result
  652. if( p->phVa != NULL )
  653. cmVectArrayAppendS(p->phVa,p->phat->xV,p->phat->fhN );
  654. }
  655. xyN0 -= n;
  656. }
  657. // fill the output buffer
  658. for(i=0; i<xyN; ++i)
  659. {
  660. if( p->xi == 0 )
  661. p->t0V[p->ti] = p->t + i;
  662. if( p->xi < p->gs->sigN )
  663. yV[i] = p->gs->ch[0].mdV[p->xi];
  664. else
  665. yV[i] = 0;
  666. p->xi = (p->xi+1) % p->phat->fhN;
  667. }
  668. p->t += xyN;
  669. if( p->xVa != NULL )
  670. cmVectArrayAppendS(p->xVa,xV,xyN);
  671. if( p->yVa != NULL )
  672. cmVectArrayAppendS(p->yVa,yV,xyN);
  673. return cmOkRC;
  674. }
  675. cmRC_t cmReflectCalcWrite( cmReflectCalc_t* p, const char* dirStr )
  676. {
  677. cmRC_t rc = cmOkRC;
  678. if( p->xVa != NULL)
  679. cmVectArrayWriteDirFn(p->xVa, dirStr, "reflect_calc_x.va" );
  680. if( p->yVa != NULL )
  681. cmVectArrayWriteDirFn(p->yVa, dirStr, "reflect_calc_y.va" );
  682. if( p->phVa != NULL )
  683. cmVectArrayWriteDirFn(p->phVa,dirStr, "reflect_calc_ph.va");
  684. return rc;
  685. }
  686. //=======================================================================================================================
  687. //
  688. //
  689. cmNlmsEc_t* cmNlmsEcAlloc( cmCtx* ctx, cmNlmsEc_t* ap, double srate, float mu, unsigned hN, unsigned delayN )
  690. {
  691. cmNlmsEc_t* p = cmObjAlloc(cmNlmsEc_t,ctx,ap);
  692. bool debugFl = false;
  693. // allocate the vect array's
  694. p->uVa = debugFl ? cmVectArrayAlloc(ctx, kFloatVaFl ) : NULL;
  695. p->fVa = debugFl ? cmVectArrayAlloc(ctx, kFloatVaFl ) : NULL;
  696. p->eVa = debugFl ? cmVectArrayAlloc(ctx, kFloatVaFl ) : NULL;
  697. if( srate != 0 )
  698. if( cmNlmsEcInit(p,srate,mu,hN,delayN) != cmOkRC )
  699. cmNlmsEcFree(&p);
  700. return p;
  701. }
  702. cmRC_t cmNlmsEcFree( cmNlmsEc_t** pp )
  703. {
  704. cmRC_t rc = cmOkRC;
  705. if( pp == NULL || *pp == NULL )
  706. return rc;
  707. cmNlmsEc_t* p = *pp;
  708. if((rc = cmNlmsEcFinal(p)) != cmOkRC )
  709. return rc;
  710. cmMemFree(p->wV);
  711. cmMemFree(p->hV);
  712. cmVectArrayFree(&p->eVa);
  713. cmObjFree(pp);
  714. return rc;
  715. }
  716. cmRC_t cmNlmsEcInit( cmNlmsEc_t* p, double srate, float mu, unsigned hN, unsigned delayN )
  717. {
  718. cmRC_t rc = cmOkRC;
  719. if((rc = cmNlmsEcFinal(p)) != cmOkRC )
  720. return rc;
  721. assert( srate >= hN );
  722. assert( srate >= delayN );
  723. p->mu = mu;
  724. p->hN = hN;
  725. p->delayN = cmMax(1,delayN);
  726. p->dN = srate;
  727. p->delayV = cmMemResizeZ(cmSample_t, p->delayV, srate );
  728. p->di = 0;
  729. p->wV = cmMemResizeZ(double,p->wV,srate);
  730. p->hV = cmMemResizeZ(double,p->hV,srate);
  731. p->w0i = 0;
  732. return rc;
  733. }
  734. cmRC_t cmNlmsEcFinal( cmNlmsEc_t* p )
  735. { return cmOkRC; }
  736. cmRC_t cmNlmsEcExec( cmNlmsEc_t* p, const cmSample_t* xV, const cmSample_t* fV, cmSample_t* yV, unsigned xyN )
  737. {
  738. // See: http://www.eit.lth.se/fileadmin/eit/courses/ett042/CE/CE2e.pdf
  739. // and http://www.eit.lth.se/fileadmin/eit/courses/ett042/CE/CE3e.pdf
  740. unsigned i;
  741. for(i=0; i<xyN; ++i)
  742. {
  743. double y = 0;
  744. unsigned k = 0;
  745. double a = 0.001;
  746. unsigned j;
  747. // Insert the next sample into the filter delay line.
  748. // Note that rather than shifting the delay line on each iteration we
  749. // increment the input location and then align it with the zeroth
  750. // weight below.
  751. p->hV[p->w0i] = p->delayV[ p->di ];
  752. p->delayV[ p->di ] = xV[i];
  753. p->di = (p->di + 1) % p->delayN;
  754. // calculate the output of the delay w0i:hN
  755. for(j=p->w0i,k=0; j<p->hN; ++j,++k)
  756. y += p->hV[j] * p->wV[k];
  757. // calcuate the output of the delay 0:w0i
  758. for(j=0; j<p->w0i; ++j,++k)
  759. y += p->hV[j] * p->wV[k];
  760. // calculate the error which is also the filter output
  761. double e = fV[i] - y;
  762. yV[i] = e;
  763. //
  764. double z = 0;
  765. for(j=0; j<p->hN; ++j)
  766. z += p->hV[j] * p->hV[j];
  767. // update weights 0 through w0i
  768. for(j=p->w0i,k=0; j<p->hN; ++j,++k)
  769. p->wV[k] += (p->mu/(a + z)) * p->hV[j] * e;
  770. // update weights w0i through hN
  771. for(j=0; j<p->w0i; ++j,++k)
  772. p->wV[k] += (p->mu/(a + z)) * p->hV[j] * e;
  773. // advance the delay
  774. p->w0i = (p->w0i+1) % p->hN;
  775. }
  776. if( p->uVa != NULL )
  777. cmVectArrayAppendS(p->uVa,xV,xyN);
  778. if( p->fVa != NULL )
  779. cmVectArrayAppendS(p->fVa,fV,xyN);
  780. if( p->eVa != NULL )
  781. cmVectArrayAppendS(p->eVa,yV,xyN);
  782. return cmOkRC;
  783. }
  784. cmRC_t cmNlmsEcWrite( cmNlmsEc_t* p, const cmChar_t* dirStr )
  785. {
  786. if( p->uVa != NULL )
  787. cmVectArrayWriteDirFn(p->uVa, dirStr, "nlms_unfiltered.va");
  788. if( p->fVa != NULL )
  789. cmVectArrayWriteDirFn(p->fVa, dirStr, "nlms_filtered.va");
  790. if( p->eVa != NULL )
  791. cmVectArrayWriteDirFn(p->eVa, dirStr, "nlms_out.va");
  792. return cmOkRC;
  793. }
  794. void cmNlmsEcSetMu( cmNlmsEc_t* p, float mu )
  795. {
  796. if( mu < 0 )
  797. p->mu = 0.0001;
  798. else
  799. if( mu >= 1 )
  800. p->mu = 0.99;
  801. else
  802. p->mu = mu;
  803. }
  804. void cmNlmsEcSetDelayN( cmNlmsEc_t* p, unsigned delayN )
  805. {
  806. if( delayN > p->dN)
  807. delayN = p->dN;
  808. else
  809. if( delayN < 1 )
  810. delayN = 1;
  811. cmVOS_Zero(p->delayV,p->delayN);
  812. p->delayN = delayN;
  813. }
  814. void cmNlmsEcSetIrN( cmNlmsEc_t* p, unsigned hN )
  815. {
  816. if( hN > p->dN )
  817. hN = p->dN;
  818. else
  819. if( hN < 1 )
  820. hN = 1;
  821. cmVOD_Zero(p->wV,p->hN);
  822. cmVOD_Zero(p->hV,p->hN);
  823. p->hN = hN;
  824. }
  825. //=======================================================================================================================
  826. //
  827. //
  828. cmSeqAlign_t* cmSeqAlignAlloc( cmCtx* ctx, cmSeqAlign_t* ap )
  829. {
  830. cmSeqAlign_t* p = cmObjAlloc(cmSeqAlign_t,ctx,ap);
  831. if( cmSeqAlignInit(p) != cmOkRC )
  832. cmSeqAlignFree(&p);
  833. return p;
  834. }
  835. cmRC_t cmSeqAlignFree( cmSeqAlign_t** pp )
  836. {
  837. cmRC_t rc = cmOkRC;
  838. if( pp == NULL || *pp == NULL )
  839. return rc;
  840. cmSeqAlign_t* p = *pp;
  841. if((rc = cmSeqAlignFinal(p)) != cmOkRC )
  842. return rc;
  843. while( p->seqL != NULL )
  844. {
  845. while( p->seqL->locL != NULL )
  846. {
  847. cmSeqAlignLoc_t* lp = p->seqL->locL->link;
  848. cmMemFree(p->seqL->locL->vV);
  849. cmMemFree(p->seqL->locL);
  850. p->seqL->locL = lp;
  851. }
  852. cmSeqAlignSeq_t* sp = p->seqL->link;
  853. cmMemFree(p->seqL);
  854. p->seqL = sp;
  855. }
  856. cmObjFree(pp);
  857. return rc;
  858. }
  859. cmRC_t cmSeqAlignInit( cmSeqAlign_t* p )
  860. { return cmOkRC; }
  861. cmRC_t cmSeqAlignFinal( cmSeqAlign_t* p )
  862. { return cmOkRC; }
  863. cmSeqAlignSeq_t* _cmSeqAlignIdToSeq( cmSeqAlign_t* p, unsigned seqId )
  864. {
  865. cmSeqAlignSeq_t* sp = p->seqL;
  866. for(; sp!=NULL; sp=sp->link)
  867. if( sp->id == seqId )
  868. return sp;
  869. return NULL;
  870. }
  871. cmSeqAlignLoc_t* _cmSeqAlignIdToLoc( cmSeqAlignSeq_t* sp, unsigned locId )
  872. {
  873. cmSeqAlignLoc_t* lp = sp->locL;
  874. for(; lp!=NULL; lp=lp->link)
  875. {
  876. // if the locId's match
  877. if( lp->id == locId )
  878. return lp;
  879. if( (lp->link != NULL && lp->link->id > locId) || lp->link==NULL )
  880. return lp; // return record previous to locId
  881. }
  882. // return NULL: locId is less than all other locations id's in the list
  883. return lp;
  884. }
  885. cmRC_t cmSeqAlignInsert( cmSeqAlign_t* p, unsigned seqId, unsigned locId, unsigned value )
  886. {
  887. cmSeqAlignSeq_t* sp;
  888. // if the requested sequence does not already exist ...
  889. if((sp = _cmSeqAlignIdToSeq(p,seqId)) == NULL )
  890. {
  891. // ... then create it
  892. sp = cmMemAllocZ(cmSeqAlignSeq_t,1);
  893. sp->id = seqId;
  894. if( p->seqL == NULL )
  895. p->seqL = sp;
  896. else
  897. {
  898. cmSeqAlignSeq_t* s0 = p->seqL;
  899. while( s0->link != NULL )
  900. s0 = s0->link;
  901. s0->link = sp;
  902. }
  903. }
  904. assert(sp != NULL);
  905. cmSeqAlignLoc_t* lp;
  906. // if the requested location does not exist in the requested sequence ...
  907. if((lp = _cmSeqAlignIdToLoc(sp,locId)) == NULL || lp->id != locId)
  908. {
  909. // ... then create it
  910. cmSeqAlignLoc_t* nlp = cmMemAllocZ(cmSeqAlignLoc_t,1);
  911. nlp->id = locId;
  912. // if lp is NULL then link nlp as first record in sequence
  913. if( lp == NULL )
  914. {
  915. // make new loc recd first on the list
  916. nlp->link = sp->locL;
  917. sp->locL = nlp;
  918. }
  919. else // otherwise link nlp after lp
  920. {
  921. nlp->link = lp->link;
  922. lp->link = nlp;
  923. }
  924. lp = nlp;
  925. }
  926. assert( lp!=NULL );
  927. // insert the new value
  928. lp->vV = cmMemResizeP(unsigned,lp->vV,lp->vN+1);
  929. lp->vV[ lp->vN ] = value;
  930. lp->vN += 1;
  931. return cmOkRC;
  932. }
  933. double _cmSeqAlignCompare( const cmSeqAlignLoc_t* l0, const cmSeqAlignLoc_t* l1)
  934. {
  935. double dist = 0;
  936. unsigned i=0;
  937. for(i=0; i<l0->vN; ++i)
  938. {
  939. unsigned j=0;
  940. for(j=0; j<l1->vN; ++j)
  941. if( l0->vV[i] == l1->vV[j] )
  942. break;
  943. if( l0->vV[i] != l1->vV[j] )
  944. dist += 1.0;
  945. }
  946. return dist;
  947. }
  948. cmRC_t cmSeqAlignExec( cmSeqAlign_t* p )
  949. {
  950. return cmOkRC;
  951. }
  952. void _cmSeqAlignReportLoc( cmRpt_t* rpt, const cmSeqAlignLoc_t* lp )
  953. {
  954. //cmRptPrintf(rpt,"%5i : ",lp->id);
  955. unsigned i;
  956. for(i=0; i<lp->vN; ++i)
  957. {
  958. //cmRptPrintf(rpt,"%3i ",lp->vV[i]);
  959. cmRptPrintf(rpt,"%4s ",cmMidiToSciPitch(lp->vV[i],NULL,0));
  960. }
  961. cmRptPrintf(rpt," | ");
  962. }
  963. void cmSeqAlignReport( cmSeqAlign_t* p, cmRpt_t* rpt )
  964. {
  965. cmSeqAlignLoc_t* slp = p->seqL->locL;
  966. for(; slp!=NULL; slp=slp->link)
  967. {
  968. cmRptPrintf(rpt,"%5i : ",slp->id);
  969. // report the next location on the first sequence as the reference location
  970. _cmSeqAlignReportLoc( rpt, slp );
  971. // for each remaining sequence
  972. cmSeqAlignSeq_t* sp = p->seqL->link;
  973. for(; sp!=NULL; sp=sp->link)
  974. {
  975. // locate the location with the same id as the reference location ...
  976. cmSeqAlignLoc_t* lp;
  977. if((lp = _cmSeqAlignIdToLoc(sp,slp->id)) != NULL && lp->id == slp->id)
  978. {
  979. _cmSeqAlignReportLoc(rpt,lp); // ... and report it
  980. }
  981. }
  982. cmRptPrintf(rpt,"\n");
  983. }
  984. }