Envelope visualisation | VSTGUI4 | Forum

Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
Envelope visualisation
Avatar
Member
Members
February 5, 2022 - 5:20 am
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Hi! Could anyone point me in the right direction on what components or technique you would use to draw a line representation of an envelope curve in the gui based on the different time/rate and level parameters? Ive created a web version of my gui and there Ive used the canvas element to easily draw what I need. Is there something similar in vstgui4 and the aspik gui creator?

Avatar
Anglia
Member
Members
February 6, 2022 - 12:00 pm
Member Since: June 2, 2014
Forum Posts: 46
sp_UserOfflineSmall Offline

Love Aurell said
Hi! Could anyone point me in the right direction on what components or technique you would use to draw a line representation of an envelope curve in the gui based on the different time/rate and level parameters? Ive created a web version of my gui and there Ive used the canvas element to easily draw what I need. Is there something similar in vstgui4 and the aspik gui creator?  

This page in the ASPiK SDK presents an example of Custom Views, which has some components which could be adapted to your needs:

http://aspikplugins.com/sdkdoc.....ner11.html

Avatar
Member
Members
February 6, 2022 - 4:19 pm
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Great! Thanks, will look into that.

Avatar
Admin
February 10, 2022 - 6:05 am
Member Since: January 1, 2020
Forum Posts: 107
sp_UserOfflineSmall Offline

Also build the example project that goes with those good docs - WithoutFFTW/DemoCustomViews

It'll need some heavy modifications but has what you need there. To get multiple values through the moodycamel stream without using pointers, I like to multiplex the data by reducing that to a 0-.99 range and then adding to it an integer index value. On receiving the value I use the index to identify it, then subtract it from the value and scale back to whatever. 

Cheers

Avatar
Member
Members
February 11, 2022 - 9:52 am
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

jim said
To get multiple values through the moodycamel stream without using pointers, I like to multiplex the data by reducing that to a 0-.99 range and then adding to it an integer index value. On receiving the value I use the index to identify it, then subtract it from the value and scale back to whatever.

That's a great tip, thanks! 

Avatar
Member
Members
March 2, 2022 - 9:18 am
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

I've now implemented a first version of this, you can see it in action here:

One issue though, is that I want the controls to push values to the data queue only when they have changed (plugin loads, user alters the parameter or preset is selected). I haven't yet found a good way to do so. At the moment do the queue pushing inside the PluginCore::processAudioFrame function, throttling the calls to 60fps using a counter variable.

First I naively put the logic in the PluginCore::guiParameterChanged, but then the values would not push on plugin load or on preset select. Then I tried adding the logic to the plugin initialization as well, but found that the custom view hasn't been initialized yet and was still nullptr.

 

• Does anyone have any good advice on a better way to keep the param values and the custom view in sync?

• Also, is there a way to increase the updating frequency of the ping message or some other way to make the custom view update more often? 50ms interval feels a bit choppy for updating an UI in realtime, since it's only 20 fps.

• In PluginCore::postUpdatePluginParameter, is there any way of checking if the param value has actually changed from the previous call? I looked into the ParameterUpdateInfo struct but found no such flag there. It seems like this function is called each frame for each param regardless if it has changed or not. Is that correct? I guess I could store the previous the value myself and compare, but it would be a neat feature to have built in to the framework.

Avatar
Admin
March 2, 2022 - 11:11 am
Member Since: January 29, 2017
Forum Posts: 693
sp_UserOfflineSmall Offline

Right now, there is no "dirty" flag for the parameters. The fundamental reason for this is -- the AU plugin API.

In the AU process loop, there is no way to know if the AU parameter has changed as it has no dirty flag or other indication. AAX and VST3 do have this capability and when I wrote the plugin shells for ASPiK, I wanted to have parity across all APIs in the way the GUI parameter changes are processed - if you have my book then you understand that this is more complicated than it sounds, because to ensure thread safety, the parameter updates are actually looped into the host first - they do not come directly from the GUI, but rather via the host DAW that has taken care of the thread synchronization issues. 

That said, it is possible to add a dirty flag that you would set during valueChanged( ) in the GUI object and that would be passed through to the plugin however that will require writing some code in the plugin shells - and it wouldn't work in AU. I have been wanting to add this flag as I am currently working with a system in the real world that has a robust checking of the dirty flag, and I think it would be a good addition to ASPiK. I just haven't had time to do any of this (I still need to fix this website too!). 

The way that other devs have gotten around this issue in AU specifically is to have a parallel set of variables that represent the last known state of the parameter values. On each incoming set of GUI parameters to process, you subtract the current value from the saved value and look at the delta. Because of floating point manipulation, this value will usually never be exactly zero, but some very small number, if the GUI control has not been changed. So the logic is to make the comparison and then branch if the value has changed by some threshold amount. This will definitely add overhead, BUT the way the normal "dirty" flag systems work also requires a subtraction to see if the value has changed, and a branch to set/clear the dirty flag. So, you have to add a few more CPU cycles regardless. 

Will 

Avatar
Member
Members
March 8, 2022 - 3:46 pm
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Thanks Will for the clarification. That makes sense, I can do my own "dirty" checking for just those params then.

What about the second topic, is the refresh rate of the custom views limited to 20fps/50ms or can you get around that somehow, calling the update function more frequently?

Avatar
Admin
March 8, 2022 - 4:09 pm
Member Since: January 29, 2017
Forum Posts: 693
sp_UserOfflineSmall Offline

The GUI refresh timer is set at the end of the open( ) function in PluginGUI.cpp around line 298

if (timer)

{

    timer->setFireTime((uint32_t)GUI_METER_UPDATE_INTERVAL_MSEC);

    timer->start();

}

 

GUI_METER_UPDATE_INTERVAL_MSEC is a constant defined as 50.0 so this is where you can alter the refresh time. 

If you search that file for GUI_METER_UPDATE_INTERVAL_MSEC you will see that it is also used in the VU Meter timing calibration, in order to make the VU meter ballistics (attack and decay times) match the original input values when the GUI control was setup. So, if you are using the CVuMeter object, you need to make an adjustment there so that it matches your timing.

The easiest solution is to simply change the constant definition for GUI_METER_UPDATE_INTERVAL_MSEC.

That I recall, the JUCE GUI refresh timer is something like 10mSec at its fastest but it has been a while since I've had to muck around in that GUI code.

You can make this value as low as 1.0 but the GUI thread may be bogged down with repaint commands. 

The reason that I chose 50mSec was that was what the VST3SDK and VSTGUI4 examples defaulted to. 

Will 

Avatar
Member
Members
March 9, 2022 - 7:53 am
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Thanks! That's exactly what I was looking for, but for some reason I didn't find it. It works great, now I get a lot smoother visual response when changing the params.

Avatar
Admin
March 9, 2022 - 8:42 am
Member Since: January 1, 2020
Forum Posts: 107
sp_UserOfflineSmall Offline

To your first question;

Does anyone have any good advice on a better way to keep the param values and the custom view in sync?

I used to do this from processAudioFrame() as you described then learnt that you can also do the same thing from;

bool PluginCore::processMessage(MessageInfo& messageInfo) {

case PLUGINGUI_TIMERPING: { 

if (isCustomViewDataQueueEnabled()) {

customViewDataQueue.enqueue( Output);  // call this line for each output value;

} }

Avatar
Member
Members
March 10, 2022 - 1:58 pm
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Thanks Jim but I'm not sure I follow. In the custom views examples, the customViewDataQueue is filled with data during the processAudioFrame() calls and emptied during processMessage(MessageInfo& messageInfo), aggregated, and sent to the respective custom view. I understand that pattern.

In your snippet, you call customViewDataQueue.enqueue( Output); instead of customViewDataQueue.dequeue(). What kind of value does "output" hold, and where does it come from? If I understand it correctly, we cannot access the params here, since we're on the GUI thread?

Avatar
Admin
March 15, 2022 - 9:05 am
Member Since: January 1, 2020
Forum Posts: 107
sp_UserOfflineSmall Offline

Sorry for the confusion with the code snippet. 

Output was any random double or float holding whatever value you wanted to send. 

virtual bool processMessage(MessageInfo& messageInfo); is called from and lives in the overriding Plugincore class so any variable that's declared in the Plugincore.h is accessible there.

What I wanted to show with my code snippet was simply that you can eliminate the counter method and achieve better syncing (vector graphics can easily cause significant GUI lag). This is because the PLUGINGUI_TIMERPING case is guaranteed to be called once, and only once every actual GUI frame update.

All you really need to is grab the current if(isCustomViewDataQueueEnabled..){} code from your plugincore audio thread and place that into the plugincore processMessage{ Timer ping switch case. Ignore the if (SpectrumView) { ..} or whatever is already there for now, just paste it in separately at the top.

 

Enqueue pushes a value to the Data Queue. Dequeue assigns that from the DataQueue value to a variable to be read. But pushDataValue() is what is actually sending that value to the GUI shell.

I think there's a very good reason why it's happening in that manner. Relating to thread safety, otherwise I think it would be possible for the GUI and Audio threads to be accessing the same variable at the same time which would be very bad. 

Avatar
Member
Members
March 16, 2022 - 4:33 pm
Member Since: February 5, 2022
Forum Posts: 26
sp_UserOfflineSmall Offline

Ok, thanks, it's a bit clearer now. PLUGINGUI_TIMERPING seems like the perfect place to fetch the values from the params. But I still don't understand the use of customViewDataQueue here. Since the processMessage(MessageInfo& messageInfo) is called from the plugin core, I imagine I can put the param values on the custom view data queue directly, in this case egVisualizer->pushDataValue(value) and then just call egVisualizer->updateview().

Thats also how it's done in the examples.

Forum Timezone: America/New_York

Most Users Ever Online: 152

Currently Online:
4 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Chaes: 56

Skyler: 48

StevieD: 46

Derek: 46

Frodson: 45

Peter: 43

TheSmile: 43

Nickolai: 43

clau_ste: 39

jeanlecode: 37

Member Stats:

Guest Posters: 2

Members: 782

Moderators: 1

Admins: 6

Forum Stats:

Groups: 13

Forums: 42

Topics: 849

Posts: 3370

Moderators: W Pirkle: 693