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
fourierspectrumgraphdrawer.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 // Drawer for drawing the spectrum with the peak markers
22 //=============================================================================
23 
25 
26 #include "../messages/messagenewfftcalculated.h"
27 #include "../messages/messagefinalkey.h"
28 #include "../messages/messageprojectfile.h"
29 #include "../messages/messagemodechanged.h"
30 #include "../math/mathtools.h"
31 
32 
33 //-----------------------------------------------------------------------------
34 // Constructor
35 //-----------------------------------------------------------------------------
36 
41 
43  : DrawerBase(graphics, updateInterval),
44  mConcertPitch(0),
45  mKeyNumberOfA4(0),
46  mNumberOfKeys(-1),
47  mSamplingRate(0),
48  mCurrentOperationMode(MODE_IDLE)
49 {
50 }
51 
52 
53 //-----------------------------------------------------------------------------
54 // Draw the spectrum
55 //-----------------------------------------------------------------------------
56 
63 
65 {
66  // draw gray vertical background grid
67  for (int i = 0; i <= mNumberOfKeys; i++)
68  {
69  double x = static_cast<double>(i)/mNumberOfKeys;
71  }
72 
73  // update (draw) the spectrum
75 }
76 
77 
78 //-----------------------------------------------------------------------------
79 // Update the spectrum
80 //-----------------------------------------------------------------------------
81 
91 
93 {
94  // delete old peaks and chart
95  // ==========================================================================
96 
98  if (item)
99  {
100  delete item;
101  item = nullptr;
102  }
103 
105  for (GraphicsItem *peakItem : peakItems)
106  {
107  delete peakItem;
108  }
109 
110  // draw new peaks and chart
111  // ==========================================================================
112 
113 
114  // check if data is available, otherwise quit
115  if (not mPolygon) return;
116 
117  // lambda function mapping the frequency to an x-coodinate in [0,1]:
118  const double a = (mKeyNumberOfA4+0.5)/mNumberOfKeys;
119  const double b = 12.0 / mNumberOfKeys / MathTools::LOG2;
120  auto xposition = [a,b,this] (double f) { return a + b*log(f/mConcertPitch); };
121 
122 
123  // MARK PEAKS AS THIN BLUE DOTS IN THE BACKGROUND (mKey needed)
124 
125  const double exponent = 0.3; // magnify low power spectral lines nonlinearly
126 
128  {
129  Key::PeakListType peaks = mKey->getPeaks();
130  for (auto p : peaks)
131  {
132  double x = xposition(p.first);
133 
134  // Search for the corresponding peaks in the polygon:
135  auto pos1 = mPolygon->begin();
136  while (pos1!=mPolygon->end() and pos1->first < p.first*0.995) pos1++;
137  auto pos2 = pos1;
138  while (pos2!=mPolygon->end() and pos2->first < p.first*1.005) pos2++;
139  auto comp = [] (const std::pair<double,double> &a, const std::pair<double,double> &b)
140  { return a.second < b.second; };
141  auto maxelem = std::max_element(pos1,pos2, comp);
142  if (maxelem != mPolygon->end())
143  {
144  double y = 1-0.95*pow(maxelem->second, exponent);
145  const double dx=0.003;
146  const double dy=0.02;
147  item = mGraphics->drawFilledRect(x-dx/2,y-dy/2,dx,dy,
150  if (item) item->setItemRole(ROLE_PEAK);
151  }
152  }
153  }
154 
155  // DRAW SPECTRUM
156 
157  std::vector<GraphicsViewAdapter::Point> points;
158  EptAssert(mConcertPitch > 0,"concert pitch should be positive");
159  EptAssert(mNumberOfKeys > 0,"invalid number of keys");
160 
161  for (auto &p : *mPolygon)
162  {
163  double x=xposition(p.first);
164  if (x>=0 and x<=1) points.push_back({x, 1-0.95*pow(p.second,exponent)});
165  }
167  if (item) item->setItemRole(ROLE_CHART);
168 }
169 
170 
171 //-----------------------------------------------------------------------------
172 // Clear the spectrum
173 //-----------------------------------------------------------------------------
174 
176 
178 { DrawerBase::clear(); }
179 
180 
181 //-----------------------------------------------------------------------------
182 // Message handler
183 //-----------------------------------------------------------------------------
184 
189 
191 {
192  switch (m->getType())
193  {
195  {
196  // Update local parameter
197  auto mpf(std::static_pointer_cast<MessageProjectFile>(m));
198  mConcertPitch = mpf->getPiano().getConcertPitch();
199  mNumberOfKeys = mpf->getPiano().getKeyboard().getNumberOfKeys();
200  mKeyNumberOfA4 = mpf->getPiano().getKeyboard().getKeyNumberOfA4();
201  mPolygon.reset();
202  redraw(true);
203  break;
204  }
206  {
207  // Update operation mode
208  auto mmc(std::static_pointer_cast<MessageModeChanged>(m));
209  mCurrentOperationMode = mmc->getMode();
210  break;
211  }
213  {
214  // Update mPolygon
215  auto mnfc(std::static_pointer_cast<MessageNewFFTCalculated>(m));
216  if (mnfc->hasError())
217  {
218  mPolygon.reset();
219  }
220  else
221  {
222  mPolygon = mnfc->getPolygon();
223  mSamplingRate = mnfc->getData()->samplingRate;
224  }
225  // Reset mKey
226  mKey.reset();
227  // Plot curve
228  if (requestRedraw(mnfc->isFinal())) updateSpectrum();
229  break;
230  }
232  // Clear everything, cancel spectrum
233  mPolygon.reset();
234  mKey.reset();
235  redraw(true);
236  break;
238  redraw();
239  break;
241  {
242  // Update mKey
243  auto mnfc(std::static_pointer_cast<MessageFinalKey>(m));
244  mKey = mnfc->getFinalKey();
245  if (requestRedraw(true)) updateSpectrum();
246  break;
247  }
248  default:
249  break;
250  }
251 }
252 
sent by SignalAnalyzer if FFT is ready
Definition: message.h:66
virtual GraphicsItem * drawChart(const std::vector< Point > &points, PenType pen=PEN_THIN_BLACK)=0
Abstract function: Draw a chart (polygon).
std::shared_ptr< Message > MessagePtr
Global type of a shared message pointer.
Definition: message.h:98
const double LOG2
Definition: mathtools.h:39
called when the recording was cleared
Definition: message.h:50
GraphicsViewAdapter * mGraphics
Pointer to the graphics view adapter.
Definition: drawerbase.h:53
OperationMode mCurrentOperationMode
Current mode of operation.
void setItemRole(RoleType role)
Setter function for mRole.
Definition: graphicsitem.h:104
int mNumberOfKeys
Total number of keys.
virtual void handleMessage(MessagePtr m) override
Message dispatcher for FourierSpectrumGraphDrawer.
Message that a change was made with the current project file.
Definition: message.h:68
bool requestRedraw(bool force=false)
Check whether the content has to be redrawn.
Definition: drawerbase.cpp:81
int mSamplingRate
copy of sample rate
Message that the operation mode has changed.
Definition: message.h:65
void updateSpectrum()
Function for updating the red curve showing the spectrum.
std::list< GraphicsItem * > GraphicItemsList
A list of GraphicItem (global)
Definition: graphicsitem.h:148
Mode for recording the piano keys.
Definition: prerequisites.h:69
void redraw(bool force=false)
Function to completely redraw the scene.
Definition: drawerbase.cpp:57
virtual void draw() overridefinal
Draw the spectrum.
virtual GraphicsItem * drawFilledRect(double x, double y, double w, double h, PenType pen=PEN_THIN_BLACK, FillTypes fill=FILL_RED)=0
Abstract function: Draw a filled rectangle.
double mConcertPitch
Target freuqency of A4.
virtual void clear()
Clear the whole view.
Definition: drawerbase.h:51
GraphicItemsList getGraphicItemsByRole(RoleType role)
Get a list of graphic items that match with the given role.
Message that progress of any kind was made by the calculator.
Definition: message.h:59
std::shared_ptr< Key > mKey
Shared pointer to selected key, holding the peaks.
final key information after recording
Definition: message.h:55
Abstract base class for implementations rendering graphics.
std::shared_ptr< FFTPolygon > mPolygon
Shared pointer to spectral polygon.
#define EptAssert(a, b)
Definition: eptexception.h:47
Class for a single item in a graphics view.
Definition: graphicsitem.h:55
virtual GraphicsItem * drawLine(double x1, double y1, double x2, double y2, PenType pen=PEN_THIN_BLACK)=0
Abstract function: Draw a line.
GraphicsItem * getGraphicItemByRole(RoleType role)
Get the first of all graphics elements with a given role.
virtual void clear() overridefinal
Clear the spectrum.
Do nothing.
Definition: prerequisites.h:68
std::map< double, double > PeakListType
Type for a peak map.
Definition: key.h:55
FourierSpectrumGraphDrawer(GraphicsViewAdapter *graphics)
Constructor of a FourierSpectrumGraphDrawer.
Abstract base class for drawing 2d graphics.
Definition: drawerbase.h:40