1+ #ifndef __PitchDetectors_hpp__
2+ #define __PitchDetectors_hpp__
3+
4+ #include " FloatArray.h"
5+
6+ class ZeroCrossingPitchDetector {
7+ private:
8+ BiquadFilter *filter;
9+ int numLowPassStages;
10+ int numHighPassStages;
11+ FloatArray counts;
12+ FloatArray filterOutput;
13+ float samplingRate;
14+ public:
15+ ZeroCrossingPitchDetector (): samplingRate(48000 ), numLowPassStages(1 ), numHighPassStages(0 ){
16+ init (0 );
17+ };
18+ ZeroCrossingPitchDetector (float aSamplingRate, int aMaxBlocksize):numLowPassStages(1 ), numHighPassStages(0 ){
19+ samplingRate=aSamplingRate;
20+ init (aMaxBlocksize);
21+ };
22+ ZeroCrossingPitchDetector (float aSamplingRate, int aMaxBlocksize, int aNumLowPassStages, int aNumHighPassStages){
23+ samplingRate=aSamplingRate;
24+ init (aMaxBlocksize);
25+ }
26+ ~ZeroCrossingPitchDetector (){
27+ FloatArray::destroy (counts);
28+ FloatArray::destroy (filterOutput);
29+ BiquadFilter::destroy (filter);
30+ }
31+ void init (int aMaxBlocksize){
32+ setMaxBlocksize (aMaxBlocksize);
33+ counts=FloatArray::create (10 ); // number of zcc to be averaged
34+ counts.setAll (0 );
35+ filter=BiquadFilter::create (numLowPassStages+numHighPassStages);
36+ setLowPassCutoff (0.03 );
37+ setHighPassCutoff (0.001 );
38+ };
39+ void setSamplingRate (float aSamplingRate){
40+ samplingRate=aSamplingRate;
41+ }
42+ void setMaxBlocksize (int aMaxBlocksize){
43+ FloatArray::destroy (filterOutput);
44+ filterOutput=FloatArray::create (aMaxBlocksize);
45+ }
46+ void setLowPassCutoff (float fc){
47+ if (numLowPassStages<1 )
48+ return ;
49+ FilterStage stage0=filter->getFilterStage (0 );
50+ stage0.setLowPass (fc/samplingRate, FilterStage::BUTTERWORTH_Q);
51+ for (int n=1 ; n<numLowPassStages; n++){
52+ FilterStage stage=filter->getFilterStage (n);
53+ stage.setCoefficients (FloatArray (stage0.getCoefficients (), 5 ));
54+ }
55+ };
56+ void setHighPassCutoff (float fc){
57+ if (numHighPassStages<1 )
58+ return ;
59+ FilterStage stage0=filter->getFilterStage (numLowPassStages);
60+ stage0.setHighPass (fc/samplingRate, FilterStage::BUTTERWORTH_Q);
61+ for (int n=numLowPassStages+1 ; n<numHighPassStages+numLowPassStages; n++){
62+ FilterStage stage=filter->getFilterStage (n);
63+ stage.setCoefficients (stage0.getCoefficients ());
64+ }
65+ };
66+ void process (FloatArray input){
67+ ASSERT (input.getSize ()<=filterOutput.getSize (), " wrong size" );
68+ static float lastValue=0 ;
69+ static int countsPointer=0 ;
70+ static float period=0 ;
71+ static float count;
72+ filter->process (input, filterOutput);
73+ // filterOutput.copyTo(input);
74+ for (int n=0 ; n<input.getSize (); n++){
75+ float currentValue=filterOutput[n];
76+ if (currentValue>0 && lastValue<=0 ){
77+ /*
78+ counts[countsPointer]=count; //Could use nearest neighbour, but
79+ count=0;
80+ */
81+ // linear interpolation gives a better estimate of the zero crossing time:
82+ float offset=(-lastValue)/(lastValue+currentValue);
83+ counts[countsPointer]=count+offset;
84+ count=-offset;
85+ countsPointer++;
86+ if (countsPointer==counts.getSize ()) // use counts as a circular buffer
87+ countsPointer=0 ;
88+ }
89+ lastValue=currentValue;
90+ count++;
91+ }
92+ }
93+
94+ float getFrequency (){
95+ return samplingRate/counts.getMean ();
96+ }
97+ BiquadFilter* getFilter (){
98+ return filter;
99+ }
100+ };
101+
102+ #endif /* __PitchDetectors_hpp__ */
0 commit comments