|
@@ -8,6 +8,7 @@
|
8
|
8
|
#include "cmLinkedHeap.h"
|
9
|
9
|
#include "cmFloatTypes.h"
|
10
|
10
|
#include "cmComplexTypes.h"
|
|
11
|
+#include "cmFile.h"
|
11
|
12
|
#include "cmFileSys.h"
|
12
|
13
|
#include "cmJson.h"
|
13
|
14
|
#include "cmSymTbl.h"
|
|
@@ -16,11 +17,12 @@
|
16
|
17
|
#include "cmProcObj.h"
|
17
|
18
|
#include "cmProcTemplate.h"
|
18
|
19
|
#include "cmMath.h"
|
19
|
|
-#include "cmProc.h"
|
20
|
|
-#include "cmVectOps.h"
|
21
|
20
|
#include "cmTime.h"
|
22
|
21
|
#include "cmMidi.h"
|
23
|
22
|
#include "cmMidiFile.h"
|
|
23
|
+#include "cmProc.h"
|
|
24
|
+#include "cmProc2.h"
|
|
25
|
+#include "cmVectOps.h"
|
24
|
26
|
#include "cmTimeLine.h"
|
25
|
27
|
#include "cmScore.h"
|
26
|
28
|
#include "cmProc4.h"
|
|
@@ -4546,3 +4548,297 @@ cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_
|
4546
|
4548
|
return cmOkRC;
|
4547
|
4549
|
}
|
4548
|
4550
|
|
|
4551
|
+//=======================================================================================================================
|
|
4552
|
+
|
|
4553
|
+cmFrqTrk* cmFrqTrkAlloc( cmCtx* c, cmFrqTrk* p, const cmFrqTrkArgs_t* a )
|
|
4554
|
+{
|
|
4555
|
+ cmFrqTrk* op = cmObjAlloc(cmFrqTrk,c,p);
|
|
4556
|
+
|
|
4557
|
+ op->bmf = cmBinMtxFileAlloc(c,NULL,NULL);
|
|
4558
|
+
|
|
4559
|
+ if( cmFrqTrkInit(op,a) != cmOkRC )
|
|
4560
|
+ cmFrqTrkFree(&op);
|
|
4561
|
+
|
|
4562
|
+ return op;
|
|
4563
|
+
|
|
4564
|
+}
|
|
4565
|
+
|
|
4566
|
+cmRC_t cmFrqTrkFree( cmFrqTrk** pp )
|
|
4567
|
+{
|
|
4568
|
+ cmRC_t rc = cmOkRC;
|
|
4569
|
+
|
|
4570
|
+ if( pp==NULL || *pp==NULL )
|
|
4571
|
+ return rc;
|
|
4572
|
+
|
|
4573
|
+ cmFrqTrk* p = *pp;
|
|
4574
|
+ if((rc = cmFrqTrkFinal(p)) != cmOkRC )
|
|
4575
|
+ return rc;
|
|
4576
|
+
|
|
4577
|
+ cmMemFree(p->ch);
|
|
4578
|
+ cmMemFree(p->dbM);
|
|
4579
|
+ cmMemFree(p->pkiV);
|
|
4580
|
+ cmMemFree(p->dbV);
|
|
4581
|
+ cmBinMtxFileFree(&p->bmf);
|
|
4582
|
+ cmObjFree(pp);
|
|
4583
|
+ return rc;
|
|
4584
|
+
|
|
4585
|
+}
|
|
4586
|
+
|
|
4587
|
+cmRC_t cmFrqTrkInit( cmFrqTrk* p, const cmFrqTrkArgs_t* a )
|
|
4588
|
+{
|
|
4589
|
+ cmRC_t rc;
|
|
4590
|
+ if((rc = cmFrqTrkFinal(p)) != cmOkRC )
|
|
4591
|
+ return rc;
|
|
4592
|
+
|
|
4593
|
+ p->a = *a;
|
|
4594
|
+ p->ch = cmMemResizeZ(cmFrqTrkCh_t,p->ch,a->chCnt );
|
|
4595
|
+ p->hN = cmMax(1,a->wndSecs * a->srate / a->hopSmpCnt );
|
|
4596
|
+ p->bN = p->a.binCnt;
|
|
4597
|
+ p->dbM = cmMemResizeZ(cmReal_t,p->dbM,p->hN*p->bN);
|
|
4598
|
+ p->hi = 0;
|
|
4599
|
+ p->dbV = cmMemResizeZ(cmReal_t,p->dbV,p->bN);
|
|
4600
|
+ p->pkiV = cmMemResizeZ(unsigned,p->pkiV,p->bN);
|
|
4601
|
+ p->deadN_max = a->maxTrkDeadSec * a->srate / a->hopSmpCnt;
|
|
4602
|
+ p->minTrkN = a->minTrkSec * a->srate / a->hopSmpCnt;
|
|
4603
|
+ p->nextTrkId = 0;
|
|
4604
|
+
|
|
4605
|
+ if( a->logFn != NULL )
|
|
4606
|
+ {
|
|
4607
|
+ if( cmBinMtxFileInit(p->bmf, a->logFn ) != cmOkRC )
|
|
4608
|
+ cmCtxRtCondition(&p->obj, cmSubSysFailRC, "Log file open failed on '%s'.",cmStringNullGuard(a->logFn));
|
|
4609
|
+ }
|
|
4610
|
+
|
|
4611
|
+ return rc;
|
|
4612
|
+}
|
|
4613
|
+
|
|
4614
|
+cmRC_t cmFrqTrkFinal( cmFrqTrk* p )
|
|
4615
|
+{
|
|
4616
|
+ cmRC_t rc = cmOkRC;
|
|
4617
|
+ cmBinMtxFileFinal(p->bmf);
|
|
4618
|
+ return rc;
|
|
4619
|
+}
|
|
4620
|
+
|
|
4621
|
+// Return an available channel record or NULL if all channel records are in use.
|
|
4622
|
+cmFrqTrkCh_t* _cmFrqTrkFindAvailCh( cmFrqTrk* p )
|
|
4623
|
+{
|
|
4624
|
+ unsigned i;
|
|
4625
|
+ for(i=0; i<p->a.chCnt; ++i)
|
|
4626
|
+ if( p->ch[i].activeFl == false )
|
|
4627
|
+ return p->ch + i;
|
|
4628
|
+
|
|
4629
|
+ return NULL;
|
|
4630
|
+}
|
|
4631
|
+
|
|
4632
|
+unsigned _cmFrqTrkActiveChCount( cmFrqTrk* p )
|
|
4633
|
+{
|
|
4634
|
+ unsigned n = 0;
|
|
4635
|
+ unsigned i;
|
|
4636
|
+ for(i=0; i<p->a.chCnt; ++i)
|
|
4637
|
+ if( p->ch[i].activeFl )
|
|
4638
|
+ ++n;
|
|
4639
|
+
|
|
4640
|
+ return n;
|
|
4641
|
+}
|
|
4642
|
+
|
|
4643
|
+void _cmFrqTrkWriteLog( cmFrqTrk* p )
|
|
4644
|
+{
|
|
4645
|
+ unsigned n;
|
|
4646
|
+
|
|
4647
|
+ if( cmBinMtxFileIsValid(p->bmf) == false )
|
|
4648
|
+ return;
|
|
4649
|
+
|
|
4650
|
+ if((n = _cmFrqTrkActiveChCount(p)) > 0 )
|
|
4651
|
+ {
|
|
4652
|
+ unsigned i,j;
|
|
4653
|
+ unsigned nn = n*4;
|
|
4654
|
+ cmReal_t* v = cmMemAllocZ(cmReal_t,nn);
|
|
4655
|
+ cmReal_t* idV = v + n * 0;
|
|
4656
|
+ cmReal_t* hzV = v + n * 1;
|
|
4657
|
+ cmReal_t* dbV = v + n * 2;
|
|
4658
|
+ cmReal_t* stV = v + n * 3;
|
|
4659
|
+
|
|
4660
|
+ for(i=0,j=0; i<p->a.chCnt; ++i)
|
|
4661
|
+ if( p->ch[i].activeFl )
|
|
4662
|
+ {
|
|
4663
|
+ assert(j < n);
|
|
4664
|
+
|
|
4665
|
+ idV[j] = p->ch[i].id;
|
|
4666
|
+ hzV[j] = p->ch[i].hz;
|
|
4667
|
+ dbV[j] = p->ch[i].db;
|
|
4668
|
+ stV[j] = p->ch[i].dN;
|
|
4669
|
+
|
|
4670
|
+ ++j;
|
|
4671
|
+ }
|
|
4672
|
+
|
|
4673
|
+ cmBinMtxFileExecR(p->bmf, v, nn );
|
|
4674
|
+ }
|
|
4675
|
+}
|
|
4676
|
+
|
|
4677
|
+void _cmFrqTrkPrintChs( const cmFrqTrk* p )
|
|
4678
|
+{
|
|
4679
|
+ unsigned i;
|
|
4680
|
+ for(i=0; i<p->a.chCnt; ++i)
|
|
4681
|
+ {
|
|
4682
|
+ cmFrqTrkCh_t* c = p->ch + i;
|
|
4683
|
+ printf("%i : %i tN:%i hz:%f db:%f\n",i,c->activeFl,c->tN,c->hz,c->db);
|
|
4684
|
+ }
|
|
4685
|
+}
|
|
4686
|
+
|
|
4687
|
+// Used to sort the channels into descending dB order.
|
|
4688
|
+int _cmFrqTrkChCompare( const void* p0, const void* p1 )
|
|
4689
|
+{ return ((cmFrqTrkCh_t*)p0)->db - ((cmFrqTrkCh_t*)p1)->db; }
|
|
4690
|
+
|
|
4691
|
+
|
|
4692
|
+// Return the index of the peak associated with pkiV[i] which best matches the tracker 'c'
|
|
4693
|
+// or cmInvalidIdx if no valid peaks were found.
|
|
4694
|
+// pkiV[ pkN ] holds the indexes into dbV[] and hzV[] which are peaks.
|
|
4695
|
+// Some elements of pkiV[] may be set to cmInvalidIdx if the associated peak has already
|
|
4696
|
+// been selected by another tracker.
|
|
4697
|
+unsigned _cmFrqTrkFindPeak( cmFrqTrk* p, const cmFrqTrkCh_t* c, const cmReal_t* dbV, const cmReal_t* hzV, unsigned* pkiV, unsigned pkN )
|
|
4698
|
+{
|
|
4699
|
+ unsigned i,pki;
|
|
4700
|
+ cmReal_t d_max = p->a.pkThreshDb;
|
|
4701
|
+ unsigned d_idx = cmInvalidIdx;
|
|
4702
|
+
|
|
4703
|
+ cmReal_t hz_min = c->hz * pow(2,-p->a.stRange/12.0);
|
|
4704
|
+ cmReal_t hz_max = c->hz * pow(2,-p->a.stRange/12.0);
|
|
4705
|
+
|
|
4706
|
+ // find the peak with the most energy inside the frequency range hz_min to hz_max.
|
|
4707
|
+ for(i=0; i<pkN; ++i)
|
|
4708
|
+ if( ((pki = pkiV[i]) != cmInvalidIdx) && hz_min <= hzV[pki] && hzV[pki] <= hz_max && dbV[pki]>d_max )
|
|
4709
|
+ {
|
|
4710
|
+ d_max= dbV[pki];
|
|
4711
|
+ d_idx = i;
|
|
4712
|
+ }
|
|
4713
|
+
|
|
4714
|
+ return d_idx;
|
|
4715
|
+}
|
|
4716
|
+
|
|
4717
|
+// Extend the existing trackers
|
|
4718
|
+void _cmFrqTrkUpdateChs( cmFrqTrk* p, const cmReal_t* dbV, const cmReal_t* hzV, unsigned* pkiV, unsigned pkN )
|
|
4719
|
+{
|
|
4720
|
+ unsigned i;
|
|
4721
|
+
|
|
4722
|
+ // sort the channels in descending order
|
|
4723
|
+ qsort(p->ch,p->a.chCnt,sizeof(cmFrqTrkCh_t),_cmFrqTrkChCompare);
|
|
4724
|
+
|
|
4725
|
+ // for each active channel
|
|
4726
|
+ for(i=0; i<p->a.chCnt; ++i)
|
|
4727
|
+ {
|
|
4728
|
+ cmFrqTrkCh_t* c = p->ch + i;
|
|
4729
|
+
|
|
4730
|
+ if( c->activeFl )
|
|
4731
|
+ {
|
|
4732
|
+ unsigned pki;
|
|
4733
|
+
|
|
4734
|
+ // if no matching peak was found to tracker 'c'.
|
|
4735
|
+ if((pki = _cmFrqTrkFindPeak(p,c,dbV,hzV,pkiV,pkN)) == cmInvalidIdx )
|
|
4736
|
+ {
|
|
4737
|
+ c->dN += 1;
|
|
4738
|
+ c->tN += 1;
|
|
4739
|
+
|
|
4740
|
+ if( c->dN >= p->deadN_max )
|
|
4741
|
+ c->activeFl = false;
|
|
4742
|
+ }
|
|
4743
|
+ else // ... update the tracker using the matching peak
|
|
4744
|
+ {
|
|
4745
|
+ unsigned j = pkiV[pki];
|
|
4746
|
+ c->dN = 0;
|
|
4747
|
+ c->db = dbV[ j ];
|
|
4748
|
+ c->hz = hzV[ j ];
|
|
4749
|
+ c->tN += 1;
|
|
4750
|
+ pkiV[pki] = cmInvalidIdx; // mark the peak as unavailable.
|
|
4751
|
+ }
|
|
4752
|
+ }
|
|
4753
|
+ }
|
|
4754
|
+}
|
|
4755
|
+
|
|
4756
|
+// Return the index into pkiV[] of the maximum energy peak in dbV[]
|
|
4757
|
+// that is also above kAtkThreshDb.
|
|
4758
|
+unsigned _cmFrqTrkMaxEnergyPeakIndex( const cmFrqTrk* p, const cmReal_t* dbV, const unsigned* pkiV, unsigned pkN )
|
|
4759
|
+{
|
|
4760
|
+ cmReal_t mv = p->a.pkAtkThreshDb;
|
|
4761
|
+ unsigned mi = cmInvalidIdx;
|
|
4762
|
+ unsigned i;
|
|
4763
|
+
|
|
4764
|
+ for(i=0; i<pkN; ++i)
|
|
4765
|
+ if( pkiV[i] != cmInvalidIdx && dbV[pkiV[i]] >= mv )
|
|
4766
|
+ {
|
|
4767
|
+ mi = i;
|
|
4768
|
+ mv = dbV[pkiV[i]];
|
|
4769
|
+ }
|
|
4770
|
+
|
|
4771
|
+ return mi;
|
|
4772
|
+}
|
|
4773
|
+
|
|
4774
|
+// start new trackers
|
|
4775
|
+void _cmFrqTrkNewChs( cmFrqTrk* p, const cmReal_t* dbV, const cmReal_t* hzV, unsigned* pkiV, unsigned pkN )
|
|
4776
|
+{
|
|
4777
|
+
|
|
4778
|
+ while(1)
|
|
4779
|
+ {
|
|
4780
|
+ unsigned db_max_idx;
|
|
4781
|
+ cmFrqTrkCh_t* c;
|
|
4782
|
+
|
|
4783
|
+ if((c = _cmFrqTrkFindAvailCh(p)) == NULL )
|
|
4784
|
+ break;
|
|
4785
|
+
|
|
4786
|
+ if((db_max_idx = _cmFrqTrkMaxEnergyPeakIndex(p,dbV,pkiV,pkN)) == cmInvalidIdx )
|
|
4787
|
+ break;
|
|
4788
|
+
|
|
4789
|
+ c->activeFl = true;
|
|
4790
|
+ c->tN = 1;
|
|
4791
|
+ c->dN = 0;
|
|
4792
|
+ c->hz = hzV[ pkiV[ db_max_idx ] ];
|
|
4793
|
+ c->db = dbV[ pkiV[ db_max_idx ] ];
|
|
4794
|
+ c->id = p->nextTrkId++;
|
|
4795
|
+
|
|
4796
|
+ pkiV[ db_max_idx ] = cmInvalidIdx;
|
|
4797
|
+ }
|
|
4798
|
+
|
|
4799
|
+}
|
|
4800
|
+
|
|
4801
|
+
|
|
4802
|
+cmRC_t cmFrqTrkExec( cmFrqTrk* p, const cmReal_t* magV, const cmReal_t* phsV, const cmReal_t* hzV )
|
|
4803
|
+{
|
|
4804
|
+ cmRC_t rc = cmOkRC;
|
|
4805
|
+
|
|
4806
|
+ // convert magV to Decibels
|
|
4807
|
+ cmVOR_AmplitudeToDb(p->dbV,p->bN,magV);
|
|
4808
|
+
|
|
4809
|
+ // copy p->dbV to dbM[hi,:]
|
|
4810
|
+ cmVOR_CopyN(p->dbM + p->hi, p->hN, p->bN, p->dbV, 1 );
|
|
4811
|
+
|
|
4812
|
+ // increment hi
|
|
4813
|
+ p->hi = (p->hi + 1) % p->hN;
|
|
4814
|
+
|
|
4815
|
+ // Form the spectral magnitude profile by taking the mean over time
|
|
4816
|
+ // of the last hN magnitude vectors
|
|
4817
|
+ cmVOR_MeanM(p->dbV, p->dbM, p->hN, p->bN, 0);
|
|
4818
|
+
|
|
4819
|
+ // set the indexes of the peaks above pkThreshDb in i0[]
|
|
4820
|
+ unsigned pkN = cmVOR_PeakIndexes(p->pkiV, p->bN, p->dbV, p->bN, p->a.pkThreshDb );
|
|
4821
|
+
|
|
4822
|
+ // extend the existing trackers
|
|
4823
|
+ _cmFrqTrkUpdateChs(p, p->dbV, hzV, p->pkiV, pkN );
|
|
4824
|
+
|
|
4825
|
+ // create new trackers
|
|
4826
|
+ _cmFrqTrkNewChs(p,p->dbV,hzV,p->pkiV,pkN);
|
|
4827
|
+
|
|
4828
|
+ return rc;
|
|
4829
|
+}
|
|
4830
|
+
|
|
4831
|
+void cmFrqTrkPrint( cmFrqTrk* p )
|
|
4832
|
+{
|
|
4833
|
+ printf("srate: %f\n",p->a.srate);
|
|
4834
|
+ printf("chCnt: %i\n",p->a.chCnt);
|
|
4835
|
+ printf("binCnt: %i\n",p->a.binCnt);
|
|
4836
|
+ printf("hopSmpCnt: %i\n",p->a.hopSmpCnt);
|
|
4837
|
+ printf("stRange: %f\n",p->a.stRange);
|
|
4838
|
+ printf("wndSecs: %f (%i)\n",p->a.wndSecs,p->hN);
|
|
4839
|
+ printf("minTrkSec: %f (%i)\n",p->a.minTrkSec,p->minTrkN);
|
|
4840
|
+ printf("maxTrkDeadSec: %f (%i)\n",p->a.maxTrkDeadSec,p->deadN_max);
|
|
4841
|
+ printf("pkThreshDb: %f\n",p->a.pkThreshDb);
|
|
4842
|
+ printf("pkAtkThreshDb: %f\n",p->a.pkAtkThreshDb);
|
|
4843
|
+
|
|
4844
|
+}
|