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 = 2;
289 const unsigned int MESSAGE_QUERY_CONTROL = 3;
290 
291 // --- example of a custom view message; here we control the visual appearance of a control
303 struct CustomViewMessage
304 {
305  CustomViewMessage() {}
306  CustomViewMessage(const CustomViewMessage& initMessage)
307  {
308  message = initMessage.message;
309  visible = initMessage.visible;
310  showAlternateGraphic = initMessage.showAlternateGraphic;
311  controlAlpha = initMessage.controlAlpha;
312  queryString = initMessage.queryString;
313  replyString = initMessage.replyString;
314  messageData = initMessage.messageData;
315  }
316 
317  CustomViewMessage& operator =(const CustomViewMessage& viewMessage)
318  {
319  message = viewMessage.message;
320  visible = viewMessage.visible;
321  showAlternateGraphic = viewMessage.showAlternateGraphic;
322  controlAlpha = viewMessage.controlAlpha;
323  queryString = viewMessage.queryString;
324  replyString = viewMessage.replyString;
325  messageData = viewMessage.messageData;
326  return *this;
327  }
328 
329  // --- show/hide flag
330  unsigned int message = MESSAGE_HIDE_CONTROL;
331 
332  bool visible = true;
333  bool showAlternateGraphic = false;
334  double controlAlpha = 1.0; // transparency: 0 = invisible (100% transparent) and 1 = solidly visible (0% transparent)
335  std::string queryString;
336  std::string replyString;
337  void* messageData = nullptr;
338 };
339 
352 class CustomKnobView : public CAnimKnob, public ICustomView
353 {
354 public:
355  CustomKnobView(const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
356  CCoord heightOfOneImage, CBitmap* background, const CPoint &offset,
357  bool bSwitchKnob = false);
358 
360  virtual void updateView() override;
361 
363  virtual void sendMessage(void* data) override;
364 
365 protected:
366  virtual ~CustomKnobView(void);
367 
368 private:
369  // --- lock-free queue for incoming data, sized to 32 in length
371 };
372 
373 
408 class KnobLinkController : public IController
409 {
410 public:
414  KnobLinkController(IController* _parentController)
415  {
416  // --- save the parent listener
417  parentController = _parentController;
418 
419  // --- INITIALIZE LINK STATE
420  linkControls = false;
421  }
423  {
424  linkedKnobs.clear();
425  }
426 
431  bool isLinkedControl(CControl* control)
432  {
433  return std::find(linkedKnobs.begin(), linkedKnobs.end(), control) != linkedKnobs.end();
434  }
435 
443  virtual CView* verifyView(CView* view, const UIAttributes& attributes, const IUIDescription* description) override
444  {
445  CAnimKnob* knob = dynamic_cast<CAnimKnob*>(view);
446  CTextButton* button = dynamic_cast<CTextButton*>(view);
447 
448  // --- save button, push back knob onto list
449  if (button)
450  {
451  linkControl = button;
452  if (button->getValueNormalized() != 0)
453  linkControls = true;
454  else
455  linkControls = false;
456  }
457  else if (knob)
458  linkedKnobs.push_back(knob);
459 
460  return view;
461  }
462 
467  virtual void valueChanged(CControl* control) override
468  {
469  // --- set the link flag
470  if (control == linkControl)
471  {
472  if (control->getValueNormalized() != 0)
473  linkControls = true;
474  else
475  linkControls = false;
476 
477  return parentController->valueChanged(control);
478  }
479 
480  // --- check flag
481  if (!linkControls)
482  return parentController->valueChanged(control);
483 
484  // --- we are linking
485  //
486  // --- make sure this is not a rogue control
487  if (isLinkedControl(control))
488  {
489  // --- iterate list
490  for (std::vector<CAnimKnob*>::iterator it = linkedKnobs.begin(); it != linkedKnobs.end(); ++it)
491  {
492  // --- set the control value for all knobs except the one generating this message
493  CControl* ctrl = *it;
494 
495  if (ctrl && control != ctrl)
496  {
497  // --- set the control visually
498  ctrl->setValueNormalized(control->getValueNormalized());
499 
500  // --- do the value change at parent level, to set on plugin
501  parentController->valueChanged(ctrl);
502 
503  ctrl->invalid();
504  }
505  }
506  }
507  // --- do the value change at parent level, to set on plugin
508  parentController->valueChanged(control);
509  }
510 
516  virtual CView* createView(const UIAttributes& attributes, const IUIDescription* description) override { return parentController->createView(attributes, description); }
517 
521  virtual void controlBeginEdit(CControl* pControl)override { parentController->controlBeginEdit(pControl); }
522 
526  virtual void controlEndEdit(CControl* pControl)override { parentController->controlEndEdit(pControl); }
527 
532  virtual void controlTagWillChange(CControl* pControl) override
533  {
534  pControl->setListener(parentController);
535  parentController->controlTagWillChange(pControl);
536  pControl->setListener(this);
537  }
538 
543  virtual void controlTagDidChange(CControl* pControl) override
544  {
545  pControl->setListener(parentController);
546  parentController->controlTagDidChange(pControl);
547  pControl->setListener(this);
548  }
549 
550 protected:
551  // --- the parent controller; we can issue IController commands to it!
552  IController* parentController = nullptr;
553 
554  // --- a CTextButton is the switcher (linkControl)
555  CTextButton* linkControl = nullptr;
556 
557  // --- when linked, all of these controls move when one of them moves,
558  // regardless of their control tags
559  typedef std::vector<CAnimKnob*> KnobList;
560  KnobList linkedKnobs;
561 
562  // --- flag for linking knobs
563  bool linkControls = false;
564 };
565 
566 
567 
568 }
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