COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 01-24-2019, 10:02 AM   #1
jan hase
Human being with feelings
 
Join Date: Jul 2017
Posts: 25
Default IPlug2: composition classes

hey there,

id like to create a composition (Parent) class which contains child classes in order to attach a whole set of controls with one Parent Control Class.
Later a Parent Structure should contain many classes and they are all connected together in the parentclass constructor. The Goal is, that when you create a new project, you just include your parentclass of your module and are able to attach it with one line. So you might have a Parentclass EQ which contains everything your EQ Module needs. Later you have modules like EQ, distortion, arpeggiator etc. and you can easily swap them around your projects.
it should be possible for the structure to integrate predefined Iplug Controls and self written controls as well.

here is an example of how i try to achieve it:

Code:
//in plug.h:
ParentClass *PClass;

//in Plug.cpp in mLayoutFunc:
PClass = new ParentClass(this, pGraphics, b, 1, 2);

class ParentClass : public IControl
{
public:
	class ToggleButton;

	ToggleButton *TButton1;
	ToggleButton *TButton2;

	ParentClass(IGEditorDelegate *pPlug, IGraphics *pGraphics, IRECT pRect, int Button1Idx,int Button2Idx)
		: IControl(*pPlug, pRect) {

		TButton1 = new ToggleButton(pPlug, IRECT(pRect.L, pRect.T, pRect.R / 2, pRect.B), Button1Idx);
		TButton2 = new ToggleButton(pPlug, IRECT(pRect.R/2, pRect.T, pRect.R, pRect.B), Button2Idx);
		pGraphics->AttachControl(TButton1);
		pGraphics->AttachControl(TButton2);
	}

	virtual void Draw(IGraphics& Graphics) override {}

///ChildClass Definition

	class ToggleButton : public IControl 
	{
	private:
		IGEditorDelegate *pP;
		IRECT pR;
		bool mState;

	public:
		ToggleButton(IGEditorDelegate* pPlug, IRECT pRect, int paramIdx)
			: IControl(*pPlug, pRect, paramIdx)
		{
			mDblAsSingleClick = true;
			pP = pPlug;			
			pR = pRect;

		}
		virtual void Draw(IGraphics& Graphics) override {

			if (mState && mValue == 0) {mState = false;}
			if (!mState && mValue == 1) {mState = true;}
			if (mState) {Graphics.FillRoundRect(COLOR_BLUE, pR, pR.H()*0.2, 0);}
			else {Graphics.FillRoundRect(COLOR_ORANGE, pR, pR.H()*0.2, 0);}
		}

		void OnMouseDown(float x, float y, const IMouseMod& mod) override
		{
			if (!mState) {mState = true;mValue = 1.0;}
			else{mState = false;mValue = 0.0;}
			SetDirty();
		}

		bool GetState() {
			return mState;
		}
	};
};
Description:

i created a class ToggleButton. This class can be used on its own directly from mLayoutFunc. In this case ToggleButton is defined within the Parentclass ParentClass ,so its code is as close by as possible.
Then two ToggleButtons are attached in the ParentClass Constructor.

So far so good. The Problem(s):

this example works - except for when a function of its members gets called from within process block before mLayoutFunc has been executed. e.g. PClass->TButton1->GetState();
On Plug Startup processblock gets called before mLayoutFunc. So if there is a Function in the Processblock eg:

if(Grid->SamplePosIsInGrid(1,16) {

PClass->TButton1->GetState();

}

it crashes because, the ParentClass Pointer (PClass) has yet no Adress of a ParentClass.

So my workaround for this was: bypassing everything in processblock until mlayountfunc is finished attaching all controls. but i think thats not very elegant.

in my world having access to pGraphics before processblock gets called, would solve it - but my c++/iplug/dsp knowledge is small and i was told, that this is not the way how to approach the goal.

The hints i got so far are:

its not adviseable to call UI stuff from the audio thread. - i dont understand how to achieve something like, a circle changes color every 1/16th, when not calling the function changecolor from the audiothread, when the samplePos is the right one for 1/16th.

it seems i have a fundamental missunderstanding of how this works, and i have trouble to get my head around it - so id be eternally thankful for help to clear this up a little more :-)
jan hase is offline   Reply With Quote
Old 01-24-2019, 10:10 AM   #2
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by jan hase View Post

So my workaround for this was: bypassing everything in processblock until mlayountfunc is finished attaching all controls. but i think thats not very elegant.
Why bypass everything? Why not just skip accessing the GUI objects if they don't exist yet? (That's a pattern I use in some of my JUCE based plugins, in those one generally can not expect the GUI objects to be around at all while the audio processing is happening.)
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 01-24-2019, 10:28 AM   #3
jan hase
Human being with feelings
 
Join Date: Jul 2017
Posts: 25
Default

whats the difference between skipping and bypassing? if i skip i would have a check like: if (gui is drawn) {access}? if thats what you mean, how would you do it?
jan hase is offline   Reply With Quote
Old 01-24-2019, 10:38 AM   #4
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by jan hase View Post
whats the difference between skipping and bypassing? if i skip i would have a check like: if (gui is drawn) {access}? if thats what you mean, how would you do it?
Sorry, I don't know the specifics how it would work in IPlug(2). In Juce there's a method GetActiveEditor() that returns the currently open GUI object or a null pointer if the GUI isn't available.

In Juce I do something like this in the audio processing method to skip accessing the GUI object if it doesn't currently exist :
Code:
auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor());
if (ed != nullptr)
{
  ed->m_sonogram.addAudioBlock(buffer);
}
But in IPlug it would be something different, maybe you need to implement checking the availability of the GUI yourself.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 01-24-2019, 11:33 AM   #5
jan hase
Human being with feelings
 
Join Date: Jul 2017
Posts: 25
Default

thank you, tried the nullptr thing, thats not working unfortunatly. but i think if i set a variable to true at the end of mlayoutfunc, and then only access the functions if that one is true, its the same result, isnt it?
jan hase is offline   Reply With Quote
Old 01-24-2019, 11:36 AM   #6
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by jan hase View Post
if i set a variable to true at the end of mlayoutfunc, and then only access the functions if that one is true, its the same result, isnt it?
Should be, but remember to initialize that variable to false first. C++ does not initialize your variables to false, zeros or null pointers by default.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 02:48 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.