ASPiK SDK
Loading...
Searching...
No Matches
Design the Custom View Objects

With the custom view names set in the GUI designer, we can turn our attention to the custom view objects. We have two view objects that we'll discuss first and then we'll look at the custom knob view. All of these controls and their associated structures are contained in the customviews.h and customviews.cpp files that come standard with all ASPiK projects. You are free to use and modify the objects as you like. Since all of the code is available and open-source we won't spend a lot of time on the details here - you are encouraged to use the Forum at the ASPiK website to ask more questions and get help.

The custom view objects must be derived from CView at the minimum, though we often use the CControl instead. Because you are designing the view as well as writing the mechanism for passing the ICustomView pointer to the plugin shell, you can implement the interface however you wish. In our example here we will simply derive the custom view from ICustomView (along with CControl) but you could implement this differently if you would like. The WaveView object declaration is shown here. For this document, we will only be discussing the mechanism for communicating with the custom view. Refer to Designing Audio Effects Plugins in C++ 2nd Ed. for details on the view operations. The important stuff is shown in below, consisting of the two ICustomView overrides plus the inclusion of the lock-free ring buffer. Note how the ring-buffer is declared - it will store a queue of double data values; DATA_QUEUE_LEN is defined at the top of the file and is set to 1024 - you can adjust the size as you like.

class WaveView : public CControl, public ICustomView
{
public:
WaveView(const CRect& size, IControlListener* listener, int32_t tag);
~WaveView();
// --- ICustomView
virtual void updateView() override;
virtual void pushDataValue(double data) override;
// --- snipped out code... //
private:
// --- lock-free queue for incoming data, sized to DATA_QUEUE_LEN in length
};
//
Custom View interface to allow plugin core to create safe communication channels with GUI custom view...
Definition: pluginstructures.h:1462
virtual void updateView()=0
virtual void pushDataValue(double data)
Definition: pluginstructures.h:1472
Definition: readerwriterqueue.h:60

The implementation of the object may be found in customviews.cpp. It uses a circular buffer to store data that will be printed into the waveform view. The circular buffer indexing is what causes the data to move from the left to the right across the screen. The circular buffer is exactly the same length as the view is wide (in pixels) so each slot in the buffer corresponds to one column of pixels in the view. The object works as follows:

• the plugin pushes audio data into the custom view, which buffers it in the lock-free ring buffer
• the plugin will push some number of samples into the view during one GUI timer ping call; this represents all of the audio data that was acquired during the previous 50 mSec timer interval
• after the plugin empties its data into the view, it calls the updateView( ) method to repaint the custom view
in the updateView( ) method, the object sorts through the last chunk of samples to find the one with the maximum value - that sample is then added to the circular buffer; afterwards the view invalidates itself, forcing the repaint

So, the WaveView object actually paints the maximum value that occurred during each 50 mSec timer interval. The circular buffer holds the samples to be painted; the lock free ring buffer acts as the incoming data buffer that isolates the circular buffer’s data which is the part used for painting.

Let’s look at the two ICustomView methods, starting with pushDataValue( ) which simply pushes the next double value into the queue.

void WaveView::pushDataValue(double data)
{
if(!dataQueue) return;
// --- add data point, make room if needed
DataQueue->enqueue(data);
}
//

The updateView( ) method sorts the buffer for the maximum value and dequeues the information. Notice the loop that empties the queue (try_dequeue( )) while also finding the maximum value. The addWaveDataPoint( ) function adds the max value into the circular buffer. The rest of the object handles the drawing of the data into the view and is discussed in Designing Audio Effects Plugins in C++ 2nd Ed. so it will not be detailed again here.

void WaveView::updateView()
{
// --- get the max value that was added to the queue during the last
// GUI timer ping interval
double audioSample = 0.0;
double max = 0.0;
bool success = dataQueue->try_dequeue(audioSample);
if(success)
{
max = audioSample;
while(success)
{
success = dataQueue->try_dequeue(audioSample);
if(success && audioSample > max)
max = audioSample;
}
// --- add to circular buffer
addWaveDataPoint(fabs(max));
}
// --- this will set the dirty flag to repaint the view
invalid();
}
//