Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
entropyminimizer.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Iterative entropy minimization
22 //=============================================================================
23 
24 #include "entropyminimizer.h"
25 
26 #include <random>
27 #include <iostream>
28 #include <algorithm>
29 #include <sstream>
30 
33 #include "core/piano/piano.h"
34 #include "core/math/mathtools.h"
35 #include "core/system/timer.h"
36 #include "core/system/log.h"
40 
41 #include "auditorypreprocessing.h"
42 
43 //=============================================================================
44 // Create algorithm factory
45 //=============================================================================
46 
47 template<>
50  AlgorithmFactoryDescription("entropyminimizer"));
51 
52 namespace entropyminimizer
53 {
54 
55 
56 //-----------------------------------------------------------------------------
57 // Constructor
58 //-----------------------------------------------------------------------------
59 
64 
66  const AlgorithmFactoryDescription &description) :
67  Algorithm(piano, description),
68  mAccumulator(NumberOfBins),
69  mPitch(mNumberOfKeys),
70  mInitialPitch(mNumberOfKeys),
71  mRecalculateEntropy(false),
72  mRecalculateKey(-1),
73  mRecalculateFrequency(0)
74 {
75  // Define cutoffs for the logarithmic spectra
76  // In order to be able to shift them up and down by up to one half tone,
77  // there should be a section of 100 cent at each end which is zero.
78  double highestfrequency = mPiano.getEqualTempFrequency(mNumberOfKeys-1,0,440)*1.13;
79  mLowerCutoff = 100;
80  mUpperCutoff = std::min(NumberOfBins-100,
81  MathTools::roundToInteger(ftom(highestfrequency)));
82 }
83 
84 
85 //-----------------------------------------------------------------------------
86 // Worker function running in an independent thread
87 //-----------------------------------------------------------------------------
88 
96 
98 {
99  // show initially a horizontal tuning curve
100  for (int k=0; k<mNumberOfKeys; k++)
101  {
102  double f = mPiano.getEqualTempFrequency(k,0,440);
103  mKeyboard[k].setComputedFrequency(f);
104  updateTuningCurve(k, f);
105  }
106 
107  bool success = performAuditoryPreprocessing();
108 
109  if (success)
110  {
111  LogI("Compute initial condition");
113 
114  msleep(500);
115 
116  MessageHandler::send<MessageCaluclationProgress>
118 
119  LogI("Start entropy minimization");
120  minimizeEntropy();
121 
122  LogI("CalculationManager: Stop calculation");
123  }
124 }
125 
126 
127 
128 //-----------------------------------------------------------------------------
129 // Message listener and dispatcher
130 //-----------------------------------------------------------------------------
131 
141 
143 {
144  EptAssert(m, "Message has to exist!");
145 
146  switch (m->getType())
147  {
149  {
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())
154  {
155  LogI ("Manual change of tuning curve during computation");
156  mRecalculateEntropy = true;
158  mRecalculateKey = keynumber;
159 #if CONFIG_ENABLE_XMGRACE
160  writeSpectrum(keynumber,"modified",mPitch[keynumber]-getRecordedPitchET440(keynumber));
161 #endif // CONFIG_ENABLE_XMGRACE
162 
163  }
164  }
165  break;
166  default:
167  break;
168  }
169 }
170 
171 
172 //-----------------------------------------------------------------------------
173 // Auditory preprocessing
174 //-----------------------------------------------------------------------------
175 
182 
184 {
185 #if CONFIG_ENABLE_XMGRACE
186  for (int k=0; k < mNumberOfKeys; ++k) writeSpectrum(k,"before");
187 #endif // CONFIG_ENABLE_XMGRACE
188 
189  LogI("EntropyMinimizer: start auditory preprocessing");
191 
192  if (not AP.checkDataConsistency()) return false;
193 
194  LogI("EntropyMinimzer: Normalize spectra ");
195  for (auto &key : mKeys)
196  {
197  AP.normalizeSpectrum(key);
198  showCalculationProgress(key,0,0.25);
199  if (cancelThread()) return false;
200  }
201 
202  LogI("EntropyMinimzer: Clean spectra ");
203  for (auto &key : mKeys)
204  {
205  AP.cleanSpectrum(key);
206  showCalculationProgress(key,0.25,0.25);
207  if (cancelThread()) return false;
208  }
209 
210  LogI("EntropyMinimizer: Cut low frequencies ");
211  for (auto &key : mKeys)
212  {
213  AP.cutLowFrequencies(key);
214  showCalculationProgress(key,0.5,0.25);
215  if (cancelThread()) return false;
216  }
217 
218  LogI("EntropyMinimzer: Apply SPLA filter");
220  for (auto &key : mKeys)
221  {
222  SpectrumType &spectrum = key.getSpectrum();
223  AP.convertToSPLA(spectrum);
224  showCalculationProgress(key,0.75,0.25);
225  if (cancelThread()) return false;
226  }
227 
228  LogI("EntropyMinimizer: Extrapolate missing inharmonicity values");
230  if (cancelThread()) return false;
231 
232 #if CONFIG_ENABLE_XMGRACE
233  std::ofstream os("0-measured-inharmonicity.dat");
234  for (int k=0; k < mNumberOfKeys; ++k)
235  os << k << " " << mKeys[k].getMeasuredInharmonicity() << std::endl;
236  os.close();
237  os.open("0-extrapolated-inharmonicity.dat");
238  for (int k=0; k < mNumberOfKeys; ++k)
239  os << k << " " << mKeys[k].getMeasuredInharmonicity() << std::endl;
240  os.close();
241 #endif // CONFIG_ENABLE_XMGRACE
242 
243  LogI("EntropyMinimizer: Amend high-frequency spectral lines");
245 
246  LogI("EntropyMinimizer: Mollify spectral lines");
247  for (auto &key : mKeys)
248  {
249  AP.applyMollifier(key);
250  showCalculationProgress(key,0,1);
251  if (cancelThread()) return false;
252  }
253 
254 
255 #if CONFIG_ENABLE_XMGRACE
256  for (int k=0; k < mNumberOfKeys; ++k) writeSpectrum(k,"final");
257 #endif // CONFIG_ENABLE_XMGRACE
258 
260  LogI("EntropyMinimizer: Stop auditory preprocessing");
261  return true;
262 }
263 
264 
265 
266 //-----------------------------------------------------------------------------
267 // Update the displayed tuning curve
268 //-----------------------------------------------------------------------------
269 
278 
280 {
281  EptAssert (keynumber>=0 and keynumber<mNumberOfKeys,"Range of keynumber");
282  double f = mPiano.getDefiningTempFrequency(keynumber, mPitch[keynumber],440);
283  updateTuningCurve(keynumber, f);
284 }
285 
286 
294 
296 {
297  for (int keynumber = 0; keynumber < mNumberOfKeys; ++keynumber)
298  updateTuningcurve(keynumber);
299 }
300 
301 
302 //-----------------------------------------------------------------------------
303 // Clear the accumulator as well as the intensities and pitches
304 //-----------------------------------------------------------------------------
305 
307 {
308  mAccumulator.assign(NumberOfBins,0);
309  mPitch.assign(mNumberOfKeys,0);
310  mInitialPitch.assign(mNumberOfKeys,0);
311 }
312 
313 
314 //-----------------------------------------------------------------------------
315 // Truncate logspectrum at the cutoffs
316 //-----------------------------------------------------------------------------
317 
323 
325 {
326  return (m>mLowerCutoff and m<mUpperCutoff ? spectrum[m] : 0);
327 }
328 
329 
330 //-----------------------------------------------------------------------------
331 // Add spectrum to the accumulator
332 //-----------------------------------------------------------------------------
333 
343 
345  int shift, double intensity)
346 {
347  for (int m=0; m<NumberOfBins; ++m)
348  {
349  mAccumulator[m] += getElement(spectrum,m-shift) * intensity;
350  // Tiny negative values are possible and will be truncated here:
351  if (mAccumulator[m]<0 and mAccumulator[m]>-1E-10) mAccumulator[m] = 0;
352  // Larger negative values will lead to an exception
353  EptAssert(mAccumulator[m] >= 0,"negative intensities are inconsistent");
354  }
355 }
356 
357 
358 //-----------------------------------------------------------------------------
359 // Modify a spectral component in the accumulator, keeping the norm
360 //-----------------------------------------------------------------------------
361 
363  int pitch)
364 {
365  EptAssert(keynumber>=0 and keynumber<mNumberOfKeys,"Range of parameter key");
366  EptAssert(abs(pitch)<100,"Pitch should be less than a half tone");
367 
368  Key &key = mKeys[keynumber];
369  SpectrumType &spectrum = key.getSpectrum();
370  int recorded_pitch = getRecordedPitchET440AsInt(keynumber);
371  int old_pitchdiff = mPitch[keynumber] - recorded_pitch;
372  int new_pitchdiff = pitch - recorded_pitch;
373 
374  addToAccumulator(spectrum,old_pitchdiff,-1);
375  addToAccumulator(spectrum,new_pitchdiff,1);
376  mPitch[keynumber] = pitch;
377 }
378 
379 
380 //-----------------------------------------------------------------------------
381 // Set all spectral components
382 //-----------------------------------------------------------------------------
383 
385 {
386  mAccumulator.assign(NumberOfBins,0);
387  for (int k=0; k<mNumberOfKeys; ++k)
388  {
389  Key &key = mKeys[k];
390  SpectrumType spectrum = key.getSpectrum();
391  int recorded_pitch = getRecordedPitchET440AsInt(k);
392  int pitchdiff = mPitch[k] - recorded_pitch;
393 
394  addToAccumulator(spectrum,pitchdiff,1);
395  }
396 }
397 
398 //-----------------------------------------------------------------------------
399 // Compute initial condition of the tuning curve
400 //-----------------------------------------------------------------------------
401 
419 
421 {
422  clear();
423  double progress = 0;
424 
425  // For the computation we need at least two octaves to both sides of A4:
426  if (mKeyNumberOfA4<=13 or mNumberOfKeys-mKeyNumberOfA4<=13) return;
427 
428  // Return the measured (and extrapolated) inharmonicity B:
429  auto B = [this] (int keynumber)
430  { return mKeys[keynumber].getMeasuredInharmonicity(); };
431 
432  // Compute the expected stretch deviation of the n_th partial of a given key:
433  auto cents = [B] (int keynumber, int n)
434  { return 600.0 / MathTools::LOG2 * log((1+n*n*B(keynumber))/(1+B(keynumber))); };
435 
436  // Helper function to set a new tuning curve value
437  auto setValue = [this,&progress](int k, double value)
438  {
439  msleep(20);
440  mInitialPitch[k] = value;
441  mPitch[k] = MathTools::roundToInteger(value);
443  progress += 1.0 / mNumberOfKeys;
444  showCalculationProgress(progress);
445  };
446 
447  // Define a linear section of the curve in the middle
448  int numberA3 = mKeyNumberOfA4-12;
449  int numberA4 = mKeyNumberOfA4;
450  int numberA5 = mKeyNumberOfA4+12;
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);
455 
456  // Extend curve to the right by iteration:
457  for (int k=numberA5+1; k<mNumberOfKeys; k++)
458  {
459  double pitch42 = mInitialPitch[k-12] + cents(k-12,4) -cents(k,2);
460  double pitch21 = mInitialPitch[k-12] + cents(k-12,2);
461  setValue(k,0.3*pitch42 + 0.7*pitch21);
462  }
463 
464  // Extend the curve to the left by iteration:
465  for (int k=numberA3-1; k>=0; k--)
466  {
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));
471  }
472 }
473 
474 
475 //-----------------------------------------------------------------------------
476 // Define a heuristic function for the allowed tolerance during Monte Carlo
477 //-----------------------------------------------------------------------------
478 
487 
489 {
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;
495 
496  auto f = [toleranceA4] (double a, double b, double k)
497  { return toleranceA4 + a*k*k + b*k*k*k; };
498 
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;
503  int dkey = keynumber - mKeyNumberOfA4;
504  return MathTools::roundToInteger(dkey<0 ? f(a1,b1,dkey) : f(a2,b2,dkey));
505 
506 }
507 
508 //-----------------------------------------------------------------------------
509 // Compute the entropy of the current accumulator content
510 //-----------------------------------------------------------------------------
511 
516 
518 {
519  SpectrumType copy(mAccumulator); // get a local copy of the accumulator
520  MathTools::normalize(copy); // normalize it
521  return MathTools::computeEntropy(copy); // return Shannon entropy
522 }
523 
524 //-----------------------------------------------------------------------------
525 // Entropy minimization (the very center of the EPT)
526 //-----------------------------------------------------------------------------
527 
544 
546 {
547  int cents=20; // even number which defines the width of the fluctuations
548 
549  // Create random device for probabilistic seeding:
550  std::random_device rd;
551  // Initialze Mersenne twister with random seed:
552  static std::mt19937 generator(rd());
553  // Define distributions to be used:
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);
557 
558  // copy initial condition to the actual pitch
559  for (int k=0; k<mNumberOfKeys; k++)
562 
564 
565  // compute initial entropy
566  double H = computeEntropy();
567  LogI("STARTING WITH ENTROPY H=%lf.",H);
568 
569  // counter for calculating progress
570  uint64_t attemptsCounter = 0;
571  uint64_t updatesSinceLastChange = 0;
572 
573  // helper function for accepting an update and handling the progress bar
574  auto acceptUpdate = [&H,&attemptsCounter,&updatesSinceLastChange,this] (int keynumber, double Hnew)
575  {
576  // update entropy and tuning curve
577  H = Hnew;
578  LogI("ENTROPY H=%lf.",H);
579  if (keynumber>=0) updateTuningcurve(keynumber);
580  else updateTuningcurve();
581 
582  // 'reset' updates
583  updatesSinceLastChange /= 2;
584 
585  //output for testing
586  //writeAccumulator("0-accumulator.dat");
587  //writeSpectrum(4,"tuned",mPitch[4]-getRecordedPitchET440AsInt(4));
588  //writeSpectrum(16,"tuned",mPitch[16]-getRecordedPitchET440AsInt(16));
589  //writeSpectrum(28,"tuned",mPitch[28]-getRecordedPitchET440AsInt(28));
590  };
591 
592  double methodRatio = 1;
593  double lastProgress = 0;
594  double pbAcc = 0;
595  double pbVel = 0;
596 
597  // accuracy (duration) of algorithm
598  int stepsToFinish = 100;
599  std::string accuracy = mFactoryDescription.getStringParameter("accuracy");
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());}
605 
606 
607  LogV("Accuracy is %s, using %d as max steps.", accuracy.c_str(), stepsToFinish);
608 
609  // if infinite reset calculation progress
610  if (stepsToFinish < 0) showCalculationProgress(0);
611 
612  // Main thread loop in which the computation is carried out
613  while (not terminateThread())
614  {
615  ++attemptsCounter;
616  ++updatesSinceLastChange;
617 
618  // update progress
619  if (stepsToFinish > 0)
620  {
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;
628  showCalculationProgress (progress);
629  if (attemptsCounter % 100 == 0) {
630  LogV("Progress: %f", progress);
631  }
632 
633  // if progress larger than 1 stop the calculation
634  if (progress > 1) break;
635  }
636 
637  // If external manual change of tuning curve reset entropy
639  {
641  LogI("NEW PITCH(%d) = %d.",mRecalculateKey,manualpitch);
643  H = computeEntropy();
644  LogI("RESET ENTROPY H = %lf.",H);
645  mRecalculateEntropy=false;
646  mRecalculateKey=-1;
648  }
649 
650  // ********************************************************************
651  // ************** Core of the whole entropy piano tuner: **************
652  // ********************************************************************
653 
654  // Select a random key which is different from A4
655  int keynumber;
656  do keynumber = keydist(generator); while (keynumber==mKeyNumberOfA4);
657 
658 
659  if (probdist(generator)>methodRatio)
660  // (a) Monte-Carlo step by changing the pitch of an individual key
661  {
662  int oldpitch = mPitch[keynumber];
663  double initialpitch = mInitialPitch[keynumber];
664  double tolerance = getTolerance(keynumber);
665  int newpitch;
666  do newpitch = oldpitch + binomial(generator)-cents/2;
667  while (((fabs(oldpitch-initialpitch) < tolerance and
668  fabs(newpitch-initialpitch) > tolerance)
669  or newpitch == oldpitch)
670  and not terminateThread());
671  modifySpectralComponent(keynumber,newpitch);
672  double Hnew = computeEntropy();
673  // If new entropy is lower accept the update, otherwise restore old situation
674  if (Hnew < H) acceptUpdate (keynumber,Hnew);
675  else modifySpectralComponent(keynumber,oldpitch);
676  }
677 
678 
679  else
680  // (b) perform a Monte Carlo trial in which a whole section is moved by +/- 1.
681  {
682  std::vector<int> savePitch(mPitch);
683  int sign = (probdist(generator)<0.5 ? 1:-1);
684  if (keynumber < mKeyNumberOfA4)
685  {
686  for (int k=0; k<=keynumber; ++k) mPitch[k]+=sign;
687  }
688  else
689  {
690  for (int k=keynumber; k<mNumberOfKeys; ++k) mPitch[k]+=sign;
691  }
693  double Hnew = computeEntropy();
694  // If new entropy is lower accept the update, otherwise restore old situation
695  if (Hnew < H)
696  {
697  acceptUpdate (-1,Hnew);
698  methodRatio *= 0.995;
699  }
700  else
701  {
702  mPitch = savePitch;
704  }
705  }
706  }
707 #if CONFIG_ENABLE_XMGRACE
708  for (int k=0; k < mNumberOfKeys; ++k) writeSpectrum(k,"middle",mPitch[k]-getRecordedPitchET440(k));
709 #endif // CONFIG_ENABLE_XMGRACE
710 
711 }
712 
713 
714 
715 //-----------------------------------------------------------------------------
716 // compute recorded pitch against ET 440
717 //-----------------------------------------------------------------------------
718 
723 
725 {
726  double ET440 = 440.0 * pow(2,1.0/12.0*(keynumber-mKeyNumberOfA4));
727  double frec = mKeys[keynumber].getRecordedFrequency();
728  return 1200*log(frec/ET440)/MathTools::LOG2;
729 }
730 
732 {
734 }
735 
736 
737 //-----------------------------------------------------------------------------
738 // get computed pitch against ET 440
739 //-----------------------------------------------------------------------------
740 
746 
747 int EntropyMinimizer::getPitchET440(int keynumber, double f)
748 {
749  double ET440 = 440.0 * pow(2,1.0/12.0*(keynumber-mKeyNumberOfA4));
750  return MathTools::roundToInteger(1200*log(f/ET440)/MathTools::LOG2);
751 }
752 
753 
754 
755 //-----------------------------------------------------------------------------
756 // Write function for development purposes
757 //-----------------------------------------------------------------------------
758 
759 void EntropyMinimizer::writeAccumulator(std::string filename)
760 {
761 #if CONFIG_ENABLE_XMGRACE
762  std::ofstream os (filename);
763  for (int m=0; m<NumberOfBins; ++m)
764  {
765  os << Key::IndexToFrequency(m) << "\t" << mAccumulator[m] << std::endl;
766  }
767  os.close();
768 #else
769  (void)filename; // suppress warnings
770 #endif // CONFIG_ENABLE_XMGRACE
771 }
772 
773 //-----------------------------------------------------------------------------
774 // Write function for development purposes
775 //-----------------------------------------------------------------------------
776 
777 void EntropyMinimizer::writeSpectrum (int k,std::string filename, int pitch)
778 {
779 #if CONFIG_ENABLE_XMGRACE
780  std::stringstream ss;
781  ss << "spectrum/" << k << "-"<< filename << ".dat";
782  std::ofstream os(ss.str());
783  auto v = mPiano.getKey(k).getSpectrum();
784  os << "# pitch= " << pitch << std::endl;
785  for (uint m=abs(pitch); m<v.size()-abs(pitch); ++m)
786  {
787  if (v.size() != static_cast<size_t>(NumberOfBins)) os << m+pitch << "\t" << v[m] << std::endl;
788  else os << Key::IndexToFrequency(m+pitch) << "\t" << v[m] << std::endl;
789  }
790  os.close();
791 #else
792  (void)filename; (void)k; (void)pitch; // suppress warnings
793 #endif // CONFIG_ENABLE_XMGRACE
794 }
795 
796 
797 } // namespace entropy minimizer
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.
Definition: message.h:98
SpectrumType mAccumulator
Accumulator holding the sum of all spectra.
const double LOG2
Definition: mathtools.h:39
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.
#define LogV(...)
Definition: log.h:38
bool mRecalculateEntropy
Flag for entropy recalculation (after manual intervention by the user)
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.
Definition: piano.cpp:148
bool terminateThread()
Definition: algorithm.h:51
Class describing a single piano key.
Definition: key.h:45
void initializeSPLAFilter()
Initialize the filter function in the vector mdBA.
void algorithmWorkerFunction() overridefinal
Main calculation, running in an independent thread.
int roundToInteger(T x)
Round a floating point number to an integer.
Definition: mathtools.h:43
Definition: piano.h:40
Keyboard & mKeyboard
Reference to the keyboard.
Definition: algorithm.h:66
void addToAccumulator(SpectrumType &spectrum, int shift, double intensity)
Add or subtract a spectrum to the accumulator.
double getEqualTempFrequency(int keynumber, double cents=0, double A4=0) const
Function returning the equal temperament.
Definition: piano.cpp:123
int mUpperCutoff
Upper cutoff for fluctuations.
static double IndexToFrequency(double m)
Convert continuous slot index to frequency in Hz.
Definition: key.cpp:102
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.
Definition: algorithm.h:69
static double ftom(double f)
Convert frequency to array index in cent spacing.
double computeEntropy(const std::vector< double > &v)
Compute the Shannon entropy of a normalized probability distribution.
Definition: mathtools.cpp:56
void convertToSPLA(SpectrumType &s)
Compute A-weighted sound pressure level SPLA.
const AlgorithmFactoryDescription & mFactoryDescription
Definition: algorithm.h:63
#define LogI(...)
Definition: log.h:50
Namespace for all entropy minimizer components.
void normalize(std::vector< double > &vec)
Normalize a distribution stored in a vector.
Definition: mathtools.cpp:92
static const AlgorithmFactory mSingleton
void showCalculationProgress(double fraction)
Transmit the current percentage of progress to the messaging system.
Definition: algorithm.cpp:79
void updateTuningcurve()
Update the entire tuning curve.
int getPitchET440(int keynumber, double f)
Get pitch from frequ.
#define LogE(...)
Definition: log.h:62
Message that the tuning curve has been adapted.
Definition: message.h:60
void updateTuningCurve(int keynumber, double frequency)
Definition: algorithm.cpp:60
bool checkDataConsistency()
Check consistency of the piano dataset.
Keys & mKeys
Reference to the keys.
Definition: algorithm.h:67
void modifySpectralComponent(int key, int pitch)
The Algorithm class is a basic abstract class for any algorithm.
Definition: algorithm.h:38
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.
Definition: key.cpp:237
#define EptAssert(a, b)
Definition: eptexception.h:47
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.
Definition: algorithm.h:62
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
Definition: piano.h:86
const int mNumberOfKeys
The number of keys.
Definition: algorithm.h:68