ASPiK SDK
customviews.h
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 // ASPiK Custom Views File: customviews.h
3 //
14 // -----------------------------------------------------------------------------
15 #pragma once
16 #include "vstgui/vstgui.h"
17 #include "vstgui/vstgui_uidescription.h" // for IController
18 
19 #include "../PluginKernel/pluginstructures.h"
20 
21 namespace VSTGUI {
22 
23 // --- with an update cycle of ~50mSec, we need at least 2205 samples; this should be more than enough
24 const int DATA_QUEUE_LEN = 4096;
25 
45 class WaveView : public CControl, public ICustomView
46 {
47 public:
48  WaveView(const CRect& size, IControlListener* listener, int32_t tag);
49  ~WaveView();
50 
52  virtual void updateView() override;
53 
55  virtual void pushDataValue(double data) override;
56 
60  void addWaveDataPoint(float fSample);
61 
64  void clearBuffer();
65 
69  void showXAxis(bool _paintXAxis) { paintXAxis = _paintXAxis; }
70 
74  void draw(CDrawContext* pContext) override;
75 
76  // --- for CControl pure abstract functions
77  CLASS_METHODS(WaveView, CControl)
78 
79 protected:
80  // --- turn on/off zerodB line
81  bool paintXAxis = true;
82 
83  // --- circular buffer and index values
84  double* circularBuffer = nullptr;
85  int writeIndex = 0;
86  int readIndex = 0;
88  CRect currentRect;
89 
90 private:
91  // --- lock-free queue for incoming data, sized to DATA_QUEUE_LEN in length
93 
94 };
95 
96 #define HAVE_FFTW 1
97 
98 #ifdef HAVE_FFTW
99 // --- FFTW (REQUIRED)
100 #include "fftw3.h"
101 
115 enum class spectrumViewWindowType {kRectWindow, kHannWindow, kBlackmanHarrisWindow};
116 
117 // --- change this for higher accuracy; needs to be power of 2
118 const int FFT_LEN = 512;
119 
120 // --- SpectrumView
121 /*
122 */
146 class SpectrumView : public CControl, public ICustomView
147 {
148 public:
149  SpectrumView(const CRect& size, IControlListener* listener, int32_t tag);
150  ~SpectrumView();
151 
153  virtual void updateView() override;
154 
156  virtual void pushDataValue(double data) override;
157 
159  void showFilledFFT(bool _filledFFT) { filledFFT = _filledFFT; }
160 
164  void setWindow(spectrumViewWindowType _window);
165 
167  void draw(CDrawContext* pContext) override;
168 
169  // --- for CControl pure abstract functions
170  CLASS_METHODS(SpectrumView, CControl)
171 
172 protected:
173  // --- for windowing; this doesn't need to be saved in current
174  // implementation but you may need it for homework/upgrading the object
175  spectrumViewWindowType window = spectrumViewWindowType::kRectWindow;
176 
177  // --- setup FFTW
178  fftw_complex* data = nullptr;
179  fftw_complex* fft_result = nullptr;
180  fftw_complex* ifft_result = nullptr;
181  fftw_plan plan_forward;
182  fftw_plan plan_backward;
183 
184  // --- for FFT data input
185  int fftInputCounter = 0;
186 
191  bool addFFTInputData(double inputSample);
192 
193  // --- a double buffer pair of magnitude arrays
194  double fftMagnitudeArray_A[FFT_LEN] = {0.0};
195  double fftMagnitudeArray_B[FFT_LEN] = {0.0};
196 
197  // --- buffer for the assigned window
198  double fftWindow[FFT_LEN] = {1.0};
199 
200  // --- pointer to mag buffer that drawing thread uses; note that
201  // this pointer is never shared with any other function
202  double* currentFFTMagBuffer = nullptr;
203 
204  // --- NOTE: move these to another file for use by other objects!!
205  // --- helper for FFT magnitude
206  inline double getMagnitude(double re, double im)
207  {
208  return sqrt((re*re)+(im*im));
209  }
210 
216  inline double normalizeBufferGetFMax(double* buffer, unsigned int bufferSize, int* ptrMaxIndex)
217  {
218  double max = 0;
219  double maxRetValue = 0;
220  *ptrMaxIndex = 0;
221 
222  for(int j=0; j<bufferSize; j++)
223  {
224  if((fabs(buffer[j])) > max)
225  {
226  max = fabs(buffer[j]);
227  *ptrMaxIndex = j;
228  }
229  }
230 
231  if(max > 0)
232  {
233  for(int j=0; j<bufferSize; j++)
234  {
235  buffer[j] = buffer[j]/max;
236  if(j == *ptrMaxIndex)
237  maxRetValue = buffer[j];
238  }
239  }
240 
241  return maxRetValue;
242  }
243 
249  inline double interpArrayValue(double* array, int arraySize, double fractionalIndex)
250  {
251  // --- extract [index_x] values
252  int x1 = (int)fractionalIndex;
253  int x2 = x1 + 1;
254 
255  // --- check invalid conditions
256  if(x1 >= arraySize)
257  return 0.0;
258  if(x2 >= arraySize)
259  return array[x1];
260  if(x2 - x1 == 0) // 0 slope: should not ever happen
261  return array[x1];
262 
263  // --- calculate decimal position of x
264  double dx = (fractionalIndex - x1)/(x2 - x1);
265 
266  // --- use weighted sum method of interpolating
267  return dx*array[x2] + (1-dx)*array[x1];
268  }
269 
270 protected:
271  // --- filled/unfilled FFT
272  bool filledFFT = true;
273 
274 private:
275  // --- lock-free queue for incoming data, sized to FFT_LEN in length
276  moodycamel::ReaderWriterQueue<double,FFT_LEN>* dataQueue = nullptr;
277 
278  // --- a pair of lock-free queues to store empty and full magnitude buffers
279  // these are setup as double buffers but you can easily extend them
280  // to quad (4) and octal (8) if you want
281  moodycamel::ReaderWriterQueue<double*,2>* fftMagBuffersReady = nullptr;
282  moodycamel::ReaderWriterQueue<double*,2>* fftMagBuffersEmpty = nullptr;
283 };
284 #endif // defined FFTW
285 
286 
287 // --- custom view example
288 const unsigned int MESSAGE_SHOW_CONTROL = 0;
289 const unsigned int MESSAGE_HIDE_CONTROL = 1;
290 const unsigned int MESSAGE_SET_CONTROL_ALPHA = 1;
291 
292 // --- example of a custom view message; here we control the visual appearance of a control
305 {
306  CustomViewMessage() {}
307  CustomViewMessage(const CustomViewMessage& initMessage)
308  {
309  visible = initMessage.visible;
311  controlAlpha = initMessage.controlAlpha;
312  }
313 
314  CustomViewMessage& operator =(const CustomViewMessage& viewMessage)
315  {
316  visible = viewMessage.visible;
318  controlAlpha = viewMessage.controlAlpha;
319  return *this;
320  }
321 
322  unsigned int message = MESSAGE_HIDE_CONTROL;
323  bool visible = true;
324  bool showAlternateGraphic = false;
325  double controlAlpha = 1.0;
326 };
327 
340 class CustomKnobView : public CAnimKnob, public ICustomView
341 {
342 public:
343  CustomKnobView(const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
344  CCoord heightOfOneImage, CBitmap* background, const CPoint &offset,
345  bool bSwitchKnob = false);
346 
348  virtual void updateView() override;
349 
351  virtual void sendMessage(void* data) override;
352 
353 protected:
354  virtual ~CustomKnobView(void);
355 
356 private:
357  // --- lock-free queue for incoming data, sized to 32 in length
359 };
360 
361 
396 class KnobLinkController : public IController
397 {
398 public:
402  KnobLinkController(IController* _parentController)
403  {
404  // --- save the parent listener
405  parentController = _parentController;
406 
407  // --- INITIALIZE LINK STATE
408  linkControls = false;
409  }
411  {
412  linkedKnobs.clear();
413  }
414 
419  bool isLinkedControl(CControl* control)
420  {
421  return std::find(linkedKnobs.begin(), linkedKnobs.end(), control) != linkedKnobs.end();
422  }
423 
431  virtual CView* verifyView(CView* view, const UIAttributes& attributes, const IUIDescription* description) override
432  {
433  CAnimKnob* knob = dynamic_cast<CAnimKnob*>(view);
434  CTextButton* button = dynamic_cast<CTextButton*>(view);
435 
436  // --- save button, push back knob onto list
437  if (button)
438  {
439  linkControl = button;
440  if (button->getValueNormalized() != 0)
441  linkControls = true;
442  else
443  linkControls = false;
444  }
445  else if (knob)
446  linkedKnobs.push_back(knob);
447 
448  return view;
449  }
450 
455  virtual void valueChanged(CControl* control) override
456  {
457  // --- set the link flag
458  if (control == linkControl)
459  {
460  if (control->getValueNormalized() != 0)
461  linkControls = true;
462  else
463  linkControls = false;
464 
465  return parentController->valueChanged(control);
466  }
467 
468  // --- check flag
469  if (!linkControls)
470  return parentController->valueChanged(control);
471 
472  // --- we are linking
473  //
474  // --- make sure this is not a rogue control
475  if (isLinkedControl(control))
476  {
477  // --- iterate list
478  for (std::vector<CAnimKnob*>::iterator it = linkedKnobs.begin(); it != linkedKnobs.end(); ++it)
479  {
480  // --- set the control value for all knobs except the one generating this message
481  CControl* ctrl = *it;
482 
483  if (ctrl && control != ctrl)
484  {
485  // --- set the control visually
486  ctrl->setValueNormalized(control->getValueNormalized());
487 
488  // --- do the value change at parent level, to set on plugin
489  parentController->valueChanged(ctrl);
490  }
491  }
492  }
493  // --- do the value change at parent level, to set on plugin
494  parentController->valueChanged(control);
495  }
496 
502  virtual CView* createView(const UIAttributes& attributes, const IUIDescription* description) override { return parentController->createView(attributes, description); }
503 
507  virtual void controlBeginEdit(CControl* pControl)override { parentController->controlBeginEdit(pControl); }
508 
512  virtual void controlEndEdit(CControl* pControl)override { parentController->controlEndEdit(pControl); }
513 
518  virtual void controlTagWillChange(CControl* pControl) override
519  {
520  pControl->setListener(parentController);
521  parentController->controlTagWillChange(pControl);
522  pControl->setListener(this);
523  }
524 
529  virtual void controlTagDidChange(CControl* pControl) override
530  {
531  pControl->setListener(parentController);
532  parentController->controlTagDidChange(pControl);
533  pControl->setListener(this);
534  }
535 
536 protected:
537  // --- the parent controller; we can issue IController commands to it!
538  IController* parentController = nullptr;
539 
540  // --- a CTextButton is the switcher (linkControl)
541  CTextButton* linkControl = nullptr;
542 
543  // --- when linked, all of these controls move when one of them moves,
544  // regardless of their control tags
545  typedef std::vector<CAnimKnob*> KnobList;
546  KnobList linkedKnobs;
547 
548  // --- flag for linking knobs
549  bool linkControls = false;
550 };
551 
552 
553 
554 }
spectrumViewWindowType
Use this strongly typed enum to easily set the window type for the spectrum view. ...
Definition: customviews.h:115
This object displays an audio histogram waveform view. .
Definition: customviews.h:45
bool visible
simple show/hide flag
Definition: customviews.h:323
bool paintXAxis
flag for painting X Axis
Definition: customviews.h:81
fftw_plan plan_forward
plan for FFT
Definition: customviews.h:181
void showFilledFFT(bool _filledFFT)
Definition: customviews.h:159
int circularBufferLength
circular buffer length
Definition: customviews.h:87
virtual void updateView() override
Definition: customviews.cpp:62
fftw_complex * ifft_result
ifft output (not used)
Definition: customviews.h:180
void draw(CDrawContext *pContext) override
Definition: customviews.cpp:104
bool addFFTInputData(double inputSample)
Definition: customviews.cpp:250
CRect currentRect
the rect to draw into
Definition: customviews.h:88
CustomKnobView(const CRect &size, IControlListener *listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap *background, const CPoint &offset, bool bSwitchKnob=false)
CustomKnobView constructor.
Definition: customviews.cpp:434
void clearBuffer()
Definition: customviews.cpp:96
virtual void pushDataValue(double data) override
Definition: customviews.cpp:54
void draw(CDrawContext *pContext) override
Definition: customviews.cpp:334
double controlAlpha
transparency: 0 = invisible (100% transparent) and 1 = solidly visible (0% transparent) ...
Definition: customviews.h:325
double interpArrayValue(double *array, int arraySize, double fractionalIndex)
Definition: customviews.h:249
bool filledFFT
flag for filled FFT
Definition: customviews.h:272
virtual void updateView() override
Definition: customviews.cpp:274
Custom View interface to allow plugin core to create safe communication channels with GUI custom view...
Definition: pluginstructures.h:1141
fftw_plan plan_backward
plan for IFFT (not used)
Definition: customviews.h:182
int writeIndex
circular buffer write location
Definition: customviews.h:85
This object demonstrates how to subclass an existing VSTGUI4 control to setup a communcation channel ...
Definition: customviews.h:340
Definition: customcontrols.cpp:20
double * currentFFTMagBuffer
poitner to current FFT buffer
Definition: customviews.h:202
fftw_complex * data
fft input data
Definition: customviews.h:178
virtual void pushDataValue(double data) override
Definition: customviews.cpp:266
double fftMagnitudeArray_B[FFT_LEN]
1/2 of double buffer (yes this is overkill but showing as demonstration!!)
Definition: customviews.h:195
void showXAxis(bool _paintXAxis)
Definition: customviews.h:69
int fftInputCounter
input counter for FFT
Definition: customviews.h:185
void setWindow(spectrumViewWindowType _window)
Definition: customviews.cpp:222
double * circularBuffer
circular buffer to store peak values
Definition: customviews.h:84
virtual void sendMessage(void *data) override
Definition: customviews.cpp:447
WaveView(const CRect &size, IControlListener *listener, int32_t tag)
WaveView constructor.
Definition: customviews.cpp:25
double fftWindow[FFT_LEN]
window buffer
Definition: customviews.h:198
int readIndex
circular buffer read location
Definition: customviews.h:86
double fftMagnitudeArray_A[FFT_LEN]
1/2 of double buffer (yes this is overkill but showing as demonstration!!)
Definition: customviews.h:194
void addWaveDataPoint(float fSample)
Definition: customviews.cpp:87
virtual void updateView() override
Definition: customviews.cpp:455
This object displays the FFT of the incoming data. .
Definition: customviews.h:146
unsigned int message
message to send/receive
Definition: customviews.h:322
double normalizeBufferGetFMax(double *buffer, unsigned int bufferSize, int *ptrMaxIndex)
Definition: customviews.h:216
SpectrumView(const CRect &size, IControlListener *listener, int32_t tag)
SpectrumView constructor.
Definition: customviews.cpp:179
fftw_complex * fft_result
fft output data
Definition: customviews.h:179
spectrumViewWindowType window
window type
Definition: customviews.h:175
bool showAlternateGraphic
flag to show another graphic
Definition: customviews.h:324
Custom structure for passing messages and data to and from the plugin core object. See the Custom View tutorial project for more informaiton.
Definition: customviews.h:304