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
stroboscopicviewadapterforqt.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 // Graphics implementation of the stroboscope for Qt
22 //=============================================================================
23 
25 
26 #include <QGraphicsPixmapItem>
27 
28 #include "../core/math/mathtools.h"
29 #include "../core/system/eptexception.h"
30 
31 //-----------------------------------------------------------------------------
32 // Constructor
33 //-----------------------------------------------------------------------------
34 
44 
46  DrawerBase *drawer,
47  QRectF sceneRect) :
48  GraphicsViewAdapterForQt(parent,drawer,sceneRect),
49  mStroboscopeItem(nullptr)
50 {
51 }
52 
53 
54 //-----------------------------------------------------------------------------
55 // Destructor
56 //-----------------------------------------------------------------------------
57 
61 
63 {
64  if (mStroboscopeItem)
65  {
66  delete mStroboscopeItem;
67  mStroboscopeItem = nullptr;
68  }
69 }
70 
71 
72 //-----------------------------------------------------------------------------
73 // Clear view
74 //-----------------------------------------------------------------------------
75 
79 
81 {
83  // calling clear of the base class already deletes mStroboscopeItem
84  // Therefore, we do not have a delete here.
85  mStroboscopeItem = nullptr;
86 }
87 
88 
89 //-----------------------------------------------------------------------------
90 // Draw the stroboscope
91 //-----------------------------------------------------------------------------
92 
103 
105 {
106  // if no stroboscope exists we clear the scene and create it
107  if (not mStroboscopeItem)
108  {
109  clear();
110  mStroboscopeItem = new QGraphicsPixmapItem;
111  mScene.addItem(mStroboscopeItem);
112  }
113 
114  // get the pixel size of the scene. This is not identical with the
115  // actual pixel size shown on the screen (it is typically 200x200)
116  qreal W = mSceneRect.width();
117  qreal H = mSceneRect.height();
118 
119  // Create an image of the same size
120  QImage image (W, H, QImage::Format_RGB32);
121 
122  // loop over all vector entries (partials)
123  const int N = data.size();
124  if (N>0)
125  {
126  // First derive the graphical information from the complex numbers
127  std::vector<double> phase(N),saturation(N), value(N);
128  for (int n=0; n<N; n++)
129  {
130  phase[n] = std::arg(data[n])/MathTools::TWO_PI + 0.5;
131  saturation[n] = pow(std::min(1.0,25.0/N*std::abs(data[n])*(n+1)),0.3);
132  value[n] = saturation[n];
133  }
134 
135  // Then for each partial generate a sequence of rgb values.
136  // These values are stored in a NxW matrix organized as a vector:
137  std::vector<uint32_t> rgbColors(N*W);
138  QColor color;
139  const int xMargin = W/100;
140 
141  // For keys with 4 partials and more the first partial covers
142  // the phase 2pi over the whole display. For very high keys
143  // the wave number is increased to 4pi, 6pi etc
144  const double wavenumber = std::max(1,5-N);
145 
146  // Before drawing the colors are computed
147  for (int n=0; n<N; n++) for (int x=0; x<W; x++)
148  {
149  // The margins are black
150  if (x<xMargin or x>=W-xMargin) rgbColors[W*n+x]=0;
151  else // otherwise they are set to a phase-shifted rainbow
152  {
153  double xc = (wavenumber*x/W*(n+1)+phase[n]);
154  double hue = xc - floor(xc);
155  // This function generates a rainbow-like color scale:
156  color.setHsvF(hue,saturation[n],value[n],1);
157  rgbColors[W*n+x] = static_cast<uint32_t>(color.rgb());
158  }
159  }
160 
161  // Depending on the number of the partials N, these color vectors
162  // are now copied into several strips of a certain stripWidth.
163  // Since this is time-critical this is done via memcpy.
164  // Black margins are added using memset.
165  int yMargin = H/20;
166  int stripWidth = (H-2*yMargin)/N;
167  int actualMargin = (H-N*stripWidth)/2;
168  int upperBound = N*stripWidth+actualMargin;
169 
170  // Main drawing loop
171  for (int y=0; y<H; ++y)
172  {
173  auto line = image.scanLine(H-1-y);
174  if (y>=actualMargin and y<upperBound)
175  {
176  int n = (y-actualMargin)/stripWidth;
177  memcpy(line,&rgbColors[W*n],W*4);
178  }
179  else memset(line,0,W*4);
180  }
181  }
182  else image.fill(0); // if N=0 return black rectangle
183 
184  // Convert the image to a pixmap:
185  QPixmap pixmap(W,H);
186  pixmap.convertFromImage(image);
187 
188  // Copy the pixmap to the stroboscope item.
189  // This method is much faster than adding a new object
190  // to the scene over and over again.
191  if (mStroboscopeItem) mStroboscopeItem->setPixmap(pixmap);
192 }
Implementation of the GraphicsViewAdapter in Qt using QGraphicsView.
~StroboscopicViewAdapterForQt()
Destructor, deleting the stroboscope if existent.
QGraphicsScene mScene
The QGraphicsScene.
StroboscopicViewAdapterForQt(QWidget *parent, DrawerBase *drawer, QRectF sceneRect)
Constructor with no stroboscope in the beginning.
virtual void clear() override
Clear the scene.
void clear() overridefinal
Clear view of stroboscope and spectral indicator.
std::vector< std::complex< double >> ComplexVector
Abstract function: Draw stroboscope.
virtual void drawStroboscope(const ComplexVector &data) overridefinal
StroboscopicViewAdapterForQt::drawStroboscope.
QGraphicsPixmapItem * mStroboscopeItem
Pointer to the stroboscope.
QRectF mSceneRect
The scene rect.
const double TWO_PI
Definition: mathtools.h:38
Abstract base class for drawing 2d graphics.
Definition: drawerbase.h:40