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
pitchraise.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 // Pitch raise algorithm
22 //=============================================================================
23 
24 #include "pitchraise.h"
25 
26 #include "core/math/mathtools.h"
30 
31 //=============================================================================
32 // Create algorithm factory
33 //=============================================================================
34 
35 template<>
37  AlgorithmFactoryDescription("pitchraise"));
38 
39 namespace pitchraise
40 {
41 
42 //-----------------------------------------------------------------------------
43 // Constructor
44 //-----------------------------------------------------------------------------
45 
52 
54  Algorithm(piano, description),
55  mPitch(piano.getKeyboard().getNumberOfKeys(),0)
56 {
57 }
58 
59 
60 //-----------------------------------------------------------------------------
61 // Update the displayed tuning curve
62 //-----------------------------------------------------------------------------
63 
72 
73 void PitchRaise::updateTuningcurve (int keynumber)
74 {
75  EptAssert (keynumber>=0 and keynumber<mNumberOfKeys,"Range of keynumber");
76  double f = mPiano.getDefiningTempFrequency(keynumber, mPitch[keynumber],440);
77  updateTuningCurve(keynumber, f);
78 }
79 
80 
88 
90 {
91  for (int keynumber = 0; keynumber < mNumberOfKeys; ++keynumber)
92  updateTuningcurve(keynumber);
93 }
94 
95 //-----------------------------------------------------------------------------
96 // Worker function
97 //-----------------------------------------------------------------------------
98 
117 {
118  LogI("Pitch Raise algorithm started");
119  // linear regression data
120  std::vector<double> X(2,0),Y(2,0),XX(2,0),XY(2,0),A(2,0),B(2,0);
121  std::vector<int> N(2,0);
122 
123  // make tuning curve initially flat
125 
126  for (int i = 0; i < mNumberOfKeys; ++i)
127  {
129  Key &key = mPiano.getKey(i);
130  showCalculationProgress(i*0.25/mNumberOfKeys);
131  msleep(5);
132  if (key.getMeasuredInharmonicity()>1E-10)
133  {
134  double B = key.getMeasuredInharmonicity();
135  int s = (i < mPiano.getKeyboard().getNumberOfBassKeys() ? 0 : 1);
136  if (s==0) LogI("Found recorded key number %d in the left section with B=%lf.",i,B)
137  else LogI("Found recorded key number %d in the right section with B=%lf.",i,B);
138  double x = i, y = -log(B);
139  N[s]++;
140  X[s] += x;
141  Y[s] += y;
142  XX[s] += x*x;
143  XY[s] += x*y;
144  }
145  }
146  if (N[0]<2)
147  {
148  // Error: Not enough recorded keys in the left section
149  MessageHandler::send<MessageCaluclationProgress>
152  return;
153  }
154  if (N[1]<2)
155  {
156  // Error: Not enough recorded keys in the right section
157  MessageHandler::send<MessageCaluclationProgress>
160  return;
161  }
162 
163  // Perform linear regression (see https://de.wikipedia.org/wiki/Lineare_Regression)
164  for (int s=0; s<2; ++s)
165  {
166  A[s] = (XX[s]*Y[s] -X[s]*XY[s]) / (N[s]*XX[s] - X[s]*X[s]);
167  B[s] = (N[s]*XY[s] - X[s]*Y[s]) / (N[s]*XX[s] - X[s]*X[s]);
168  }
169 
170  // Define lambda regression function
171  auto estimatedInharmonicity = [this,A,B] (int k)
172  {
173  int s = (k < mPiano.getKeyboard().getNumberOfBassKeys() ? 0 : 1);
174  double minusLogB = A[s] + k*B[s];
175  return exp(-minusLogB);
176  };
177 
178  // For the computation we need at least two octaves to both sides of A4:
179  if (mKeyNumberOfA4<=13 or mNumberOfKeys-mKeyNumberOfA4<=13) return;
180 
181  // Compute the expected stretch deviation of the n_th partial of a given key:
182  auto cents = [estimatedInharmonicity] (int keynumber, int n)
183  { return 600.0 / MathTools::LOG2 *
184  log((1+n*n*estimatedInharmonicity(keynumber)) /
185  (1+estimatedInharmonicity(keynumber))); };
186 
187  // Define a linear section of the curve in the middle
188  int numberA3 = mKeyNumberOfA4-12;
189  int numberA4 = mKeyNumberOfA4;
190  int numberA5 = mKeyNumberOfA4+12;
191  double pitchA5 = 0.5*cents(numberA4,3)+0.5*cents(numberA4,2);
192  double pitchA3 = cents(numberA4,2)-cents(numberA3,4);
193  for (int k=numberA3; k<mKeyNumberOfA4; ++k)
194  {
196  mPitch[k] = pitchA3*(mKeyNumberOfA4-k)/12.0;
197  showCalculationProgress(0.25+(k-numberA3)*0.125/12);
199  msleep(30);
200 
201  }
202  for (int k=mKeyNumberOfA4+1; k<=numberA5; ++k)
203  {
205  mPitch[k] = pitchA5*(k-mKeyNumberOfA4)/12.0;
206  showCalculationProgress(0.375+(k-mKeyNumberOfA4)*0.125/12);
208  msleep(30);
209  }
210 
211  // Extend curve to the right by iteration:
212  for (int k=numberA5+1; k<mNumberOfKeys; k++)
213  {
215  double pitch42 = mPitch[k-12] + cents(k-12,4) -cents(k,2);
216  double pitch21 = mPitch[k-12] + cents(k-12,2);
217  mPitch[k] = 0.3*pitch42 + 0.7*pitch21;
219  showCalculationProgress(0.5+(k-numberA5)*0.25/(mNumberOfKeys-numberA5));
220  msleep(30);
221  }
222 
223  // Extend the curve to the left by iteration:
224  for (int k=numberA3-1; k>=0; k--)
225  {
227  double pitch42 = mPitch[k+12] + cents(k+12,2) -cents(k,4);
228  double pitch105 = mPitch[k+12] + cents(k+12,5) -cents(k,10);
229  double fraction = 1.0*k/numberA3;
230  mPitch[k] = pitch42*fraction+pitch105*(1-fraction);
232  msleep(30);
233  showCalculationProgress(0.75+(numberA3-k)*0.25/(numberA3));
234  }
235 }
236 
237 
238 
239 } // namespace pitchraise
const double LOG2
Definition: mathtools.h:39
The AlgorithmFactory class is a template class to be created with the actual Algorithm.
PitchRaise(const Piano &piano, const AlgorithmFactoryDescription &description)
Constructor of the pitch-raise algorithm.
Definition: pitchraise.cpp:53
void updateTuningcurve()
Update the entire tuning curve.
Definition: pitchraise.cpp:89
#define CHECK_CANCEL_THREAD
void msleep(double milliseconds)
Sleep function for staying idle.
double getDefiningTempFrequency(int keynumber, double cents=0, double A4=0) const
Compute the defining temperatent.
Definition: piano.cpp:148
virtual void algorithmWorkerFunction() overridefinal
PitchRaise::algorithmWorkerFunction.
Definition: pitchraise.cpp:116
Class describing a single piano key.
Definition: key.h:45
Definition: piano.h:40
std::vector< double > mPitch
Definition: pitchraise.h:52
int getNumberOfBassKeys() const
Definition: keyboard.h:75
const Keyboard & getKeyboard() const
Definition: piano.h:83
const int mKeyNumberOfA4
Number of A4.
Definition: algorithm.h:69
double getMeasuredInharmonicity() const
Get estimated inharmonicity.
Definition: key.cpp:141
#define LogI(...)
Definition: log.h:50
static const AlgorithmFactory mSingleton
void showCalculationProgress(double fraction)
Transmit the current percentage of progress to the messaging system.
Definition: algorithm.cpp:79
void updateTuningCurve(int keynumber, double frequency)
Definition: algorithm.cpp:60
The Algorithm class is a basic abstract class for any algorithm.
Definition: algorithm.h:38
#define EptAssert(a, b)
Definition: eptexception.h:47
Piano mPiano
Copy of the piano.
Definition: algorithm.h:62
const Key & getKey(int i) const
Definition: piano.h:86
const int mNumberOfKeys
The number of keys.
Definition: algorithm.h:68