ASPiK SDK
customviews.h
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;
87  int circularBufferLength = 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 #ifdef HAVE_FFTW
97 // --- FFTW (REQUIRED)
98 #include "fftw3.h"
99 
113 enum class spectrumViewWindowType {kRectWindow, kHannWindow, kBlackmanHarrisWindow};
114 
115 // --- change this for higher accuracy; needs to be power of 2
116 const int FFT_LEN = 512;
117 
118 // --- SpectrumView
119 /*
120 */
144 class SpectrumView : public CControl, public ICustomView
145 {
146 public:
147  SpectrumView(const CRect& size, IControlListener* listener, int32_t tag);
148  ~SpectrumView();
149 
151  virtual void updateView() override;
152 
154  virtual void pushDataValue(double data) override;
155 
157  void showFilledFFT(bool _filledFFT) { filledFFT = _filledFFT; }
158 
162  void setWindow(spectrumViewWindowType _window);
163 
165  void draw(CDrawContext* pContext) override;
166 
167  // --- for CControl pure abstract functions
168  CLASS_METHODS(SpectrumView, CControl)
169 
170 protected:
171  // --- for windowing; this doesn't need to be saved in current
172  // implementation but you may need it for homework/upgrading the object
173  spectrumViewWindowType window = spectrumViewWindowType::kRectWindow;
174 
175  // --- setup FFTW
176  fftw_complex* data = nullptr;
177  fftw_complex* fft_result = nullptr;
178  fftw_complex* ifft_result = nullptr;
179  fftw_plan plan_forward;
180  fftw_plan plan_backward;
181 
182  // --- for FFT data input
183  int fftInputCounter = 0;
184 
189  bool addFFTInputData(double inputSample);
190 
191  // --- a double buffer pair of magnitude arrays
192  double fftMagnitudeArray_A[FFT_LEN] = {0.0};
193  double fftMagnitudeArray_B[FFT_LEN] = {0.0};
194 
195  // --- buffer for the assigned window
196  double fftWindow[FFT_LEN] = {1.0};
197 
198  // --- pointer to mag buffer that drawing thread uses; note that
199  // this pointer is never shared with any other function
200  double* currentFFTMagBuffer = nullptr;
201 
202  // --- NOTE: move these to another file for use by other objects!!
203  // --- helper for FFT magnitude
204  inline double getMagnitude(double re, double im)
205  {
206  return sqrt((re*re)+(im*im));
207  }
208 
214  inline double normalizeBufferGetFMax(double* buffer, unsigned int bufferSize, int* ptrMaxIndex)
215  {
216  double max = 0;
217  double maxRetValue = 0;
218  *ptrMaxIndex = 0;
219 
220  for(int j=0; j<bufferSize; j++)
221  {
222  if((fabs(buffer[j])) > max)
223  {
224  max = fabs(buffer[j]);
225  *ptrMaxIndex = j;
226  }
227  }
228 
229  if(max > 0)
230  {
231  for(int j=0; j<bufferSize; j++)
232  {
233  buffer[j] = buffer[j]/max;
234  if(j == *ptrMaxIndex)
235  maxRetValue = buffer[j];
236  }
237  }
238 
239  return maxRetValue;
240  }
241 
247  inline double interpArrayValue(double* array, int arraySize, double fractionalIndex)
248  {
249  // --- extract [index_x] values
250  int x1 = (int)fractionalIndex;
251  int x2 = x1 + 1;
252 
253  // --- check invalid conditions
254  if(x1 >= arraySize)
255  return 0.0;
256  if(x2 >= arraySize)
257  return array[x1];
258  if(x2 - x1 == 0) // 0 slope: should not ever happen
259  return array[x1];
260 
261  // --- calculate decimal position of x
262  double dx = (fractionalIndex - x1)/(x2 - x1);
263 
264  // --- use weighted sum method of interpolating
265  return dx*array[x2] + (1-dx)*array[x1];
266  }
267 
268 protected:
269  // --- filled/unfilled FFT
270  bool filledFFT = true;
271 
272 private:
273  // --- lock-free queue for incoming data, sized to FFT_LEN in length
274  moodycamel::ReaderWriterQueue<double,FFT_LEN>* dataQueue = nullptr;
275 
276  // --- a pair of lock-free queues to store empty and full magnitude buffers
277  // these are setup as double buffers but you can easily extend them
278  // to quad (4) and octal (8) if you want
279  moodycamel::ReaderWriterQueue<double*,2>* fftMagBuffersReady = nullptr;
280  moodycamel::ReaderWriterQueue<double*,2>* fftMagBuffersEmpty = nullptr;
281 };
282 #endif // defined FFTW
283 
284 
285 // --- custom view example
286 const unsigned int MESSAGE_SHOW_CONTROL = 0;
287 const unsigned int MESSAGE_HIDE_CONTROL = 1;
288 const unsigned int MESSAGE_SET_CONTROL_ALPHA = 1;
289 
290 // --- example of a custom view message; here we control the visual appearance of a control
302 struct CustomViewMessage
303 {
304  CustomViewMessage() {}
305  CustomViewMessage(const CustomViewMessage& initMessage)
306  {
307  visible = initMessage.visible;
308  showAlternateGraphic = initMessage.showAlternateGraphic;
309  controlAlpha = initMessage.controlAlpha;
310  }
311 
312  CustomViewMessage& operator =(const CustomViewMessage& viewMessage)
313  {
314  visible = viewMessage.visible;
315  showAlternateGraphic = viewMessage.showAlternateGraphic;
316  controlAlpha = viewMessage.controlAlpha;
317  return *this;
318  }
319 
320  unsigned int message = MESSAGE_HIDE_CONTROL;
321  bool visible = true;
322  bool showAlternateGraphic = false;
323  double controlAlpha = 1.0;
324 };
325 
338 class CustomKnobView : public CAnimKnob, public ICustomView
339 {
340 public:
341  CustomKnobView(const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
342  CCoord heightOfOneImage, CBitmap* background, const CPoint &offset,
343  bool bSwitchKnob = false);
344 
346  virtual void updateView() override;
347 
349  virtual void sendMessage(void* data) override;
350 
351 protected:
352  virtual ~CustomKnobView(void);
353 
354 private:
355  // --- lock-free queue for incoming data, sized to 32 in length
357 };
358 
359 
394 class KnobLinkController : public IController
395 {
396 public:
400  KnobLinkController(IController* _parentController)
401  {
402  // --- save the parent listener
403  parentController = _parentController;
404 
405  // --- INITIALIZE LINK STATE
406  linkControls = false;
407  }
409  {
410  linkedKnobs.clear();
411  }
412 
417  bool isLinkedControl(CControl* control)
418  {
419  return std::find(linkedKnobs.begin(), linkedKnobs.end(), control) != linkedKnobs.end();
420  }
421 
429  virtual CView* verifyView(CView* view, const UIAttributes& attributes, const IUIDescription* description) override
430  {
431  CAnimKnob* knob = dynamic_cast<CAnimKnob*>(view);
432  CTextButton* button = dynamic_cast<CTextButton*>(view);
433 
434  // --- save button, push back knob onto list
435  if (button)
436  {
437  linkControl = button;
438  if (button->getValueNormalized() != 0)
439  linkControls = true;
440  else
441  linkControls = false;
442  }
443  else if (knob)
444  linkedKnobs.push_back(knob);
445 
446  return view;
447  }
448 
453  virtual void valueChanged(CControl* control) override
454  {
455  // --- set the link flag
456  if (control == linkControl)
457  {
458  if (control->getValueNormalized() != 0)
459  linkControls = true;
460  else
461  linkControls = false;
462 
463  return parentController->valueChanged(control);
464  }
465 
466  // --- check flag
467  if (!linkControls)
468  return parentController->valueChanged(control);
469 
470  // --- we are linking
471  //
472  // --- make sure this is not a rogue control
473  if (isLinkedControl(control))
474  {
475  // --- iterate list
476  for (std::vector<CAnimKnob*>::iterator it = linkedKnobs.begin(); it != linkedKnobs.end(); ++it)
477  {
478  // --- set the control value for all knobs except the one generating this message
479  CControl* ctrl = *it;
480 
481  if (ctrl && control != ctrl)
482  {
483  // --- set the control visually
484  ctrl->setValueNormalized(control->getValueNormalized());
485 
486  // --- do the value change at parent level, to set on plugin
487  parentController->valueChanged(ctrl);
488  }
489  }
490  }
491  // --- do the value change at parent level, to set on plugin
492  parentController->valueChanged(control);
493  }
494 
500  virtual CView* createView(const UIAttributes& attributes, const IUIDescription* description) override { return parentController->createView(attributes, description); }
501 
505  virtual void controlBeginEdit(CControl* pControl)override { parentController->controlBeginEdit(pControl); }
506 
510  virtual void controlEndEdit(CControl* pControl)override { parentController->controlEndEdit(pControl); }
511 
516  virtual void controlTagWillChange(CControl* pControl) override
517  {
518  pControl->setListener(parentController);
519  parentController->controlTagWillChange(pControl);
520  pControl->setListener(this);
521  }
522 
527  virtual void controlTagDidChange(CControl* pControl) override
528  {
529  pControl->setListener(parentController);
530  parentController->controlTagDidChange(pControl);
531  pControl->setListener(this);
532  }
533 
534 protected:
535  // --- the parent controller; we can issue IController commands to it!
536  IController* parentController = nullptr;
537 
538  // --- a CTextButton is the switcher (linkControl)
539  CTextButton* linkControl = nullptr;
540 
541  // --- when linked, all of these controls move when one of them moves,
542  // regardless of their control tags
543  typedef std::vector<CAnimKnob*> KnobList;
544  KnobList linkedKnobs;
545 
546  // --- flag for linking knobs
547  bool linkControls = false;
548 };
549 
550 
551 
552 }
This object displays an audio histogram waveform view. .
Definition: customviews.h:45
bool visible
simple show/hide flag
Definition: customviews.h:332
bool paintXAxis
flag for painting X Axis
Definition: customviews.h:81
int circularBufferLength
circular buffer length
Definition: customviews.h:87
virtual void updateView() override
Definition: customviews.cpp:62
void draw(CDrawContext *pContext) override
Definition: customviews.cpp:104
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
double controlAlpha
transparency: 0 = invisible (100% transparent) and 1 = solidly visible (0% transparent) ...
Definition: customviews.h:334
double * circularBuffer
circular buffer to store peak values
Definition: customviews.h:84
Custom View interface to allow plugin core to create safe communication channels with GUI custom view...
Definition: pluginstructures.h:1395
int writeIndex
circular buffer write location
Definition: customviews.h:85
Definition: customcontrols.cpp:20
void showXAxis(bool _paintXAxis)
Definition: customviews.h:69
double getMagnitude(double re, double im)
calculates magnitude of a complex numb er
Definition: fxobjects.h:1004
virtual void sendMessage(void *data) override
Definition: customviews.cpp:447
int readIndex
circular buffer read location
Definition: customviews.h:86
void addWaveDataPoint(float fSample)
Definition: customviews.cpp:87
virtual void updateView() override
Definition: customviews.cpp:465
unsigned int message
message to send/receive
Definition: customviews.h:330
bool showAlternateGraphic
flag to show another graphic
Definition: customviews.h:333