void PitchTracker::run() { for (;;) { busy = false; sem_wait(&m_trig); if (error) { continue; } float sum = 0.0; for (int k = 0; k < m_buffersize; ++k) { sum += fabs(m_input[k]); } float threshold = (m_audioLevel ? signal_threshold_off : signal_threshold_on); m_audioLevel = (sum / m_buffersize >= threshold); if ( m_audioLevel == false ) { if (m_freq != 0) { m_freq = 0; new_freq(); } continue; } memcpy(m_fftwBufferTime, m_input, m_buffersize * sizeof(*m_fftwBufferTime)); memset(m_fftwBufferTime+m_buffersize, 0, (m_fftSize - m_buffersize) * sizeof(*m_fftwBufferTime)); fftwf_execute(m_fftwPlanFFT); for (int k = 1; k < m_fftSize/2; k++) { m_fftwBufferFreq[k] = sq(m_fftwBufferFreq[k]) + sq(m_fftwBufferFreq[m_fftSize-k]); m_fftwBufferFreq[m_fftSize-k] = 0.0; } m_fftwBufferFreq[0] = sq(m_fftwBufferFreq[0]); m_fftwBufferFreq[m_fftSize/2] = sq(m_fftwBufferFreq[m_fftSize/2]); fftwf_execute(m_fftwPlanIFFT); double sumSq = 2.0 * static_cast<double>(m_fftwBufferTime[0]) / static_cast<double>(m_fftSize); for (int k = 0; k < m_fftSize - m_buffersize; k++) { m_fftwBufferTime[k] = m_fftwBufferTime[k+1] / static_cast<float>(m_fftSize); } int count = (m_buffersize + 1) / 2; for (int k = 0; k < count; k++) { sumSq -= sq(m_input[m_buffersize-1-k]) + sq(m_input[k]); // dividing by zero is very slow, so deal with it seperately if (sumSq > 0.0) { m_fftwBufferTime[k] *= 2.0 / sumSq; } else { m_fftwBufferTime[k] = 0.0; } } const float thres = 0.99; // was 0.6 int maxAutocorrIndex = findsubMaximum(m_fftwBufferTime, count, thres); float x = 0.0; if (maxAutocorrIndex >= 0) { parabolaTurningPoint(m_fftwBufferTime[maxAutocorrIndex-1], m_fftwBufferTime[maxAutocorrIndex], m_fftwBufferTime[maxAutocorrIndex+1], maxAutocorrIndex+1, &x); x = m_sampleRate / x; if (x > 999.0) { // precision drops above 1000 Hz x = 0.0; } } if (m_freq != x) { m_freq = x; new_freq(); } } }
double MyTransforms::get_max_note_change(float *input, double period) { //TODO /*matlab code l = length(s); m = floor(l / 4); % m is the maximum size sub-window to use % w is the sub-window size if p < m w = p * floor(m / p); else w = p; end n = -4:4; ln = length(n); left = cell(1, ln); right = cell(1, ln); left_pow = zeros(1, ln); right_pow = zeros(1, ln); pow = zeros(1, ln); err = zeros(1, ln); for i = 1:ln left{i} = s(1:(w-n(i))); % a smaller delay period has a larger window size, to ensure only the same data is used right{i} = s(1+p+n(i):w+p); left_pow(i) = sum(left{i}.^2); right_pow(i) = sum(right{i}.^2); err(i) = sum((left{i} - right{i}) .^ 2); end */ int i, j, j2; int max_subwindow = n / 4; int subwindow_size; if(period < 1.0) return 0.0; //period too small if(period > n/2) { printf("period = %lf\n", period); return 0.0; } int iPeriod = int(floor(period)); if(period < double(max_subwindow)) subwindow_size = int(floor(period * (double(max_subwindow) / period))); else subwindow_size = int(floor(period)); int num = n-subwindow_size-iPeriod; std::vector<int> offsets; for(j=-4; j<=4; j++) offsets.push_back(j); //do a total of 9 subwindows at once. 4 either side. int ln = offsets.size(); std::vector<float> left(ln); std::vector<float> right(ln); std::vector<float> left_pow(ln); std::vector<float> right_pow(ln); std::vector<float> pow(ln); std::vector<float> err(ln); std::vector<float> result(ln); std::vector<float> unsmoothed(num); std::vector<float> smoothed(num); std::vector<float> smoothed_diff(num); //calc the values of pow and err for the first in each row. for(i=0; i<ln; i++) { left_pow[i] = right_pow[i] = pow[i] = err[i] = 0; for(j=0, j2=iPeriod+offsets[i]; j<subwindow_size-offsets[i]; j++, j2++) { left_pow[i] += sq(input[j]); right_pow[i] += sq(input[j2]); err[i] += sq(input[j] - input[j2]); } } //printf("subwindow_size=%d, num=%d, period=%lf\n", subwindow_size, num, period); /*matlab code for j = 1:(num-1) for i = 1:ln pow(i) = (left_pow(i) + right_pow(i)); resulte(i, j) = err(i); resultp(i, j) = pow(i); result(i, j) = 1 - (err(i) / pow(i)); %err = err - (s(j) - s(j+p)).^2 + (s(j+w) - s(j+w+p)).^2; err(i) = err(i) - ((s(j) - s(j+p+n(i))).^2) + (s(j+w-n(i)) - s(j+w+p)).^2; left_pow(i) = left_pow(i) - s(j).^2 + s(j+w-n(i)).^2; right_pow(i) = right_pow(i) - s(j+p+n(i)).^2 + s(j+p+w).^2; end end for i = 1:ln pow(i) = (left_pow(i) + right_pow(i)); result(i, num) = 1 - (err(i) / pow(i)); end */ //TODO: speed up this for loop for(j=0; j<num-1; j++) { for(i=0; i<ln; i++) { pow[i] = left_pow[i] + right_pow[i]; result[i] = 1.0 - (err[i] / pow[i]); err[i] += -sq(input[j] - input[j+iPeriod+offsets[i]]) + sq(input[j+subwindow_size-offsets[i]] - input[j+subwindow_size+iPeriod]); left_pow[i] += -sq(input[j]) + sq(input[j+subwindow_size-offsets[i]]); right_pow[i] += -sq(input[j+iPeriod+offsets[i]]) + sq(input[j+iPeriod+subwindow_size]); } /*matlab code for j = 1:num [dud pos] = max(result(:,j)); if pos > 1 && pos < ln [period(j) dummy] = parabolaPeak(result(pos-1, j), result(pos, j), result(pos+1, j), p+n(pos)); else period(j) = p+n(pos); end period_int(j) = p+n(pos); end*/ int pos = int(std::max_element(result.begin(), result.begin()+ln) - result.begin()); if(pos > 0 && pos < ln-1) unsmoothed[j] = double(iPeriod + offsets[pos]) + parabolaTurningPoint(result[pos-1], result[pos], result[pos+1]); else unsmoothed[j] = double(iPeriod + offsets[pos]); } fastSmooth->fast_smoothB(&(unsmoothed[0]), &(smoothed[0]), num-1); int max_pos = 0; for(j=0; j<num-2; j++) { smoothed_diff[j] = fabs(smoothed[j+1] - smoothed[j]); //printf("%f ", smoothed[j]); if(smoothed_diff[j] > smoothed_diff[max_pos]) max_pos = j; } //printf("\nsmooted_diff=%f\n", smoothed_diff[max_pos]); //return smoothed_diff[max_pos] / period * double(rate) * double(n) / 40000.0; double ret = smoothed_diff[max_pos] / period * double(rate) * double(subwindow_size) / 10000.0; //ret = (ret < 0.19) ? 0.0 : 1.0; return ret; }