ref: 7c1652ac641228e85209accc16e509f74e249396
parent: 3e21094724bf346ebe920419a178cf06720d3a3d
author: Matthew Wang <mjw7@princeton.edu>
date: Thu Jul 9 15:31:08 EDT 2020
mostly working bacf pitch detection
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -33,6 +33,8 @@
tMBTriangle btri;
tMBPulse bpulse;
+tPitchDetector detector;
+
float gain;
float freq;
float dtime;
@@ -42,7 +44,7 @@
float y = 0.0f;
float a, b, c, d;
-#define MSIZE 50000
+#define MSIZE 500000
char memory[MSIZE];
void LEAFTest_init (float sampleRate, int blockSize)
@@ -52,6 +54,8 @@
tMBSaw_init(&bsaw);
tMBTriangle_init(&btri);
tMBPulse_init(&bpulse);
+
+ tPitchDetector_init(&detector, 1000.0f, 5000.0f, 0.0f);
}
inline double getSawFall(double angle) {
@@ -65,16 +69,22 @@
float LEAFTest_tick (float input)
{
- tMBSaw_setFreq(&bsaw, x);
- tMBTriangle_setFreq(&btri, x);
- tMBPulse_setFreq(&bpulse, x);
+// tMBSaw_setFreq(&bsaw, x);
+// tMBTriangle_setFreq(&btri, x);
+// tMBPulse_setFreq(&bpulse, x);
+//
+// tMBTriangle_setWidth(&btri, y);
+// tMBPulse_setWidth(&bpulse, y);
+//
+//// return tMBSaw_tick(&bsaw);
+//// return tMBTriangle_tick(&btri);
+// return tMBPulse_tick(&bpulse);
- tMBTriangle_setWidth(&btri, y);
- tMBPulse_setWidth(&bpulse, y);
+ tPitchDetector_tick(&detector, input);
-// return tMBSaw_tick(&bsaw);
-// return tMBTriangle_tick(&btri);
- return tMBPulse_tick(&bpulse);
+ tMBTriangle_setFreq(&btri, tPitchDetector_getFrequency(&detector));
+
+ return input + tMBTriangle_tick(&btri) * 0.25;
}
int firstFrame = 1;
@@ -81,6 +91,8 @@
bool lastState = false, lastPlayState = false;
void LEAFTest_block (void)
{
+ DBG(tPitchDetector_getFrequency(&detector));
+ DBG(tPitchDetector_getPeriodicity(&detector));
// if (firstFrame == 1)
// {
// tBuffer_record(&buff); // starts recording
@@ -94,15 +106,15 @@
// a = val * tBuffer_getBufferLength(&buff);
- DBG("start: " + String(a));
+// DBG("start: " + String(a));
val = getSliderValue("mod depth");
y = val * 2.0f - 1.0f;
- DBG(String(y));
+// DBG(String(y));
// b = val * tBuffer_getBufferLength(&buff);
- DBG("rate: " + String(b));
+// DBG("rate: " + String(b));
//
// tSampler_setStart(&samp, a);
// tSampler_setEnd(&samp, b);
--- a/TestPlugin/Source/PluginProcessor.cpp
+++ b/TestPlugin/Source/PluginProcessor.cpp
@@ -66,10 +66,9 @@
LEAFTest_block();
MidiMessage m;
- int time;
-
- for (MidiBuffer::Iterator i (midiMessages); i.getNextEvent (m, time);)
+ for (MidiMessageMetadata metadata : midiMessages)
{
+ m = metadata.getMessage();
int noteNumber = m.getNoteNumber();
float velocity = m.getFloatVelocity();
--- a/leaf/Inc/leaf-analysis.h
+++ b/leaf/Inc/leaf-analysis.h
@@ -683,11 +683,11 @@
float _prev;// = 0.0f;
float _hysteresis;
- bool _state;// = false;
+ int _state;// = false;
int _num_edges;// = 0;
int _window_size;
int _frame;// = 0;
- bool _ready;// = false;
+ int _ready;// = false;
float _peak_update;// = 0.0f;
float _peak;// = 0.0f;
} _tZeroCrossings;
@@ -756,7 +756,8 @@
void tBACF_initToPool (tBACF* const bacf, tBitset* const bitset, tMempool* const mempool);
void tBACF_free (tBACF* const bacf);
- int tBACF_tick (tBACF* const bacf, int pos);
+ int tBACF_getCorrelation (tBACF* const bacf, int pos);
+ void tBACF_set (tBACF* const bacf, tBitset* const bitset);
//==============================================================================
@@ -782,7 +783,7 @@
_auto_correlation_info _fundamental;
// passed in, not initialized
- tZeroCrossing _zc;
+ tZeroCrossings _zc;
float _harmonic_threshold;
float _periodicity_diff_threshold;
@@ -794,8 +795,7 @@
tMempool mempool;
tZeroCrossings _zc;
- float _period;
- float _periodicity;
+ float _period_info[2]; // i0 is period, i1 is periodicity
unsigned int _min_period;
int _range;
tBitset _bits;
@@ -805,6 +805,9 @@
float _predicted_period;// = -1.0f;
unsigned int _edge_mark;// = 0;
unsigned int _predict_edge;// = 0;
+
+ tBACF _bacf;
+
} _tPeriodDetector;
typedef _tPeriodDetector* tPeriodDetector;
@@ -813,7 +816,49 @@
void tPeriodDetector_initToPool (tPeriodDetector* const detector, float lowestFreq, float highestFreq, float hysteresis, tMempool* const mempool);
void tPeriodDetector_free (tPeriodDetector* const detector);
- float tPeriodDetector_tick (tPeriodDetector* const detector, float sample);
+ int tPeriodDetector_tick (tPeriodDetector* const detector, float sample);
+
+ // get the periodicity for a given harmonic
+ float tPeriodDetector_getPeriod (tPeriodDetector* const detector);
+ float tPeriodDetector_getPeriodicity (tPeriodDetector* const detector);
+ float tPeriodDetector_harmonic (tPeriodDetector* const detector, int harmonicIndex);
+ float tPeriodDetector_predictPeriod (tPeriodDetector* const detector);
+ int tPeriodDetector_isReady (tPeriodDetector* const detector);
+
+ //==============================================================================
+
+#define MAX_DEVIATION 0.9f
+#define MIN_PERIODICITY 0.8f
+
+ typedef struct _tPitchDetector
+ {
+ tMempool mempool;
+
+ tPeriodDetector _pd;
+ float _frequency;
+ float _median, _median_b, _median_c;
+ float _predict_median, _predict_median_b, _predict_median_c;
+ int _frames_after_shift;// = 0;
+
+ } _tPitchDetector;
+
+ 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_free (tPitchDetector* const detector);
+
+ int tPitchDetector_tick (tPitchDetector* const detector, float sample);
+ 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);
+
+
+
+
+
--- a/leaf/Inc/leaf-math.h
+++ b/leaf/Inc/leaf-math.h
@@ -216,6 +216,8 @@
// or let the user pointer popcount() to whatever they want
// something to look into...
int popcount(unsigned int x);
+
+ float median3f(float a, float b, float c);
//==============================================================================
--- a/leaf/Src/leaf-analysis.c
+++ b/leaf/Src/leaf-analysis.c
@@ -1063,6 +1063,14 @@
for (int i = 0; i < z->_size; i++)
tZeroCrossing2_initToPool(&z->_info[i], mp);
z->_pos = 0;
+
+ z->_prev = 0.0f;
+ z->_state = 0;
+ z->_num_edges = 0;
+ z->_frame = 0;
+ z->_ready = 0;
+ z->_peak_update = 0.0f;
+ z->_peak = 0.0f;
}
void tZeroCrossings_free (tZeroCrossings* const zc)
@@ -1095,7 +1103,7 @@
// We need at least two rising edges.
if (z->_num_edges > 1)
- z->_ready = true;
+ z->_ready = 1;
else
reset(zc);
}
@@ -1188,11 +1196,11 @@
{
--z->_pos;
z->_pos &= z->_mask;
- _tZeroCrossing2 crossing = *z->_info[z->_pos];
- crossing._before_crossing = z->_prev;
- crossing._after_crossing = s;
- crossing._peak = s;
- crossing._leading_edge = (int) z->_frame;
+ tZeroCrossing2 crossing = z->_info[z->_pos];
+ crossing->_before_crossing = z->_prev;
+ crossing->_after_crossing = s;
+ crossing->_peak = s;
+ crossing->_leading_edge = (int) z->_frame;
++z->_num_edges;
z->_state = 1;
}
@@ -1398,8 +1406,6 @@
}
}
-
-
void tBACF_init (tBACF* const bacf, tBitset* const bitset)
{
tBACF_initToPool(bacf, bitset, &leaf.mempool);
@@ -1422,7 +1428,7 @@
mpool_free((char*) b, b->mempool);
}
-int tBACF_tick (tBACF* const bacf, int pos)
+int tBACF_getCorrelation (tBACF* const bacf, int pos)
{
_tBACF* b = *bacf;
@@ -1454,13 +1460,27 @@
}
}
return count;
+}
+
+void tBACF_set (tBACF* const bacf, tBitset* const bitset)
+{
+ _tBACF* b = *bacf;
+ b->_bitset = *bitset;
+ b->_mid_array = ((b->_bitset->_bit_size / b->_bitset->_value_size) / 2) - 1;
}
static inline void set_bitstream(tPeriodDetector* const detector);
static inline void autocorrelate(tPeriodDetector* const detector);
-static inline void sub_collector_init(_sub_collector collector, tZeroCrossings* const crossings, float pdt, int range);
+static inline void sub_collector_init(_sub_collector* collector, tZeroCrossings* 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_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);
+
void tPeriodDetector_init (tPeriodDetector* const detector, float lowestFreq, float highestFreq, float hysteresis)
{
tPeriodDetector_initToPool(detector, lowestFreq, highestFreq, hysteresis, &leaf.mempool);
@@ -1485,6 +1505,8 @@
p->_predicted_period = -1.0f;
p->_edge_mark = 0;
p->_predict_edge = 0;
+
+ tBACF_initToPool(&p->_bacf, &p->_bits, mempool);
}
void tPeriodDetector_free (tPeriodDetector* const detector)
@@ -1493,11 +1515,12 @@
tZeroCrossings_free(&p->_zc);
tBitset_free(&p->_bits);
+ tBACF_free(&p->_bacf);
mpool_free((char*) p, p->mempool);
}
-float tPeriodDetector_tick (tPeriodDetector* const detector, float s)
+int tPeriodDetector_tick (tPeriodDetector* const detector, float s)
{
_tPeriodDetector* p = *detector;
@@ -1513,8 +1536,8 @@
if (tZeroCrossings_isReset(&p->_zc))
{
- p->_period = -1;
- p->_periodicity = 0.0f;
+ p->_period_info[0] = -1.0f;
+ p->_period_info[1] = 0.0f;
}
if (tZeroCrossings_isReady(&p->_zc))
@@ -1521,12 +1544,84 @@
{
set_bitstream(detector);
autocorrelate(detector);
- return true;
+ return 1;
}
- return false;
+ return 0;
}
+float tPeriodDetector_getPeriod (tPeriodDetector* const detector)
+{
+ _tPeriodDetector* p = *detector;
+
+ return p->_period_info[0];
+}
+float tPeriodDetector_getPeriodicity (tPeriodDetector* const detector)
+{
+ _tPeriodDetector* p = *detector;
+
+ return p->_period_info[1];
+}
+
+float tPeriodDetector_harmonic (tPeriodDetector* const detector, int harmonicIndex)
+{
+ _tPeriodDetector* p = *detector;
+
+ if (harmonicIndex > 0)
+ {
+ if (harmonicIndex == 1)
+ return p->_period_info[1];
+
+ float target_period = p->_period_info[0] / (float) harmonicIndex;
+ if (target_period >= p->_min_period && target_period < p->_mid_point)
+ {
+ int count = tBACF_getCorrelation(&p->_bacf, roundf(target_period));
+ float periodicity = 1.0f - (count * p->_weight);
+ return periodicity;
+ }
+ }
+ return 0.0f;
+}
+
+float tPeriodDetector_predictPeriod (tPeriodDetector* const detector)
+{
+ _tPeriodDetector* p = *detector;
+
+ if (p->_predicted_period == -1.0f && p->_edge_mark != p->_predict_edge)
+ {
+ p->_predict_edge = p->_edge_mark;
+ int n = tZeroCrossings_getNumEdges(&p->_zc);
+ if (n > 1)
+ {
+ float threshold = tZeroCrossings_getPeak(&p->_zc) * PULSE_THRESHOLD;
+ for (int i = n - 1; i > 0; --i)
+ {
+ tZeroCrossing2 edge2 = tZeroCrossings_getCrossing(&p->_zc, i);
+ if (edge2->_peak >= threshold)
+ {
+ for (int j = i-1; j >= 0; --j)
+ {
+ tZeroCrossing2 edge1 = tZeroCrossings_getCrossing(&p->_zc, j);
+ if (tZeroCrossing2_isSimilar(&edge1, &edge2))
+ {
+ p->_predicted_period = tZeroCrossing2_fractionalPeriod(&edge1, &edge2);
+ return p->_predicted_period;
+ }
+ }
+ }
+ }
+ }
+ }
+ return p->_predicted_period;
+}
+
+int tPeriodDetector_isReady (tPeriodDetector* const detector)
+{
+ _tPeriodDetector* p = *detector;
+
+ return tZeroCrossings_isReady(&p->_zc);
+}
+
static inline void set_bitstream(tPeriodDetector* const detector)
{
_tPeriodDetector* p = *detector;
@@ -1550,4 +1645,492 @@
static inline void autocorrelate(tPeriodDetector* const detector)
{
_tPeriodDetector* p = *detector;
+
+ float threshold = tZeroCrossings_getPeak(&p->_zc) * PULSE_THRESHOLD;
+
+ _sub_collector collect;
+ sub_collector_init(&collect, &p->_zc, p->_periodicity_diff_threshold, p->_range);
+
+ int shouldBreak = 0;
+ int n = tZeroCrossings_getNumEdges(&p->_zc);
+ for (int i = 0; i != n - 1; ++i)
+ {
+ tZeroCrossing2 first = tZeroCrossings_getCrossing(&p->_zc, i);
+ if (first->_peak >= threshold)
+ {
+ for (int j = i + 1; j != n; ++j)
+ {
+ tZeroCrossing2 next = tZeroCrossings_getCrossing(&p->_zc, j);
+ if (next->_peak >= threshold)
+ {
+ int period = tZeroCrossing2_period(&first, &next);
+ if (period > p->_mid_point)
+ break;
+ if (period >= p->_min_period)
+ {
+
+ 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
+ {
+ // 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;
+ }
+ }
+
+ 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;
+ }
+
+ // Get the final resuts
+ sub_collector_get(&collect, collect._fundamental, p->_period_info);
+}
+
+static inline void sub_collector_init(_sub_collector* collector, tZeroCrossings* const crossings, float pdt, int range)
+{
+ collector->_zc = *crossings;
+ collector->_harmonic_threshold = HARMONIC_PERIODICITY_FACTOR * 2.0f / collector->_zc->_window_size;
+ collector->_periodicity_diff_threshold = pdt;
+ collector->_range = range;
+ collector->_fundamental._i1 = -1;
+ collector->_fundamental._i2 = -1;
+ collector->_fundamental._period = -1;
+ collector->_fundamental._periodicity = 0.0f;
+ collector->_fundamental._harmonic = 0;
+}
+
+static inline float sub_collector_period_of(_sub_collector* collector, _auto_correlation_info info)
+{
+ tZeroCrossing2 first = tZeroCrossings_getCrossing(&collector->_zc, info._i1);
+ tZeroCrossing2 next = tZeroCrossings_getCrossing(&collector->_zc, info._i2);
+ return tZeroCrossing2_fractionalPeriod(&first, &next);
+}
+
+static inline void sub_collector_save(_sub_collector* collector, _auto_correlation_info info)
+{
+ collector->_fundamental = info;
+ collector->_fundamental._harmonic = 1;
+ 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)
+{
+ int incoming_period = info._period / harmonic;
+ int current_period = collector->_fundamental._period;
+ if (abs(incoming_period - current_period) < collector->_periodicity_diff_threshold)
+ {
+ // If incoming is a different harmonic and has better
+ // periodicity ...
+ if (info._periodicity > collector->_fundamental._periodicity &&
+ harmonic != collector->_fundamental._harmonic)
+ {
+ float periodicity_diff = fabs(info._periodicity - collector->_fundamental._periodicity);
+
+ // If incoming periodicity is within the harmonic
+ // periodicity threshold, then replace _fundamental with
+ // incoming. Take note of the harmonic for later.
+ if (periodicity_diff <= collector->_harmonic_threshold)
+ {
+ collector->_fundamental._i1 = info._i1;
+ collector->_fundamental._i2 = info._i2;
+ collector->_fundamental._periodicity = info._periodicity;
+ collector->_fundamental._harmonic = harmonic;
+ }
+
+ // If not, then we save incoming (replacing the current
+ // _fundamental).
+ else
+ {
+ sub_collector_save(collector, info);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+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);
+}
+
+static inline void sub_collector_process(_sub_collector* collector, _auto_correlation_info info)
+{
+ if (collector->_fundamental._period == -1.0f)
+ sub_collector_save(collector, info);
+
+ else if (sub_collector_process_harmonics(collector, info))
+ return;
+
+ else if (info._periodicity > collector->_fundamental._periodicity)
+ sub_collector_save(collector, info);
+}
+
+static inline void sub_collector_get(_sub_collector* collector, _auto_correlation_info info, float* result)
+{
+ if (info._period != -1.0f)
+ {
+ result[0] = sub_collector_period_of(collector, info) / info._harmonic;
+ result[1] = info._periodicity;
+ }
+ else
+ {
+ result[0] = -1.0f;
+ result[1] = 0.0f;
+ }
+}
+
+static inline float calculate_frequency(tPitchDetector* const detector);
+static inline void bias(tPitchDetector* const detector, float incoming);
+
+void tPitchDetector_init (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis)
+{
+ tPitchDetector_initToPool(detector, lowestFreq, highestFreq, hysteresis, &leaf.mempool);
+}
+
+void tPitchDetector_initToPool (tPitchDetector* const detector, float lowestFreq, float highestFreq, float hysteresis, 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;
+ p->_frames_after_shift = 0;
+}
+
+void tPitchDetector_free (tPitchDetector* const detector)
+{
+ _tPitchDetector* p = *detector;
+
+ tPeriodDetector_free(&p->_pd);
+ mpool_free((char*) p, p->mempool);
+}
+
+int tPitchDetector_tick (tPitchDetector* const detector, float s)
+{
+ _tPitchDetector* p = *detector;
+ tPeriodDetector_tick(&p->_pd, s);
+
+ int ready = tPeriodDetector_isReady(&p->_pd);
+ if (ready > 0)
+ {
+ if (p->_frequency == 0.0f)
+ {
+ // Disregard if we are not periodic enough
+ if (p->_pd->_period_info[1] >= MAX_DEVIATION)
+ {
+ 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->_frames_after_shift = 0;
+ }
+ }
+ }
+ else
+ {
+ if (p->_pd->_period_info[1] < MIN_PERIODICITY)
+ p->_frames_after_shift = 0;
+ float f = calculate_frequency(detector);
+ if (f > 0.0f)
+ bias(detector, f);
+ }
+ }
+ return ready;
+}
+
+float tPitchDetector_getFrequency (tPitchDetector* const detector)
+{
+ _tPitchDetector* p = *detector;
+
+ return p->_frequency;
+}
+
+float tPitchDetector_getPeriodicity (tPitchDetector* const detector)
+{
+ _tPitchDetector* p = *detector;
+
+ return p->_pd->_period_info[1];
+}
+
+float tPitchDetector_predictFrequency (tPitchDetector* const detector, int init)
+{
+ _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;
+}
+
+void tPitchDetector_reset (tPitchDetector* const detector)
+{
+ _tPitchDetector* p = *detector;
+
+ p->_frequency = 0.0f;
+}
+
+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];
+ return 0.0f;
+}
+
+static inline void bias(tPitchDetector* const detector, float incoming)
+{
+ _tPitchDetector* p = *detector;
+
+ float current = p->_frequency;
+ ++p->_frames_after_shift;
+ int shifted = 0;
+
+ float f;
+
+ //=============================================================================
+ //float f = bias(current, incoming, shift);
+ {
+ float error = current / 32.0f; // approx 1/2 semitone
+ float diff = fabsf(current - incoming);
+ int done = 0;
+
+ // Try fundamental
+ if (diff < error)
+ {
+ f = incoming;
+ done = 1;
+ }
+ // Try harmonics and sub-harmonics
+ else if (p->_frames_after_shift > 2)
+ {
+ if (current > incoming)
+ {
+ float multiple = roundf(current / incoming);
+ if (multiple > 1.0f)
+ {
+ float h = incoming * multiple;
+ if (fabsf(current - h) < error)
+ {
+ f = h;
+ done = 1;
+ }
+ }
+ }
+ else
+ {
+ float multiple = roundf(incoming / current);
+ if (multiple > 1.0f)
+ {
+ float h = incoming / multiple;
+ if (fabsf(current - h) < error)
+ {
+ f = 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
+ shifted = 1;
+ f = incoming;
+ }
+ else f = current;
+ }
+ }
+
+ //=============================================================================
+
+ // Don't do anything if incoming is not periodic enough
+ // Note that we only do this check on frequency shifts
+ if (shifted)
+ {
+ if (p->_pd->_period_info[1] < MAX_DEVIATION)
+ {
+ // 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->_median = median3f(f, p->_median_b, p->_median_c);
+ p->_median_c = p->_median_b;
+ p->_median_b = f;
+ p->_frequency = p->_median;
+ }
+
+ }
+ 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;
+ }
}
--- a/leaf/Src/leaf-effects.c
+++ b/leaf/Src/leaf-effects.c
@@ -285,11 +285,11 @@
{
if(r[0] < min)
{
- for(i=0; i<n; i++)
- {
+// for(i=0; i<n; i++)
+// {
buf[i] = 0.0f;
return;
- }
+// }
}
tTalkbox_lpcDurbin(r, o, k, G); //calc reflection coeffs
@@ -612,11 +612,11 @@
{
if(r[0] < min)
{
- for(i=0; i<n; i++)
- {
+// for(i=0; i<n; i++)
+// {
buf[i] = 0.0f;
return;
- }
+// }
}
tTalkbox_lpcDurbin(r, o, k, G); //calc reflection coeffs
--- a/leaf/Src/leaf-math.c
+++ b/leaf/Src/leaf-math.c
@@ -731,3 +731,8 @@
c++;
return c;
}
+
+float median3f(float a, float b, float c)
+{
+ return fmax(fmin(a, b), fmin(fmax(a, b), c));
+}