ref: 3152c9f2d0d1dd1de3c1025ce7f924242ff2ca82
parent: 697a53f9c9921991681e2a599af8b163d8dc388a
author: Matthew Wang <mjw7@princeton.edu>
date: Wed Aug 12 13:11:34 EDT 2020
tDualPitchDetector and other bacf pitch detector updates
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -18,14 +18,18 @@
tMBTriangle btri;
tMBPulse bpulse;
-tPitchDetector detector;
+tDualPitchDetector detector;
+tCompressor compressor;
+
+tSVF lp, hp;
+
tPeriodDetection pd;
tZeroCrossingCounter zc;
tEnvelopeFollower ef;
-tCycle sine;
+tTriangle tri;
tBuffer samp;
tMBSampler sampler;
@@ -54,16 +58,21 @@
bufIn = (float*) leaf_alloc(sizeof(float) * 4096);
bufOut = (float*) leaf_alloc(sizeof(float) * 4096);
- // lowestFreq, highestFreq, hysteresis (width of hysteresis region around 0.0 for zero crossing detection)
- tPitchDetector_init(&detector, mtof(48), mtof(84), 0.01f);
+ tDualPitchDetector_init(&detector, mtof(53), mtof(77));
+
+ tCompressor_init(&compressor);
+
+ tSVF_init(&lp, SVFTypeLowpass, mtof(77) * 2.0f, 1.0f);
+ tSVF_init(&hp, SVFTypeHighpass, mtof(48) * 0.5f, 1.0f);
+
tPeriodDetection_init(&pd, bufIn, bufOut, 4096, 1024);
tZeroCrossingCounter_init(&zc, 128);
tEnvelopeFollower_init(&ef, 0.02f, 0.9999f);
- tCycle_init(&sine);
- tCycle_setFreq(&sine, 100);
+ tTriangle_init(&tri);
+ tTriangle_setFreq(&tri, 100);
tBuffer_init(&samp, 5.0f * leaf.sampleRate);
tMBSampler_init(&sampler, &samp);
@@ -81,14 +90,13 @@
}
-float lastFreq;
float LEAFTest_tick (float input)
{
- tBuffer_tick(&samp, input);
+// tBuffer_tick(&samp, input);
+//
+// return tMBSampler_tick(&sampler);
- return tMBSampler_tick(&sampler);
-
// tMBSaw_setFreq(&bsaw, x);
// tMBTriangle_setFreq(&btri, x);
// tMBPulse_setFreq(&bpulse, x);
@@ -99,23 +107,23 @@
//// return tMBSaw_tick(&bsaw);
//// return tMBTriangle_tick(&btri);
// return tMBPulse_tick(&bpulse);
-
+ input = tSVF_tick(&hp, tSVF_tick(&lp, tCompressor_tick(&compressor, input)));
+
// float freq = 1.0f/tPeriodDetection_tick(&pd, input) * leaf.sampleRate;
-// tPitchDetector_tick(&detector, input);
-// float altFreq = tPitchDetector_getFrequency(&detector);
-//
+ tDualPitchDetector_tick(&detector, input);
+ float altFreq = tDualPitchDetector_getFrequency(&detector);
+
// if (fabsf(1.0f - (freq / altFreq)) < 0.05f)
-//// if (tZeroCrossingCounter_tick(&zc, input) < 0.05 && freq > 0.0f)
-// {
-// tCycle_setFreq(&sine, altFreq);
-// }
-//
-// float g = tEnvelopeFollower_tick(&ef, input);
-//
-// lastFreq = freq;
-//
-// return tCycle_tick(&sine) * g * 2.0f + input;
+// if (tZeroCrossingCounter_tick(&zc, input) < 0.05 && freq > 0.0f)
+ if (altFreq > 0.0f)
+ {
+ tTriangle_setFreq(&tri, altFreq);
+ }
+
+ float g = tEnvelopeFollower_tick(&ef, input);
+
+ return tTriangle_tick(&tri) * g;
}
int firstFrame = 1;
@@ -122,11 +130,11 @@
bool lastState = false, lastPlayState = false;
void LEAFTest_block (void)
{
- float periodicity = tPitchDetector_getPeriodicity(&detector);
+ float periodicity = tDualPitchDetector_getPeriodicity(&detector);
if (periodicity > 0.99f)
{
- DBG(tPitchDetector_getFrequency(&detector));
- DBG(tPitchDetector_getPeriodicity(&detector));
+ DBG(tDualPitchDetector_getFrequency(&detector));
+ DBG(tDualPitchDetector_getPeriodicity(&detector));
}
float val = getSliderValue("on/off");
--- a/leaf/Inc/leaf-analysis.h
+++ b/leaf/Inc/leaf-analysis.h
@@ -572,13 +572,9 @@
int tZeroCrossingInfo_period(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
float tZeroCrossingInfo_fractionalPeriod(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
int tZeroCrossingInfo_getWidth(tZeroCrossingInfo* const);
- int tZeroCrossingInfo_isSimilar(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
//==============================================================================
-#define PULSE_HEIGHT_DIFF 0.8
-#define PULSE_WIDTH_DIFF 0.85
-
typedef struct _tZeroCrossingCollector
{
tMempool mempool;
@@ -618,6 +614,8 @@
int tZeroCrossingCollector_isReset(tZeroCrossingCollector* const zc);
tZeroCrossingInfo const tZeroCrossingCollector_getCrossing(tZeroCrossingCollector* const zc, int index);
+
+ void tZeroCrossingCollector_setHysteresis(tZeroCrossingCollector* const zc, float hysteresis);
//==============================================================================
@@ -709,7 +707,16 @@
@fn int tPeriodDetector_isReady (tPeriodDetector* const detector)
@brief
@param
+
+ @fn int tPeriodDetector_isReset (tPeriodDetector* const detector)
+ @brief
+ @param

+ @fn void tPeriodDetector_setHysteresis (tPeriodDetector* const detector, float hysteresis)
+ @brief Set the hysteresis used in zero crossing detection.
+ @param detector A pointer to the relevant tPeriodDetector.
+ @param hysteresis The hysteresis in decibels. Defaults to -40db.
+
@} */
#define PULSE_THRESHOLD 0.6f
@@ -741,12 +748,18 @@
int _range;
} _sub_collector;
+ typedef struct _period_info
+ {
+ float period; // -1.0f
+ float periodicity;
+ } _period_info;
+
typedef struct _tPeriodDetector
{
tMempool mempool;
tZeroCrossingCollector _zc;
- float _period_info[2]; // i0 is period, i1 is periodicity
+ _period_info _fundamental;
unsigned int _min_period;
int _range;
tBitset _bits;
@@ -756,6 +769,8 @@
float _predicted_period;// = -1.0f;
unsigned int _edge_mark;// = 0;
unsigned int _predict_edge;// = 0;
+ unsigned int _num_pulses; // = 0;
+ int _half_empty; // 0;
tBACF _bacf;
@@ -775,6 +790,9 @@
float tPeriodDetector_harmonic (tPeriodDetector* const detector, int harmonicIndex);
float tPeriodDetector_predictPeriod (tPeriodDetector* const detector);
int tPeriodDetector_isReady (tPeriodDetector* const detector);
+ int tPeriodDetector_isReset (tPeriodDetector* const detector);
+
+ void tPeriodDetector_setHysteresis (tPeriodDetector* const detector, float hysteresis);
//==============================================================================
@@ -784,46 +802,60 @@
@brief
@{
- @fn void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis)
+ @fn void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq)
@brief Initialize a tPitchDetector to the default LEAF mempool.
- @param
+ @param detector A pointer to the relevant tPitchDetector.
+ @param lowestFreq
+ @param highestFreq
- @fn void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis, tMempool* const mempool)
+
+ @fn void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, tMempool* const mempool)
@brief Initialize a tPitchDetector to a specified mempool.
- @param
+ @param detector A pointer to the relevant tPitchDetector.
+ @param lowestFreq
+ @param highestFreq
+ @param mempool
@fn void tPitchDetector_free (tPitchDetector* const detector)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
@fn int tPitchDetector_tick (tPitchDetector* const detector, float sample)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
@fn float tPitchDetector_getFrequency (tPitchDetector* const detector)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
@fn float tPitchDetector_getPeriodicity (tPitchDetector* const detector)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
@fn float tPitchDetector_harmonic (tPitchDetector* const detector, int harmonicIndex)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
- @fn float tPitchDetector_predictFrequency (tPitchDetector* const detector, int init)
+ @fn float tPitchDetector_predictFrequency (tPitchDetector* const detector)
@brief
- @param
+ @param detector A pointer to the relevant tPitchDetector.
- @fn void tPitchDetector_reset (tPitchDetector* const detector)
- @brief
- @param
+ @fn void tPitchDetector_setHysteresis (tPitchDetector* const detector, float hysteresis)
+ @brief Set the hysteresis used in zero crossing detection.
+ @param detector A pointer to the relevant tPitchDetector.
+ @param hysteresis The hysteresis in decibels. Defaults to -40db.

@} */
-#define MAX_DEVIATION 0.9f
-#define MIN_PERIODICITY 0.8f
+#define ONSET_PERIODICITY 0.95f
+#define MIN_PERIODICITY 0.9f
+#define DEFAULT_HYSTERESIS -40.0f
+
+ typedef struct _pitch_info
+ {
+ float frequency;
+ float periodicity;
+ } _pitch_info;
typedef struct _tPitchDetector
{
@@ -830,9 +862,7 @@
tMempool mempool;
tPeriodDetector _pd;
- float _frequency;
- float _median, _median_b, _median_c;
- float _predict_median, _predict_median_b, _predict_median_c;
+ _pitch_info _current;
int _frames_after_shift;// = 0;
} _tPitchDetector;
@@ -839,8 +869,8 @@
typedef _tPitchDetector* tPitchDetector;
- void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis);
- void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis, tMempool* const mempool);
+ void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq);
+ void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, tMempool* const mempool);
void tPitchDetector_free (tPitchDetector* const detector);
int tPitchDetector_tick (tPitchDetector* const detector, float sample);
@@ -847,16 +877,43 @@
float tPitchDetector_getFrequency (tPitchDetector* const detector);
float tPitchDetector_getPeriodicity (tPitchDetector* const detector);
float tPitchDetector_harmonic (tPitchDetector* const detector, int harmonicIndex);
- float tPitchDetector_predictFrequency (tPitchDetector* const detector, int init);
- void tPitchDetector_reset (tPitchDetector* const detector);
+ float tPitchDetector_predictFrequency (tPitchDetector* const detector);
+ int tPitchDetector_indeterminate (tPitchDetector* const detector);
+ void tPitchDetector_setHysteresis (tPitchDetector* const detector, float hysteresis);
+
+ typedef struct _tDualPitchDetector
+ {
+ tMempool mempool;
+
+ tPitchDetector _pd1;
+ tPitchDetector _pd2;
+ _pitch_info _current;
+ float _mean;
+ float _predicted_frequency;
+ int _first;
+
+ } _tDualPitchDetector;
+ typedef _tDualPitchDetector* tDualPitchDetector;
+ void tDualPitchDetector_init (tDualPitchDetector* const detector, float lowestFreq, float highestFreq);
+ void tDualPitchDetector_initToPool (tDualPitchDetector* const detector, float lowestFreq, float highestFreq, tMempool* const mempool);
+ void tDualPitchDetector_free (tDualPitchDetector* const detector);
+ int tDualPitchDetector_tick (tDualPitchDetector* const detector, float sample);
+ float tDualPitchDetector_getFrequency (tDualPitchDetector* const detector);
+ float tDualPitchDetector_getPeriodicity (tDualPitchDetector* const detector);
+ float tDualPitchDetector_harmonic (tDualPitchDetector* const detector, int harmonicIndex);
+ float tDualPitchDetector_predictFrequency (tDualPitchDetector* const detector);
+ void tDualPitchDetector_setHysteresis (tDualPitchDetector* const detector, float hysteresis);
+
+
+
#ifdef __cplusplus
}
#endif
@@ -864,6 +921,7 @@
#endif // LEAF_ANALYSIS_H_INCLUDED
//==============================================================================
+
--- a/leaf/Src/leaf-analysis.c
+++ b/leaf/Src/leaf-analysis.c
@@ -1021,19 +1021,6 @@
return z->_width;
}
-int tZeroCrossingInfo_isSimilar(tZeroCrossingInfo* const zc, tZeroCrossingInfo* const next)
-{
- _tZeroCrossingInfo* z = *zc;
- _tZeroCrossingInfo* n = *next;
-
- int similarPeak = fabs(z->_peak - n->_peak) <= ((1.0f - PULSE_HEIGHT_DIFF) * fmax(fabs(z->_peak), fabs(n->_peak)));
-
- int similarWidth = fabs(z->_width - n->_width) <= ((1.0f - PULSE_WIDTH_DIFF) * fmax(fabs(z->_width), fabs(n->_width)));
-
- return similarPeak && similarWidth;
-}
-
-
static inline void update_state(tZeroCrossingCollector* const zc, float s);
static inline void shift(tZeroCrossingCollector* const zc, int n);
static inline void reset(tZeroCrossingCollector* const zc);
@@ -1049,7 +1036,7 @@
_tZeroCrossingCollector* z = *zc = (_tZeroCrossingCollector*) mpool_alloc(sizeof(_tZeroCrossingCollector), m);
z->mempool = m;
- z->_hysteresis = -hysteresis;
+ z->_hysteresis = -dbtoa(hysteresis);
int bits = CHAR_BIT * sizeof(unsigned int);
z->_window_size = fmax(2, (windowSize + bits - 1) / bits) * bits;
@@ -1177,6 +1164,13 @@
return z->_frame == 0;
}
+void tZeroCrossingCollector_setHysteresis(tZeroCrossingCollector* const zc, float hysteresis)
+{
+ _tZeroCrossingCollector* z = *zc;
+
+ z->_hysteresis = -dbtoa(hysteresis);
+}
+
static inline void update_state(tZeroCrossingCollector* const zc, float s)
{
_tZeroCrossingCollector* z = *zc;
@@ -1225,6 +1219,9 @@
z->_peak = z->_peak_update;
}
+ if (z->_frame > z->_window_size * 2)
+ reset(zc);
+
z->_prev = s;
}
@@ -1494,10 +1491,10 @@
static inline void sub_collector_init(_sub_collector* collector, tZeroCrossingCollector* const crossings, float pdt, int range);
static inline float sub_collector_period_of(_sub_collector* collector, _auto_correlation_info info);
static inline void sub_collector_save(_sub_collector* collector, _auto_correlation_info info);
-static inline int sub_collector_try_sub_harmonic(_sub_collector* collector, int harmonic, _auto_correlation_info info);
+static inline int sub_collector_try_sub_harmonic(_sub_collector* collector, int harmonic, _auto_correlation_info info, float incoming_period);
static inline int sub_collector_process_harmonics(_sub_collector* collector, _auto_correlation_info info);
static inline void sub_collector_process(_sub_collector* collector, _auto_correlation_info info);
-static inline void sub_collector_get(_sub_collector* collector, _auto_correlation_info info, float* result);
+static inline void sub_collector_get(_sub_collector* collector, _auto_correlation_info info, _period_info* result);
void tPeriodDetector_init (tPeriodDetector* const detector, float lowestFreq, float highestFreq, float hysteresis)
{
@@ -1523,6 +1520,8 @@
p->_predicted_period = -1.0f;
p->_edge_mark = 0;
p->_predict_edge = 0;
+ p->_num_pulses = 0;
+ p->_half_empty = 0;
tBACF_initToPool(&p->_bacf, &p->_bits, mempool);
}
@@ -1554,8 +1553,8 @@
if (tZeroCrossingCollector_isReset(&p->_zc))
{
- p->_period_info[0] = -1.0f;
- p->_period_info[1] = 0.0f;
+ p->_fundamental.period = -1.0f;
+ p->_fundamental.periodicity = 0.0f;
}
if (tZeroCrossingCollector_isReady(&p->_zc))
@@ -1571,7 +1570,7 @@
{
_tPeriodDetector* p = *detector;
- return p->_period_info[0];
+ return p->_fundamental.period;
}
float tPeriodDetector_getPeriodicity (tPeriodDetector* const detector)
@@ -1578,7 +1577,7 @@
{
_tPeriodDetector* p = *detector;
- return p->_period_info[1];
+ return p->_fundamental.periodicity;
}
float tPeriodDetector_harmonic (tPeriodDetector* const detector, int harmonicIndex)
@@ -1588,9 +1587,9 @@
if (harmonicIndex > 0)
{
if (harmonicIndex == 1)
- return p->_period_info[1];
+ return p->_fundamental.periodicity;
- float target_period = p->_period_info[0] / (float) harmonicIndex;
+ float target_period = p->_fundamental.period / (float) harmonicIndex;
if (target_period >= p->_min_period && target_period < p->_mid_point)
{
int count = tBACF_getCorrelation(&p->_bacf, roundf(target_period));
@@ -1620,12 +1619,14 @@
for (int j = i-1; j >= 0; --j)
{
tZeroCrossingInfo edge1 = tZeroCrossingCollector_getCrossing(&p->_zc, j);
- if (tZeroCrossingInfo_isSimilar(&edge1, &edge2))
+ if (edge1->_peak >= threshold)
{
- p->_predicted_period = tZeroCrossingInfo_fractionalPeriod(&edge1, &edge2);
- return p->_predicted_period;
+ float period = tZeroCrossingInfo_fractionalPeriod(&edge1, &edge2);
+ if (period > p->_min_period)
+ return (p->_predicted_period = period);
}
}
+ return p->_predicted_period = -1.0f;
}
}
}
@@ -1640,24 +1641,47 @@
return tZeroCrossingCollector_isReady(&p->_zc);
}
+int tPeriodDetector_isReset (tPeriodDetector* const detector)
+{
+ _tPeriodDetector* p = *detector;
+
+ return tZeroCrossingCollector_isReset(&p->_zc);
+}
+
+void tPeriodDetector_setHysteresis (tPeriodDetector* const detector, float hysteresis)
+{
+ _tPeriodDetector* p = *detector;
+
+ return tZeroCrossingCollector_setHysteresis(&p->_zc, hysteresis);
+}
+
static inline void set_bitstream(tPeriodDetector* const detector)
{
_tPeriodDetector* p = *detector;
float threshold = tZeroCrossingCollector_getPeak(&p->_zc) * PULSE_THRESHOLD;
+ unsigned int leading_edge = tZeroCrossingCollector_getWindowSize(&p->_zc);
+ unsigned int trailing_edge = 0;
+ p->_num_pulses = 0;
tBitset_clear(&p->_bits);
-
+
for (int i = 0; i != tZeroCrossingCollector_getNumEdges(&p->_zc); ++i)
{
tZeroCrossingInfo info = tZeroCrossingCollector_getCrossing(&p->_zc, i);
if (info->_peak >= threshold)
{
+ ++p->_num_pulses;
+ if (info->_leading_edge < leading_edge)
+ leading_edge = info->_leading_edge;
+ if (info->_trailing_edge > trailing_edge)
+ trailing_edge = info->_trailing_edge;
int pos = fmax(info->_leading_edge, 0);
int n = info->_trailing_edge - pos;
tBitset_setMultiple(&p->_bits, pos, n, 1);
}
}
+ p->_half_empty = (leading_edge > p->_mid_point) || (trailing_edge < p->_mid_point);
}
static inline void autocorrelate(tPeriodDetector* const detector)
@@ -1669,69 +1693,87 @@
_sub_collector collect;
sub_collector_init(&collect, &p->_zc, p->_periodicity_diff_threshold, p->_range);
- int shouldBreak = 0;
- int n = tZeroCrossingCollector_getNumEdges(&p->_zc);
- for (int i = 0; i != n - 1; ++i)
+ if (p->_half_empty || p->_num_pulses < 2)
{
- tZeroCrossingInfo first = tZeroCrossingCollector_getCrossing(&p->_zc, i);
- if (first->_peak >= threshold)
+ p->_fundamental.periodicity = -1.0f;
+ return;
+ }
+ else
+ {
+ int shouldBreak = 0;
+ int n = tZeroCrossingCollector_getNumEdges(&p->_zc);
+ for (int i = 0; i != n - 1; ++i)
{
- for (int j = i + 1; j != n; ++j)
+ tZeroCrossingInfo curr = tZeroCrossingCollector_getCrossing(&p->_zc, i);
+ if (curr->_peak >= threshold)
{
- tZeroCrossingInfo next = tZeroCrossingCollector_getCrossing(&p->_zc, j);
- if (next->_peak >= threshold)
+ for (int j = i + 1; j != n; ++j)
{
- int period = tZeroCrossingInfo_period(&first, &next);
- if (period > p->_mid_point)
- break;
- if (period >= p->_min_period)
+ tZeroCrossingInfo next = tZeroCrossingCollector_getCrossing(&p->_zc, j);
+ if (next->_peak >= threshold)
{
-
- int count = tBACF_getCorrelation(&p->_bacf, period);
-
- int mid = p->_bacf->_mid_array * CHAR_BIT * sizeof(unsigned int);
-
- int start = period;
-
- if (period < 32) // Search minimum if the resolution is low
+ int period = tZeroCrossingInfo_period(&curr, &next);
+ if (period > p->_mid_point)
+ break;
+ if (period >= p->_min_period)
{
- // Search upwards for the minimum autocorrelation count
- for (int d = start + 1; d < mid; ++d)
+
+ int count = tBACF_getCorrelation(&p->_bacf, period);
+
+ int mid = p->_bacf->_mid_array * CHAR_BIT * sizeof(unsigned int);
+
+ int start = period;
+
+ if ((collect._fundamental._period == -1.0f) && count == 0)
{
- int c = tBACF_getCorrelation(&p->_bacf, d);
- if (c > count)
- break;
- count = c;
- period = d;
+ if (tBACF_getCorrelation(&p->_bacf, period / 2.0f) == 0)
+ count = -1;
}
- // Search downwards for the minimum autocorrelation count
- for (int d = start - 1; d > p->_min_period; --d)
+ else if (period < 32) // Search minimum if the resolution is low
{
- int c = tBACF_getCorrelation(&p->_bacf, d);
- if (c > count)
- break;
- count = c;
- period = d;
+ // Search upwards for the minimum autocorrelation count
+ for (int d = start + 1; d < mid; ++d)
+ {
+ int c = tBACF_getCorrelation(&p->_bacf, d);
+ if (c > count)
+ break;
+ count = c;
+ period = d;
+ }
+ // Search downwards for the minimum autocorrelation count
+ for (int d = start - 1; d > p->_min_period; --d)
+ {
+ int c = tBACF_getCorrelation(&p->_bacf, d);
+ if (c > count)
+ break;
+ count = c;
+ period = d;
+ }
}
+
+ if (count == -1)
+ {
+ shouldBreak = 1;
+ break; // Return early if we have false correlation
+ }
+ float periodicity = 1.0f - (count * p->_weight);
+ _auto_correlation_info info = { i, j, (int) period, periodicity };
+ sub_collector_process(&collect, info);
+ if (count == 0)
+ {
+ shouldBreak = 1;
+ break; // Return early if we have perfect correlation
+ }
}
-
- float periodicity = 1.0f - (count * p->_weight);
- _auto_correlation_info info = { i, j, (int) period, periodicity };
- sub_collector_process(&collect, info);
- if (count == 0)
- {
- shouldBreak = 1;
- break; // Return early if we have perfect correlation
- }
}
}
}
+ if (shouldBreak > 0) break;
}
- if (shouldBreak > 0) break;
}
// Get the final resuts
- sub_collector_get(&collect, collect._fundamental, p->_period_info);
+ sub_collector_get(&collect, collect._fundamental, &p->_fundamental);
}
static inline void sub_collector_init(_sub_collector* collector, tZeroCrossingCollector* const crossings, float pdt, int range)
@@ -1761,11 +1803,9 @@
collector->_first_period = sub_collector_period_of(collector, collector->_fundamental);
}
-static inline int sub_collector_try_sub_harmonic(_sub_collector* collector, int harmonic, _auto_correlation_info info)
+static inline int sub_collector_try_sub_harmonic(_sub_collector* collector, int harmonic, _auto_correlation_info info, float incoming_period)
{
- int incoming_period = info._period / harmonic;
- int current_period = collector->_fundamental._period;
- if (abs(incoming_period - current_period) < collector->_periodicity_diff_threshold)
+ if (fabsf(incoming_period - collector->_first_period) < collector->_periodicity_diff_threshold)
{
// If incoming is a different harmonic and has better
// periodicity ...
@@ -1792,18 +1832,19 @@
sub_collector_save(collector, info);
}
}
- return true;
+ return 1;
}
- return false;
+ return 0;
}
static inline int sub_collector_process_harmonics(_sub_collector* collector, _auto_correlation_info info)
{
if (info._period < collector->_first_period)
- return false;
-
- int multiple = fmaxf(1.0f, roundf(sub_collector_period_of(collector, info) / collector->_first_period));
- return sub_collector_try_sub_harmonic(collector, fmin(collector->_range, multiple), info);
+ return 0;
+
+ float incoming_period = sub_collector_period_of(collector, info);
+ int multiple = fmaxf(1.0f, roundf( incoming_period / collector->_first_period));
+ return sub_collector_try_sub_harmonic(collector, fmin(collector->_range, multiple), info, incoming_period/multiple);
}
static inline void sub_collector_process(_sub_collector* collector, _auto_correlation_info info)
@@ -1818,36 +1859,37 @@
sub_collector_save(collector, info);
}
-static inline void sub_collector_get(_sub_collector* collector, _auto_correlation_info info, float* result)
+static inline void sub_collector_get(_sub_collector* collector, _auto_correlation_info info, _period_info* result)
{
if (info._period != -1.0f)
{
- result[0] = sub_collector_period_of(collector, info) / info._harmonic;
- result[1] = info._periodicity;
+ result->period = sub_collector_period_of(collector, info) / info._harmonic;
+ result->periodicity = info._periodicity;
}
else
{
- result[0] = -1.0f;
- result[1] = 0.0f;
+ result->period = -1.0f;
+ result->period = 0.0f;
}
}
static inline float calculate_frequency(tPitchDetector* const detector);
-static inline void bias(tPitchDetector* const detector, float incoming);
+static inline void bias(tPitchDetector* const detector, _pitch_info incoming);
-void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis)
+void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq)
{
- tPitchDetector_initToPool(detector, lowestFreq, highestFreq, hysteresis, &leaf.mempool);
+ tPitchDetector_initToPool(detector, lowestFreq, highestFreq, &leaf.mempool);
}
-void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis, tMempool* const mempool)
+void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, tMempool* const mempool)
{
_tMempool* m = *mempool;
_tPitchDetector* p = *detector = (_tPitchDetector*) mpool_alloc(sizeof(_tPitchDetector), m);
p->mempool = m;
- tPeriodDetector_initToPool(&p->_pd, lowestFreq, highestFreq, hysteresis, mempool);
- p->_frequency = 0.0f;
+ tPeriodDetector_initToPool(&p->_pd, lowestFreq, highestFreq, DEFAULT_HYSTERESIS, mempool);
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
p->_frames_after_shift = 0;
}
@@ -1864,22 +1906,33 @@
_tPitchDetector* p = *detector;
tPeriodDetector_tick(&p->_pd, s);
+ if (tPeriodDetector_isReset(&p->_pd))
+ {
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
+ }
+
int ready = tPeriodDetector_isReady(&p->_pd);
- if (ready > 0)
+ if (ready)
{
- if (p->_frequency == 0.0f)
+ float periodicity = p->_pd->_fundamental.periodicity;
+
+ if (periodicity == -1.0f)
{
- // Disregard if we are not periodic enough
- if (p->_pd->_period_info[1] >= MAX_DEVIATION)
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
+ return 0;
+ }
+
+ if (p->_current.frequency == 0.0f)
+ {
+ if (periodicity >= ONSET_PERIODICITY)
{
float f = calculate_frequency(detector);
if (f > 0.0f)
{
- // Apply the median for the future
- p->_median = median3f(f, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = f;
- p->_frequency = f; // But assign outright now
+ p->_current.frequency = f;
+ p->_current.periodicity = periodicity;
p->_frames_after_shift = 0;
}
}
@@ -1886,11 +1939,14 @@
}
else
{
- if (p->_pd->_period_info[1] < MIN_PERIODICITY)
+ if (periodicity < MIN_PERIODICITY)
p->_frames_after_shift = 0;
float f = calculate_frequency(detector);
if (f > 0.0f)
- bias(detector, f);
+ {
+ _pitch_info info = { f, periodicity };
+ bias(detector, info);
+ }
}
}
return ready;
@@ -1900,7 +1956,7 @@
{
_tPitchDetector* p = *detector;
- return p->_frequency;
+ return p->_current.frequency;
}
float tPitchDetector_getPeriodicity (tPitchDetector* const detector)
@@ -1907,7 +1963,7 @@
{
_tPitchDetector* p = *detector;
- return p->_pd->_period_info[1];
+ return p->_current.periodicity;
}
float tPitchDetector_harmonic (tPitchDetector* const detector, int harmonicIndex)
@@ -1917,82 +1973,75 @@
return tPeriodDetector_harmonic(&p->_pd, harmonicIndex);
}
-float tPitchDetector_predictFrequency (tPitchDetector* const detector, int init)
+float tPitchDetector_predictFrequency (tPitchDetector* const detector)
{
_tPitchDetector* p = *detector;
float period = tPeriodDetector_predictPeriod(&p->_pd);
- if (period < p->_pd->_min_period)
- return 0.0f;
- float f = leaf.sampleRate / period;
- if (p->_frequency != f)
- {
- p->_predict_median = median3f(f, p->_predict_median_b, p->_predict_median_c);
- p->_predict_median_c = p->_predict_median_b;
- p->_predict_median_b = f;
- f = p->_predict_median;
- if (init > 0)
- {
- p->_median = median3f(f, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = f;
- p->_frequency = p->_median;
- }
- }
- return f;
+ if (period > 0.0f)
+ return leaf.sampleRate / period;
+ return 0.0f;
}
-void tPitchDetector_reset (tPitchDetector* const detector)
+int tPitchDetector_indeterminate (tPitchDetector* const detector)
{
_tPitchDetector* p = *detector;
- p->_frequency = 0.0f;
+ return p->_current.frequency == 0.0f;
}
+void tPitchDetector_setHysteresis (tPitchDetector* const detector, float hysteresis)
+{
+ _tPitchDetector* p = *detector;
+
+ tPeriodDetector_setHysteresis(&p->_pd, hysteresis);
+}
+
static inline float calculate_frequency(tPitchDetector* const detector)
{
_tPitchDetector* p = *detector;
- if (p->_pd->_period_info[0] != -1)
- return leaf.sampleRate / p->_pd->_period_info[0];
+ float period = p->_pd->_fundamental.period;
+ if (period > 0.0f)
+ return leaf.sampleRate / period;
return 0.0f;
}
-static inline void bias(tPitchDetector* const detector, float incoming)
+static inline void bias(tPitchDetector* const detector, _pitch_info incoming)
{
_tPitchDetector* p = *detector;
- float current = p->_frequency;
++p->_frames_after_shift;
int shifted = 0;
- float f;
+ _pitch_info result;
//=============================================================================
- //float f = bias(current, incoming, shift);
+ //_pitch_info result = bias(current, incoming, shift);
{
- float error = current / 32.0f; // approx 1/2 semitone
- float diff = fabsf(current - incoming);
+ float error = p->_current.frequency / 32.0f; // approx 1/2 semitone
+ float diff = fabsf(p->_current.frequency - incoming.frequency);
int done = 0;
// Try fundamental
if (diff < error)
{
- f = incoming;
+ result = incoming;
done = 1;
}
// Try harmonics and sub-harmonics
- else if (p->_frames_after_shift > 2)
+ else if (p->_frames_after_shift > 1)
{
- if (current > incoming)
+ if (p->_current.frequency > incoming.frequency)
{
- float multiple = roundf(current / incoming);
- if (multiple > 1.0f)
+ int multiple = roundf(p->_current.frequency / incoming.frequency);
+ if (multiple > 1)
{
- float h = incoming * multiple;
- if (fabsf(current - h) < error)
+ float f = incoming.frequency * multiple;
+ if (fabsf(p->_current.frequency - f) < error)
{
- f = h;
+ result.frequency = f;
+ result.periodicity = incoming.periodicity;
done = 1;
}
}
@@ -1999,13 +2048,14 @@
}
else
{
- float multiple = roundf(incoming / current);
- if (multiple > 1.0f)
+ int multiple = roundf(incoming.frequency / p->_current.frequency);
+ if (multiple > 1)
{
- float h = incoming / multiple;
- if (fabsf(current - h) < error)
+ float f = incoming.frequency / multiple;
+ if (fabsf(p->_current.frequency - f) < error)
{
- f = h;
+ result.frequency = f;
+ result.periodicity = incoming.periodicity;
done = 1;
}
}
@@ -2018,13 +2068,13 @@
// harmonic matches).
if (!done)
{
- if (p->_pd->_period_info[1] > MIN_PERIODICITY)
+ if (p->_pd->_fundamental.periodicity > MIN_PERIODICITY)
{
// Now we have a frequency shift
shifted = 1;
- f = incoming;
+ result = incoming;
}
- else f = current;
+ else result = p->_current;
}
}
@@ -2034,128 +2084,161 @@
// Note that we only do this check on frequency shifts
if (shifted)
{
- if (p->_pd->_period_info[1] < MAX_DEVIATION)
+ float periodicity = p->_pd->_fundamental.periodicity;
+ if (periodicity >= ONSET_PERIODICITY)
{
- // If we don't have enough confidence in the autocorrelation
- // result, we'll try the zero-crossing edges to extract the
- // frequency and the one closest to the current frequency wins.
- int shifted2 = 0;
- float predicted = tPitchDetector_predictFrequency(detector, 0);
- if (predicted > 0.0f)
- {
- float f2;
-
- //=============================================================================
-// float f2 = bias(current, predicted, shifted2);
- {
- float error = current / 32.0f; // approx 1/2 semitone
- float diff = fabsf(current - predicted);
- int done = 0;
-
- // Try fundamental
- if (diff < error)
- {
- f2 = predicted;
- done = 1;
- }
- // Try harmonics and sub-harmonics
- else if (p->_frames_after_shift > 2)
- {
- if (current > predicted)
- {
- float multiple = roundf(current / predicted);
- if (multiple > 1.0f)
- {
- float h = predicted * multiple;
- if (fabsf(current - h) < error)
- {
- f2 = h;
- done = 1;
- }
- }
- }
- else
- {
- float multiple = roundf(predicted / current);
- if (multiple > 1.0f)
- {
- float h = predicted / multiple;
- if (fabsf(current - h) < error)
- {
- f2 = h;
- done = 1;
- }
- }
- }
- }
- // Don't do anything if the latest autocorrelation is not periodic
- // enough. Note that we only do this check on frequency shifts (i.e. at
- // this point, we are looking at a potential frequency shift, after
- // passing through the code above, checking for fundamental and
- // harmonic matches).
- if (!done)
- {
- if (p->_pd->_period_info[1] > MIN_PERIODICITY)
- {
- // Now we have a frequency shift
- shifted2 = 1;
- f2 = predicted;
- }
- else f2 = current;
- }
- }
-
- //=============================================================================
-
- // If there's no shift, the edges wins
- if (!shifted2)
- {
- p->_median = median3f(f2, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = f2;
- p->_frequency = p->_median;
- }
- else // else, whichever is closest to the current frequency wins.
- {
- int predicted = fabsf(current - f) >= fabsf(current - f2);
- float pf = !predicted ? f : f2;
- p->_median = median3f(pf, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = pf;
- p->_frequency = p->_median;
- }
- }
- else
+ p->_frames_after_shift = 0;
+ p->_current = result;
+ }
+ else if (periodicity < MIN_PERIODICITY)
+ {
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
+ }
+ }
+ else
+ {
+ p->_current = result;
+ }
+}
+
+static inline int within_octave(tDualPitchDetector* const detector, float f);
+static inline void compute_predicted_frequency(tDualPitchDetector* const detector);
+
+void tDualPitchDetector_init (tDualPitchDetector* const detector, float lowestFreq, float highestFreq)
+{
+ tDualPitchDetector_initToPool(detector, lowestFreq, highestFreq, &leaf.mempool);
+}
+
+void tDualPitchDetector_initToPool (tDualPitchDetector* const detector, float lowestFreq, float highestFreq, tMempool* const mempool)
+{
+ _tMempool* m = *mempool;
+ _tDualPitchDetector* p = *detector = (_tDualPitchDetector*) mpool_alloc(sizeof(_tDualPitchDetector), m);
+ p->mempool = m;
+
+ tPitchDetector_initToPool(&p->_pd1, lowestFreq, highestFreq, mempool);
+ tPitchDetector_initToPool(&p->_pd2, lowestFreq, highestFreq, mempool);
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
+ p->_mean = lowestFreq + ((highestFreq - lowestFreq) / 2.0f);
+ p->_predicted_frequency = 0.0f;
+ p->_first = 1;
+}
+
+void tDualPitchDetector_free (tDualPitchDetector* const detector)
+{
+ _tDualPitchDetector* p = *detector;
+
+ tPitchDetector_free(&p->_pd1);
+ tPitchDetector_free(&p->_pd2);
+
+ mpool_free((char*) p, p->mempool);
+}
+
+int tDualPitchDetector_tick (tDualPitchDetector* const detector, float sample)
+{
+ _tDualPitchDetector* p = *detector;
+
+ int pd1_ready = tPitchDetector_tick(&p->_pd1, sample);
+ int pd2_ready = tPitchDetector_tick(&p->_pd2, -sample);
+
+ if (pd1_ready || pd2_ready)
+ {
+ int pd1_indeterminate = tPitchDetector_indeterminate(&p->_pd1);
+ int pd2_indeterminate = tPitchDetector_indeterminate(&p->_pd2);
+ if (!pd1_indeterminate && !pd2_indeterminate)
+ {
+ _pitch_info _i1 = p->_pd1->_current;
+ _pitch_info _i2 = p->_pd2->_current;
+
+ float pd1_diff = fabsf(_i1.frequency - p->_mean);
+ float pd2_diff = fabsf(_i2.frequency - p->_mean);
+ _pitch_info i = (pd1_diff < pd2_diff) ? _i1 : _i2;
+
+ if (p->_first)
+ {
+ p->_current = i;
+ p->_mean = p->_current.frequency;
+ p->_first = 0;
+ p->_predicted_frequency = 0.0f;
+ }
+ else if (within_octave(detector, i.frequency))
+ {
+ p->_current = i;
+ p->_mean = p->_current.frequency;//(0.222222f * p->_current.frequency) + (0.888888f * p->_mean);
+ p->_predicted_frequency = 0.0f;
+ }
+ }
+
+ if (pd1_indeterminate && pd2_indeterminate)
+ {
+ compute_predicted_frequency(detector);
+ p->_current.frequency = 0.0f;
+ p->_current.periodicity = 0.0f;
+ }
+ }
+
+ return pd1_ready || pd2_ready;
+}
+
+float tDualPitchDetector_getFrequency (tDualPitchDetector* const detector)
+{
+ _tDualPitchDetector* p = *detector;
+
+ return p->_current.frequency;
+}
+
+float tDualPitchDetector_getPeriodicity (tDualPitchDetector* const detector)
+{
+ _tDualPitchDetector* p = *detector;
+
+ return p->_current.periodicity;
+}
+
+float tDualPitchDetector_predictFrequency (tDualPitchDetector* const detector)
+{
+ _tDualPitchDetector* p = *detector;
+
+ if (p->_predicted_frequency == 0.0f)
+ compute_predicted_frequency(detector);
+ return p->_predicted_frequency;
+}
+
+void tDualPitchDetector_setHysteresis (tDualPitchDetector* const detector, float hysteresis)
+{
+ _tDualPitchDetector* p = *detector;
+
+ tPitchDetector_setHysteresis(&p->_pd1, hysteresis);
+ tPitchDetector_setHysteresis(&p->_pd2, hysteresis);
+}
+
+static inline int within_octave(tDualPitchDetector* const detector, float f)
+{
+ _tDualPitchDetector* p = *detector;
+
+ return (f > p->_mean) ? (f < (p->_mean * 2.0f)) : (f > (p->_mean * 0.5f));
+}
+
+static inline void compute_predicted_frequency(tDualPitchDetector* const detector)
+{
+ _tDualPitchDetector* p = *detector;
+
+ float f1 = tPitchDetector_predictFrequency(&p->_pd1);
+ if (f1 > 0.0f)
+ {
+ float f2 = tPitchDetector_predictFrequency(&p->_pd2);
+ if (f2 > 0.0f)
+ {
+ float error = f1 * 0.1f;
+ if (fabsf(f1 - f2) < error)
{
- p->_median = median3f(f, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = f;
- p->_frequency = p->_median;
+ if (p->_first || within_octave(detector, f1))
+ {
+ p->_predicted_frequency = f1;
+ return;
+ }
}
-
}
- else
- {
- // Now we have a frequency shift. Get the median of 3 (incoming
- // frequency and last two frequency shifts) to eliminate abrupt
- // changes. This will minimize potentially unwanted shifts.
- // See https://en.wikipedia.org/wiki/Median_filter
-
- p->_median = median3f(incoming, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = incoming;
-
- if (p->_median == incoming)
- p->_frames_after_shift = 0;
-
- p->_frequency = f;
- }
}
- else
- {
- p->_median = median3f(f, p->_median_b, p->_median_c);
- p->_median_c = p->_median_b;
- p->_median_b = f;
- p->_frequency = p->_median;
- }
+ p->_predicted_frequency = 0.0f;
}