30 #include "../config.h"
31 #include "../system/log.h"
32 #include "../system/eptexception.h"
33 #include "../piano/piano.h"
34 #include "../math/mathtools.h"
42 mOptimalSuperposition(),
43 mCurrentKernelKey(nullptr)
70 EptAssert(finalFFT->isValid(),
"The FFT data is not valid");
71 EptAssert(finalKey >= 0,
"The final key has to be set.");
74 std::shared_ptr<Key> key;
77 LogV(
"FFTAnalyzer started");
82 Write(
"4-final-logspec.dat", spectrum);
89 auto octaves = [
this] (
int keynumber,
int keyNumberOfA)
91 int distance = keyNumberOfA - keynumber;
92 if (distance > 36)
return 2;
93 else if (distance > 24)
return 1;
103 LogV(
"FFTAnalyzer: Estimated frequency f = %f, key = %d", f, finalKey);
110 LogV(
"FFTAnalyzer: Inharmonicity B = %f", B);
114 LogV(
"FFTAnalyzer: Accurate frequency f = %f", f);
121 LogV(
"FFTAnalyzer: Quality measure (cents) Q = %f", Q);
124 LogV(
"FFTAnalyzer: frequency correction cents C = %f", cents);
130 key.reset(
new Key());
132 key->setRecordedFrequency(f);
133 key->setMeasuredInharmonicity(B);
134 key->setRecognitionQuality(Q);
135 key->setSpectrum(spectrum);
136 key->setRecorded(
true);
140 LogV(
"FFTAnalyzer: found %i peaks.", static_cast<int>(peaks.size()));
141 key->setPeaks(peaks);
145 LogW(
"Frequence %f is out of bounds", f);
149 LogV(
"leaving FFTAnalyzer thread.");
176 EptAssert(finalFFT->isValid(),
"The FFT data is not valid");
177 EptAssert(keyIndex >= 0,
"The final key has to be set.");
186 if (targetFrequency <= 20 or targetFrequency > 10000)
194 if (centerFrequency<=10) centerFrequency = targetFrequency;
201 const int searchSize = 200;
209 double middle = centerFrequency;
213 middle *= 2 * sqrt((1+4*B)/(1+B));
216 for (
int i=0; i<searchSize; ++i)
219 if (m>0 and m<static_cast<int>(spectrum.size()))
221 double value = spectrum[m] * spectrum[m];
222 if (value > maximum) maximum = value;
223 zoomedPeak[i] = value;
231 for (
auto &element : zoomedPeak) element /= maximum;
232 out = std::move(zoomedPeak);
254 index -= searchSize / 2;
256 double detectedFrequency = centerFrequency * std::pow(2.0, (index) / 1200.0);
257 EptAssert(detectedFrequency > 1 && detectedFrequency < 20000,
"Unallowed frequency range");
262 result->deviationInCents =
static_cast<int>(index - computedIndex);
263 result->detectedFrequency = detectedFrequency;
264 result->positionOfMaximum = index;
265 result->tuningDeviationCurve = std::move(out);
267 LogV(
"Deviation %d, comp index %d", result->deviationInCents, computedIndex);
293 const double b = 2.0 * fftData->fft.size() / fftData->samplingRate;
294 std::function<double(double)> mtoq = [
this,b] (
double m)
306 c = c / (c.real() * c.real() + c.imag() * c.imag());
315 const int searchOffset = searchSize / 2;
319 for (
int j = -searchOffset; j < searchSize - searchOffset; j++) {
320 out[j + searchOffset] = 0;
322 out[j + searchOffset] += kernel[(i - j +
NumberOfBins) % NumberOfBins] * signal[i];
344 and spectrum.size()>0,
"Inconsistent arguments");
366 and spectrum.size()>0,
"Inconsistent arguments");
369 double y1=spectrum[mmax-1], y2=spectrum[mmax], y3=spectrum[mmax+1];
370 double N = y1 - 2*y2 + y3;
371 if (N == 0)
return mmax;
374 double correction = (y1-y3)/2/N;
375 if (fabs(correction)<1)
return mmax+correction;
396 EptAssert(conertPitch>390 or conertPitch<500,
"Concert pitch unreasonable.");
398 double d = 17.3123*log(f / conertPitch);
400 double c =0.000019394+0.079694594*d-0.003718646*d*d+0.000450934*d*d*d + 0.000003724*d*d*d*d;
401 int k=-1; k =
static_cast<int>(keyNumberOfA + d-c/100+0.5);
402 return (k>=0 and k<numberOfKeys ? k : -1);
422 EptAssert(concertPitch>390 or concertPitch<500,
"Concert pitch unreasonable.");
424 double d = keynumber - keyNumberOfA;
426 double c =0.000019394+0.079694594*d-0.003718646*d*d+
427 0.000450934*d*d*d + 0.000003724*d*d*d*d;
428 return pow(2.0, d/12+c/1200) * concertPitch;
452 const double factor = 1.0 + 0.000577623 * cents;
453 const double b = 2.0 * fftData->fft.size() / fftData->samplingRate;
458 if (q1 > 0 and q2 < static_cast<int>(fftData->fft.size()))
462 for (
int q=q1; q<q2; ++q)
if (fftData->fft[q]>fftmax)
463 { fftmax = fftData->fft[q]; qmax=q; }
486 return (f > 100 ? exp(-15.45 + 1.354*log(f)) : 0.000099575);
513 if (spectrum.size()==0 or f<20)
return 0;
517 if (f > 2250)
return 0;
524 double z = f2*f2/f/f;
525 if (z>4.4 or z<4)
return 0;
526 double B = (4-z)/(z-16);
527 LogV(
"FFTAnalyzer: treble: B = %f", B);
544 LogV(
"FFTAnalyzer: expected B = %f", expected_B);
547 for (
double scan_B = expected_B/5; scan_B <= expected_B*5; scan_B*=1.03)
550 for (
int n=1; n<=N; ++n)
552 double fn = n*f*sqrt((1+scan_B*n*n)/(1+scan_B));
557 for (
int r=0; r<R; r++)
559 int m =
static_cast<int>(mn+r-R/2);
561 partialspectrum[r]=pow(spectrum[m],2);
564 for (
int r=0; r<R; r++) superposition[r]+=partialspectrum[r];
575 Write(
"7-find-inharmonicity.dat",superposition);
578 LogV(
"FFTAnalyzer: finished estimating inharmonicity: B = %f", B);
580 #if CONFIG_ENABLE_XMGRACE
582 #endif // CONFIG_ENABLE_XMGRACE
606 double variance = M2-M1*M1;
608 return M0/(1+0.1*pow(variance,1.5));
634 const double f,
const double B)
636 const int MaxNumberOfPeaks = 50;
637 auto InharmonicPartial = [] (
double f,
int n,
double B) {
return f*n*sqrt((1+B*n*n)/(1+B)); };
638 int N=std::min(MaxNumberOfPeaks, static_cast<int>(10000.0/f));
640 for (
int n=1; n<=N; ++n)
642 double fn = InharmonicPartial(f,n,B);
648 peaks[fc]=spectrum[m];
661 #if CONFIG_ENABLE_XMGRACE
662 std::ofstream os(filename);
663 for (uint m=0; m<v.size(); ++m)
665 if (v.size() !=
static_cast<size_t>(
NumberOfBins)) os << m <<
"\t" << v[m] << std::endl;
670 (void)filename; (void)v;
671 #endif // CONFIG_ENABLE_XMGRACE
678 #if CONFIG_ENABLE_XMGRACE
679 std::ofstream os(filename);
680 for (uint m=0; m<v.size(); ++m)
682 os << m <<
"\t" << v[m].real() << std::endl;
684 os <<
"&" << std::endl;
685 for (uint m=0; m<v.size(); ++m)
687 os << m <<
"\t" << v[m].imag() << std::endl;
691 (void)filename; (void)v;
692 #endif // CONFIG_ENABLE_XMGRACE
699 #if CONFIG_ENABLE_XMGRACE
700 std::ofstream os(filename);
701 os <<
"@g0 type logxy" << std::endl;
702 os <<
"# logspec / peaks according to F&B / peaks in the list" << std::endl;
703 for (
int m=0; m<Key::NumberOfBins; ++m) if (v[m]>1E-100) os <<
Key::IndexToFrequency(m) <<
"\t" << v[m] << std::endl;
704 os <<
"&" << std::endl;
716 os << fn-0.00001 <<
'\t' << 1E-9 << std::endl;
717 os << fn <<
'\t' << p.second << std::endl;
718 os << fn+0.00001 <<
'\t' << 1E-9 << std::endl;
721 (void)filename; (void)peaks; (void)v;
722 #endif // CONFIG_ENABLE_XMGRACE
bool isRecorded() const
Get recorded flag.
double getRecordedFrequency() const
Get recorded frequency.
double findAccuratePeakFrequency(FFTDataPointer fftData, double f, int cents=5)
Find the accurate frequency of a spectral peak in the original FFT.
FFTAnalyzer()
Constructor.
Key::PeakListType PeakListType
Type for a peak map.
std::vector< FFTComplexType > FFTComplexVector
SpectrumType mCurrentKernel
The current kernel for the key detection.
Class describing a single piano key.
TuningDeviationCurveType computeTuningDeviation(const SpectrumType &kernel, const SpectrumType &signal, int searchSize)
std::vector< double > TuningDeviationCurveType
The FrequencyDetectionResultStruct struct.
double getExpectedInharmonicity(double f)
Key::SpectrumType SpectrumType
Type of a log spectrum.
static double IndexToFrequency(double m)
Convert continuous slot index to frequency in Hz.
double estimateFrequencyShift()
PeakListType identifyPeaks(FFTDataPointer fftData, const SpectrumType &spectrum, const double f, const double B)
void Write(std::string filename, SpectrumType &v)
std::pair< FFTAnalyzerErrorTypes, std::shared_ptr< Key > > analyse(const Piano *piano, FFTDataPointer finalFFT, int finalKey)
Main analyzing function.
No intensity in the signal near expected peak.
const Keyboard & getKeyboard() const
The recorded frequency is out of the piano range.
double getComputedFrequency() const
Get computed frequency.
static double FrequencyToRealIndex(double f)
Convert frequency to real-valued logbin index.
std::complex< double > FFTComplexType
FFT_Implementation mFFT
Instance of FFT implementation.
int findNearestKey(double f, double conertPitch, int numberOfKeys, int keyNumberOfA)
Compute the number of the nearest key.
int getKeyNumberOfA4() const
SpectrumType constructKernel(const SpectrumType &originalSpectrum)
const double & getConcertPitch() const
const SpectrumType & getSpectrum() const
Get a read-only reference to mSpectrum.
The analyzer needs a computed frequency.
FrequencyDetectionResult detectFrequencyOfKnownKey(FFTDataPointer finalFFT, const Piano *piano, const Key &key, int keyIndex)
FFTAnalyzer::detectFrequencyOfKnownKey.
const Key * mCurrentKernelKey
The key of which mCurrentKernel belongs to.
int locatePeak(const SpectrumType &spectrum, int m, int width)
static int FrequencyToIndex(double f)
Convert frequency to logbin index.
std::shared_ptr< FFTData > FFTDataPointer
Shared pointer of FFTData.
double interpolatePeakPosition(const SpectrumType &spectrum, int m, int width)
double estimateInharmonicity(FFTDataPointer fftData, SpectrumType &spectrum, double f)
Estimate the inharmonicity B.
double getExpectedInharmonicity(double f) const
Compute expected approximative inharmonicity.
std::shared_ptr< FrequencyDetectionResultStruct > FrequencyDetectionResult
void constructLogBinnedSpectrum(FFTDataPointer fftData, SpectrumType &spectrum)
Construct logarithmically binned spectrum from the mFinalFFT.
double estimateFrequency(int keynumber, double concertPitch, int keyNumberOfA)
Estimate the frequency for a given keynumber.
void WritePeaks(std::string filename, SpectrumType &v, PeakListType &peaks)
void calculateFFT(const FFTRealVector &in, FFTComplexVector &out)
Foward FFT, mapping a real vector with size N to a complex one with size N/2+1.
SpectrumType mOptimalSuperposition
Superposition of the partials.