68 mAccumulator(NumberOfBins),
69 mPitch(mNumberOfKeys),
70 mInitialPitch(mNumberOfKeys),
71 mRecalculateEntropy(false),
73 mRecalculateFrequency(0)
111 LogI(
"Compute initial condition");
116 MessageHandler::send<MessageCaluclationProgress>
119 LogI(
"Start entropy minimization");
122 LogI(
"CalculationManager: Stop calculation");
146 switch (m->getType())
150 auto message(std::static_pointer_cast<MessageChangeTuningCurve>(m));
151 double f = message->getFrequency();
152 int keynumber = message->getKeyNumber();
153 if (keynumber>=0)
if (f !=
mKeyboard[keynumber].getComputedFrequency())
155 LogI (
"Manual change of tuning curve during computation");
159 #if CONFIG_ENABLE_XMGRACE
161 #endif // CONFIG_ENABLE_XMGRACE
185 #if CONFIG_ENABLE_XMGRACE
187 #endif // CONFIG_ENABLE_XMGRACE
189 LogI(
"EntropyMinimizer: start auditory preprocessing");
194 LogI(
"EntropyMinimzer: Normalize spectra ");
195 for (
auto &key :
mKeys)
202 LogI(
"EntropyMinimzer: Clean spectra ");
203 for (
auto &key : mKeys)
210 LogI(
"EntropyMinimizer: Cut low frequencies ");
211 for (
auto &key : mKeys)
218 LogI(
"EntropyMinimzer: Apply SPLA filter");
220 for (
auto &key : mKeys)
228 LogI(
"EntropyMinimizer: Extrapolate missing inharmonicity values");
232 #if CONFIG_ENABLE_XMGRACE
233 std::ofstream os(
"0-measured-inharmonicity.dat");
235 os << k <<
" " << mKeys[k].getMeasuredInharmonicity() << std::endl;
237 os.open(
"0-extrapolated-inharmonicity.dat");
239 os << k <<
" " << mKeys[k].getMeasuredInharmonicity() << std::endl;
241 #endif // CONFIG_ENABLE_XMGRACE
243 LogI(
"EntropyMinimizer: Amend high-frequency spectral lines");
246 LogI(
"EntropyMinimizer: Mollify spectral lines");
247 for (
auto &key : mKeys)
255 #if CONFIG_ENABLE_XMGRACE
257 #endif // CONFIG_ENABLE_XMGRACE
260 LogI(
"EntropyMinimizer: Stop auditory preprocessing");
297 for (
int keynumber = 0; keynumber <
mNumberOfKeys; ++keynumber)
345 int shift,
double intensity)
366 EptAssert(abs(pitch)<100,
"Pitch should be less than a half tone");
371 int old_pitchdiff =
mPitch[keynumber] - recorded_pitch;
372 int new_pitchdiff = pitch - recorded_pitch;
376 mPitch[keynumber] = pitch;
392 int pitchdiff =
mPitch[k] - recorded_pitch;
429 auto B = [
this] (
int keynumber)
430 {
return mKeys[keynumber].getMeasuredInharmonicity(); };
433 auto cents = [B] (
int keynumber,
int n)
434 {
return 600.0 /
MathTools::LOG2 * log((1+n*n*B(keynumber))/(1+B(keynumber))); };
437 auto setValue = [
this,&progress](
int k,
double value)
451 double pitchA5 = cents(numberA4,2);
452 double pitchA3 = cents(numberA4,2)-cents(numberA3,4);
453 for (
int k=numberA3; k<
mKeyNumberOfA4; ++k) setValue(k,pitchA3*(mKeyNumberOfA4-k)/12.0);
454 for (
int k=mKeyNumberOfA4+1; k<=numberA5; ++k) setValue(k,pitchA5*(k-mKeyNumberOfA4)/12.0);
459 double pitch42 =
mInitialPitch[k-12] + cents(k-12,4) -cents(k,2);
461 setValue(k,0.3*pitch42 + 0.7*pitch21);
465 for (
int k=numberA3-1; k>=0; k--)
467 double pitch63 =
mInitialPitch[k+12] + cents(k+12,3) -cents(k,6);
468 double pitch105 =
mInitialPitch[k+12] + cents(k+12,5) -cents(k,10);
469 double fraction = 1.0*k/numberA3;
470 setValue(k,pitch63*fraction+pitch105*(1-fraction));
490 const double toleranceA0 = 30;
491 const double toleranceA2 = 15;
492 const double toleranceA4 = 5;
493 const double toleranceA6 = 15;
494 const double toleranceA7 = 30;
496 auto f = [toleranceA4] (
double a,
double b,
double k)
497 {
return toleranceA4 + a*k*k + b*k*k*k; };
499 const double a1 = (-toleranceA0+8*toleranceA2-7*toleranceA4)/2304.0;
500 const double b1 = (-toleranceA0+4*toleranceA2-3*toleranceA4)/55296.0;
501 const double a2 = (-19*toleranceA4+27*toleranceA6-8*toleranceA7)/5184.0;
502 const double b2 = (5*toleranceA4-9*toleranceA6+4*toleranceA7)/62208.0;
550 std::random_device rd;
552 static std::mt19937 generator(rd());
554 std::binomial_distribution<int> binomial(cents);
555 std::uniform_int_distribution<int> keydist(0,
mNumberOfKeys-1);
556 std::uniform_real_distribution<double> probdist(0,1);
567 LogI(
"STARTING WITH ENTROPY H=%lf.",H);
570 uint64_t attemptsCounter = 0;
571 uint64_t updatesSinceLastChange = 0;
574 auto acceptUpdate = [&H,&attemptsCounter,&updatesSinceLastChange,
this] (
int keynumber,
double Hnew)
578 LogI(
"ENTROPY H=%lf.",H);
583 updatesSinceLastChange /= 2;
592 double methodRatio = 1;
593 double lastProgress = 0;
598 int stepsToFinish = 100;
600 if (accuracy ==
"low") {stepsToFinish = 50;}
601 else if (accuracy ==
"standard") {stepsToFinish = 100;}
602 else if (accuracy ==
"high") {stepsToFinish = 150;}
603 else if (accuracy ==
"infinite") {stepsToFinish = -1;}
604 else {
LogE(
"Accuracy %s is not supported, using standard.", accuracy.c_str());}
607 LogV(
"Accuracy is %s, using %d as max steps.", accuracy.c_str(), stepsToFinish);
616 ++updatesSinceLastChange;
619 if (stepsToFinish > 0)
621 double progress =
static_cast<double>(updatesSinceLastChange) / stepsToFinish;
622 progress = std::max(progress, lastProgress);
623 pbAcc = std::max(-1.0, std::min(1.0, (progress - lastProgress)));
624 pbVel += pbAcc * 1.0;
625 pbVel = std::max(0.0, pbVel);
626 progress = pbVel * 0.001;
627 lastProgress = progress;
629 if (attemptsCounter % 100 == 0) {
630 LogV(
"Progress: %f", progress);
634 if (progress > 1)
break;
644 LogI(
"RESET ENTROPY H = %lf.",H);
656 do keynumber = keydist(generator);
while (keynumber==
mKeyNumberOfA4);
659 if (probdist(generator)>methodRatio)
662 int oldpitch =
mPitch[keynumber];
666 do newpitch = oldpitch + binomial(generator)-cents/2;
667 while (((fabs(oldpitch-initialpitch) < tolerance and
668 fabs(newpitch-initialpitch) > tolerance)
669 or newpitch == oldpitch)
674 if (Hnew < H) acceptUpdate (keynumber,Hnew);
682 std::vector<int> savePitch(
mPitch);
683 int sign = (probdist(generator)<0.5 ? 1:-1);
686 for (
int k=0; k<=keynumber; ++k)
mPitch[k]+=sign;
697 acceptUpdate (-1,Hnew);
698 methodRatio *= 0.995;
707 #if CONFIG_ENABLE_XMGRACE
709 #endif // CONFIG_ENABLE_XMGRACE
726 double ET440 = 440.0 * pow(2,1.0/12.0*(keynumber-
mKeyNumberOfA4));
727 double frec =
mKeys[keynumber].getRecordedFrequency();
749 double ET440 = 440.0 * pow(2,1.0/12.0*(keynumber-
mKeyNumberOfA4));
761 #if CONFIG_ENABLE_XMGRACE
762 std::ofstream os (filename);
770 #endif // CONFIG_ENABLE_XMGRACE
779 #if CONFIG_ENABLE_XMGRACE
780 std::stringstream ss;
781 ss <<
"spectrum/" << k <<
"-"<< filename <<
".dat";
782 std::ofstream os(ss.str());
784 os <<
"# pitch= " << pitch << std::endl;
785 for (uint m=abs(pitch); m<v.size()-abs(pitch); ++m)
787 if (v.size() !=
static_cast<size_t>(
NumberOfBins)) os << m+pitch <<
"\t" << v[m] << std::endl;
792 (void)filename; (void)k; (void)pitch;
793 #endif // CONFIG_ENABLE_XMGRACE
int getTolerance(int keynumber)
Allowed tolerance of the tuning curve during the Monte Carlo process.
Class of functions for auditory preprocessing.
std::shared_ptr< Message > MessagePtr
Global type of a shared message pointer.
SpectrumType mAccumulator
Accumulator holding the sum of all spectra.
The AlgorithmFactory class is a template class to be created with the actual Algorithm.
void extrapolateInharmonicity()
Extrapolate inharmonicity and estimate missing values.
std::vector< int > mPitch
Vector of pitches (in cents)
std::vector< double > mInitialPitch
Vector of initial pitches.
void msleep(double milliseconds)
Sleep function for staying idle.
bool mRecalculateEntropy
Flag for entropy recalculation (after manual intervention by the user)
Key::SpectrumType SpectrumType
void ComputeInitialTuningCurve()
Compute initial condition of the tuning curve.
void writeAccumulator(std::string filename)
int mRecalculateKey
Number of manually changed key.
bool performAuditoryPreprocessing()
Auditory preprocessing.
double getDefiningTempFrequency(int keynumber, double cents=0, double A4=0) const
Compute the defining temperatent.
Class describing a single piano key.
void initializeSPLAFilter()
Initialize the filter function in the vector mdBA.
void algorithmWorkerFunction() overridefinal
Main calculation, running in an independent thread.
void setAllSpectralComponents()
Keyboard & mKeyboard
Reference to the keyboard.
void addToAccumulator(SpectrumType &spectrum, int shift, double intensity)
Add or subtract a spectrum to the accumulator.
void applyMollifier(Key &key)
double getEqualTempFrequency(int keynumber, double cents=0, double A4=0) const
Function returning the equal temperament.
int mUpperCutoff
Upper cutoff for fluctuations.
static double IndexToFrequency(double m)
Convert continuous slot index to frequency in Hz.
virtual void handleMessage(MessagePtr m) overridefinal
Message listener and dispatcher for mouse clicks in the tuning curve.
int getRecordedPitchET440AsInt(int keynumber)
Get recorded pitch.
double mRecalculateFrequency
Frequency of manually changed key.
const int mKeyNumberOfA4
Number of A4.
static double ftom(double f)
Convert frequency to array index in cent spacing.
void convertToSPLA(SpectrumType &s)
Compute A-weighted sound pressure level SPLA.
const AlgorithmFactoryDescription & mFactoryDescription
Namespace for all entropy minimizer components.
static const AlgorithmFactory mSingleton
void showCalculationProgress(double fraction)
Transmit the current percentage of progress to the messaging system.
void updateTuningcurve()
Update the entire tuning curve.
int getPitchET440(int keynumber, double f)
Get pitch from frequ.
Message that the tuning curve has been adapted.
void updateTuningCurve(int keynumber, double frequency)
bool checkDataConsistency()
Check consistency of the piano dataset.
Keys & mKeys
Reference to the keys.
void modifySpectralComponent(int key, int pitch)
The Algorithm class is a basic abstract class for any algorithm.
double getElement(SpectrumType &spectrum, int m)
Truncate logspectrum at the cutoffs and return an element.
const SpectrumType & getSpectrum() const
Get a read-only reference to mSpectrum.
EntropyMinimizer(const Piano &piano, const AlgorithmFactoryDescription &desciption)
Constructor.
void improveHighFrequencyPeaks()
Improve high-frequency spectral lines.
double getRecordedPitchET440(int keynumber)
Get recorded pitch.
Piano mPiano
Copy of the piano.
void minimizeEntropy()
Entropy minimizer.
void normalizeSpectrum(Key &key)
Normalize spectrum.
bool cancelThread() const
Cancel-flag getter method, thread-safe.
const std::string & getStringParameter(const std::string &id) const
void cutLowFrequencies(Key &key)
Cut all frequencies below 5/6*f1 in order to reduce noise.
double computeEntropy()
Compute the entropy of the current normalized accumulator content.
void cleanSpectrum(Key &key)
Clean logarithmically binned spectrum.
int mLowerCutoff
Lower cutoff for fluctuations.
void writeSpectrum(int k, std::string filename, int pitch=0)
const Key & getKey(int i) const
const int mNumberOfKeys
The number of keys.