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
plotsdialog.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 #include "plotsdialog.h"
21 #include <cmath>
22 #include <QVBoxLayout>
23 #include <QHBoxLayout>
24 #include <QLabel>
25 #include <QSettings>
26 #include <QToolBar>
27 #include <QToolButton>
28 #include <QDialogButtonBox>
30 #include "qtconfig.h"
31 #include "displaysize.h"
32 #include "qwt_plot.h"
33 #include "qwt_plot_picker.h"
34 #include "qwt_plot_marker.h"
35 #include <qwt_plot_curve.h>
36 #include <qwt_plot_grid.h>
37 #include <qwt_symbol.h>
38 #include <qwt_legend.h>
39 #include <qwt_plot_panner.h>
40 #include <qwt_plot_magnifier.h>
41 #include <qwt_plot_zoomer.h>
42 #include "keyindexscaleengine.h"
43 #include "keyindexscaledraw.h"
44 
45 PlotsDialog::PlotsDialog(const Piano &piano, QWidget *parent) :
46  QDialog(parent, Qt::Window),
47  mPiano(piano),
48  mKeyboard(piano.getKeyboard())
49 {
50  std::fill(mCurves.begin(), mCurves.end(), nullptr);
51  const bool vNav(DisplaySizeDefines::getSingleton()->showPlotNavigationVertical());
52 
54 
55  QVBoxLayout *mainLayout = new QVBoxLayout;
56  mainLayout->setMargin(0);
57  setLayout(mainLayout);
58 
59  QLayout *plotLayout = mainLayout;
60 
61  QToolBar *toolBar = new QToolBar;
62  int iconSize = DisplaySizeDefines::getSingleton()->getMediumIconSize();
63  toolBar->setIconSize(QSize(iconSize, iconSize));
64  mainLayout->addWidget(toolBar);
65 
66  QHBoxLayout *barLayout = new QHBoxLayout;
67  barLayout->setMargin(0);
68  mainLayout->addLayout(barLayout);
69 
70  QToolBar *navBar = toolBar;
71  if (vNav) {
72  navBar = new QToolBar;
73  navBar->setIconSize(QSize(iconSize, iconSize));
74  navBar->setOrientation(Qt::Vertical);
75 
76  QHBoxLayout *vTbExtraLayout = new QHBoxLayout;
77  vTbExtraLayout->setMargin(0);
78  mainLayout->addLayout(vTbExtraLayout);
79  vTbExtraLayout->addWidget(navBar);
80 
81  plotLayout = vTbExtraLayout;
82  }
83 
84  auto makeColorIcon = [](QColor c) {
85  int size = DisplaySizeDefines::getSingleton()->getSmallIconSize() / 2;
86  QPixmap p(size, size);
87  p.fill(c);
88  return QIcon(p);
89  };
90 
91  auto makeToolButton = [&toolBar, &makeColorIcon, this](QColor c, QString title, Curves curve) {
92  PlotToolButton *b = new PlotToolButton(curve);
93  toolBar->addWidget(b);
94  b->setFocusPolicy(Qt::NoFocus);
95  b->setCheckable(true);
96  b->setIcon(makeColorIcon(c));
97  b->setText(title);
98  b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
99  QObject::connect(b, SIGNAL(toggled(bool)), this, SLOT(plotToolButtonToggled(bool)));
100 
101  this->mPlotToolButtons[curve] = b;
102 
103  return b;
104  };
105 
106  navBar->addAction(QIcon(":/media/icons/view-fullscreen.png"), tr("Reset view"), plot, SLOT(resetView()));
107  navBar->addAction(QIcon(":/media/icons/go-first.png"), tr("Go first"), plot, SLOT(zoomGoFirst()));
108  navBar->addAction(QIcon(":/media/icons/go-previous.png"), tr("Go previous"), plot, SLOT(zoomGoPrevious()));
109  navBar->addAction(QIcon(":/media/icons/go-next.png"), tr("Go next"), plot, SLOT(zoomGoNext()));
110  navBar->addAction(QIcon(":/media/icons/go-last.png"), tr("Go last"), plot, SLOT(zoomGoLast()));
111 
112  if (!vNav) {
113  toolBar->addSeparator();
114  }
115  if (DisplaySizeDefines::getSingleton()->abbrevPlotLabels()) {
116  makeToolButton(Qt::darkGreen, tr("Inh."), CURVE_INHARMONICITY);
117  makeToolButton(Qt::red, tr("Rec."), CURVE_RECORDED);
118  makeToolButton(Qt::blue, tr("Comp."), CURVE_COMPUTED);
119  makeToolButton(Qt::green, tr("Tun."), CURVE_TUNED);
120  } else {
121  makeToolButton(Qt::darkGreen, tr("Inharmonicity"), CURVE_INHARMONICITY);
122  makeToolButton(Qt::red, tr("Recorded"), CURVE_RECORDED);
123  makeToolButton(Qt::blue, tr("Computed"), CURVE_COMPUTED);
124  makeToolButton(Qt::green, tr("Tuned"), CURVE_TUNED);
125  }
126 
127  toolBar->addSeparator();
128 
129  QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
130  toolBar->addWidget(buttonBox);
131  QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
132 
133 
134  mPlot = plot;
135  plot->setCanvasBackground( Qt::white );
136  // plot->insertLegend( new QwtLegend() );
137  plot->setAxisTitle(QwtPlot::xBottom, tr("Key index"));
138  plot->resetView();
139 
140  QwtPlotGrid *grid = new QwtPlotGrid();
141  grid->setMinorPen(Qt::darkGray, 1);
142  grid->setMajorPen(Qt::black, 1);
143  grid->enableXMin(true);
144  grid->attach( plot );
145  grid->setZ(-200);
146 
147  QwtPlotMarker *marker = new QwtPlotMarker;
148  marker->setLinePen(Qt::black, 2);
149  marker->setLineStyle(QwtPlotMarker::HLine);
150  marker->setYValue(0);
151  marker->attach(plot);
152  marker->setZ(-100);
153 
154  plotLayout->addWidget(plot);
155 
156  for (int i = 0; i < CURVE_COUNT; i++) {
157  prepareCurve(static_cast<Curves>(i));
158  }
159 
160  //QwtPlotPicker *pickers = new QwtPlotPicker(plot->canvas());
161  //pickers->setTrackerMode(QwtPlotPicker::AlwaysOn);
162 
163  QObject::connect(mPlot, SIGNAL(keyWidthChanged(double)), this, SLOT(updateTickWidth(double)));
164 
165  // show last shown charts
166  QSettings s;
167  for (int i = 0; i < CURVE_COUNT; i++) {
168  bool defaultShown = i == CURVE_RECORDED || i == CURVE_COMPUTED;
169  mPlotToolButtons[i]->setChecked(s.value(QString("plots/curve%1").arg(i), defaultShown).toBool());
170  }
171 
172 #if CONFIG_DIALOG_SIZE == 1
173  // load stored geometry
174  restoreGeometry(s.value("plots/geometry").toByteArray());
175  setWindowState(static_cast<Qt::WindowState>(s.value("plots/windowState").toInt()));
176 #else
177  SHOW_DIALOG(this);
178 #endif
179 
180  mPlot->updateAxes();
181 }
182 
184  // store shown curves
185  QSettings s;
186  for (int i = 0; i < CURVE_COUNT; ++i) {
187  s.setValue(QString("plots/curve%1").arg(i), mCurves[i]->isVisible());
188  }
189 
190 #if CONFIG_DIALOG_SIZE == 1
191  // load stored geometry
192  s.setValue("plots/geometry", saveGeometry());
193  s.setValue("plots/windowState", (int)windowState());
194 #endif
195 
196  for (auto *curve : mCurves) {
197  if (curve) {delete curve;}
198  }
199 
200 }
201 
203  for (QwtPlotCurve *c : mCurves) {
204  if (c) {
205  QwtSymbol *s = const_cast<QwtSymbol*>(c->symbol());
206  if (s) {
207  s->setSize(QSize(d, 1));
208  }
209  }
210  }
211 }
212 
214 {
215  return 48 - mKeyboard.getKeyNumberOfA4();
216 }
217 
219  if (mCurves[curve]) {delete mCurves[curve];}
220 
221  QwtPlotCurve *c = mCurves[curve] = new QwtPlotCurve;
222 
223  auto cents = [] (double ratio) { return 1200.0 * log(ratio)/log(2); };
224 
225  if (curve == CURVE_INHARMONICITY) {
226  c->setStyle(QwtPlotCurve::NoCurve);
227  c->setSymbol(new QwtSymbol(QwtSymbol::HLine, QBrush(), QPen(Qt::darkGreen, 2), QSize(mPlot->currentTickDistanceInPixel(), 1)));
228 
229 
230  QPolygonF points;
231  for (int i = 0; i < mKeyboard.getNumberOfKeys(); ++i) {
232  if (mKeyboard[i].getMeasuredInharmonicity() > 0) {
233  points << QPointF(i + 0.5 + getKeyOffset(), mKeyboard[i].getMeasuredInharmonicity());
234  }
235  }
236  c->setSamples( points );
237  } else if (curve == CURVE_RECORDED) {
238  c->setStyle(QwtPlotCurve::NoCurve);
239  c->setSymbol(new QwtSymbol(QwtSymbol::HLine, QBrush(), QPen(Qt::red, 2), QSize(mPlot->currentTickDistanceInPixel(), 1)));
240 
241  QPolygonF points;
242  for (int i = 0; i < mKeyboard.getNumberOfKeys(); ++i) {
243  points << QPointF(i + 0.5 + getKeyOffset(), cents(mKeyboard[i].getRecordedFrequency() / mPiano.getEqualTempFrequency(i)));
244  }
245  c->setSamples(points);
246  } else if (curve == CURVE_COMPUTED) {
247  c->setStyle(QwtPlotCurve::NoCurve);
248  c->setSymbol(new QwtSymbol(QwtSymbol::HLine, QBrush(), QPen(Qt::blue, 2), QSize(mPlot->currentTickDistanceInPixel(), 1)));
249 
250  QPolygonF points;
251  for (int i = 0; i < mKeyboard.getNumberOfKeys(); ++i) {
252  points << QPointF(i + 0.5 + getKeyOffset(), cents(mKeyboard[i].getComputedFrequency() / mPiano.getEqualTempFrequency(i,0,440)));
253  }
254  c->setSamples(points);
255  } else if (curve == CURVE_TUNED) {
256  c->setStyle(QwtPlotCurve::NoCurve);
257  c->setSymbol(new QwtSymbol(QwtSymbol::HLine, QBrush(), QPen(Qt::green, 2), QSize(mPlot->currentTickDistanceInPixel(), 1)));
258 
259  QPolygonF points;
260  for (int i = 0; i < mKeyboard.getNumberOfKeys(); ++i) {
261  points << QPointF(i + 0.5 + getKeyOffset(), cents(mKeyboard[i].getTunedFrequency() / mPiano.getEqualTempFrequency(i)));
262  }
263  c->setSamples(points);
264  }
265 
266 
267  c->attach(mPlot);
268  c->hide();
269 }
270 
272  const PlotToolButton *tb = qobject_cast<const PlotToolButton*>(sender());
273  EptAssert(tb, "ToolButton has to be PlotToolButton type");
274 
275  const Curves curve = tb->getCurve();
276 
277  if (b) {
278  mCurves[curve]->show();
279  if (curve == CURVE_INHARMONICITY) {
280  mPlotToolButtons[CURVE_RECORDED]->setChecked(false);
281  mPlotToolButtons[CURVE_COMPUTED]->setChecked(false);
282  mPlotToolButtons[CURVE_TUNED]->setChecked(false);
283  mPlot->setAxisTitle(QwtPlot::yLeft, tr("Inharmonicity"));
284  mPlot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine);
285  } else {
286  mPlotToolButtons[CURVE_INHARMONICITY]->setChecked(false);
287  mPlot->setAxisTitle(QwtPlot::yLeft, tr("Frequency deviation [cent]"));
288  mPlot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
289  }
290  } else {
291  mCurves[curve]->hide();
292  }
293  mPlot->replot();
294 }
295 
296 
CentralPlotFrame * mPlot
Definition: plotsdialog.h:59
const Keyboard & mKeyboard
Definition: plotsdialog.h:64
const Piano & mPiano
Definition: plotsdialog.h:63
PlotsDialog(const Piano &piano, QWidget *parent)
Definition: plotsdialog.cpp:45
#define SHOW_DIALOG(d)
Definition: qtconfig.h:41
Definition: piano.h:40
std::array< QwtPlotCurve *, CURVE_COUNT > mCurves
Definition: plotsdialog.h:60
const PlotsDialog::Curves & getCurve() const
Definition: plotsdialog.h:73
double getEqualTempFrequency(int keynumber, double cents=0, double A4=0) const
Function returning the equal temperament.
Definition: piano.cpp:123
virtual ~PlotsDialog()
void prepareCurve(Curves curve)
void updateTickWidth(double d)
int getKeyOffset()
int getKeyNumberOfA4() const
Definition: keyboard.h:73
#define EptAssert(a, b)
Definition: eptexception.h:47
void plotToolButtonToggled(bool)
static const std::unique_ptr< DisplaySizeDefines > & getSingleton()
Definition: displaysize.cpp:29
int getNumberOfKeys() const
Definition: keyboard.h:72
double currentTickDistanceInPixel() const
std::array< PlotToolButton *, CURVE_COUNT > mPlotToolButtons
Definition: plotsdialog.h:61