1 //-----------------------------------------------------------------------------
2 // Project     : VST SDK
3 //
4 // Category    : Examples
5 // Filename    : public.sdk/samples/vst/hostchecker/source/hostchecker.cpp
6 // Created by  : Steinberg, 04/2012
7 // Description :
8 //
9 //-----------------------------------------------------------------------------
10 // LICENSE
11 // (c) 2018, Steinberg Media Technologies GmbH, All Rights Reserved
12 //-----------------------------------------------------------------------------
13 // Redistribution and use in source and binary forms, with or without modification,
14 // are permitted provided that the following conditions are met:
15 //
16 //   * Redistributions of source code must retain the above copyright notice,
17 //     this list of conditions and the following disclaimer.
18 //   * Redistributions in binary form must reproduce the above copyright notice,
19 //     this list of conditions and the following disclaimer in the documentation
20 //     and/or other materials provided with the distribution.
21 //   * Neither the name of the Steinberg Media Technologies nor the names of its
22 //     contributors may be used to endorse or promote products derived from this
23 //     software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 // OF THE POSSIBILITY OF SUCH DAMAGE.
35 //-----------------------------------------------------------------------------
36 
37 #include "hostcheckercontroller.h"
38 #include "eventlogdatabrowsersource.h"
39 
40 #include "public.sdk/source/vst/vstcomponentbase.h"
41 #include "public.sdk/source/vst/vstrepresentation.h"
42 #include "pluginterfaces/base/ibstream.h"
43 #include "pluginterfaces/base/ustring.h"
44 #include "pluginterfaces/vst/ivstcontextmenu.h"
45 #include "pluginterfaces/vst/ivstmidicontrollers.h"
46 #include "pluginterfaces/vst/ivstpluginterfacesupport.h"
47 
48 #include "editorsizecontroller.h"
49 #include "hostcheckerprocessor.h"
50 #include "logevents.h"
51 #include "vstgui/lib/cvstguitimer.h"
52 #include "base/source/fstreamer.h"
53 
54 using namespace VSTGUI;
55 
56 namespace Steinberg {
57 namespace Vst {
58 
59 //-----------------------------------------------------------------------------
60 FUID HostCheckerController::cid (0x35AC5652, 0xC7D24CB1, 0xB1427D38, 0xEB690DAF);
61 
62 //-----------------------------------------------------------------------------
63 class MyVST3Editor : public VST3Editor
64 {
65 public:
66 	MyVST3Editor (HostCheckerController* controller, UTF8StringPtr templateName,
67 	              UTF8StringPtr xmlFile);
68 
canResize(bool val)69 	void canResize (bool val) { mCanResize = val; }
70 
71 protected:
72 	~MyVST3Editor () override;
73 
74 	bool PLUGIN_API open (void* parent, const PlatformType& type) override;
75 	void PLUGIN_API close () override;
76 
77 	bool beforeSizeChange (const CRect& newSize, const CRect& oldSize) override;
78 
79 	Steinberg::tresult PLUGIN_API onSize (Steinberg::ViewRect* newSize) override;
80 	Steinberg::tresult PLUGIN_API canResize () override;
81 	Steinberg::tresult PLUGIN_API checkSizeConstraint (Steinberg::ViewRect* rect) override;
82 	Steinberg::tresult PLUGIN_API onKeyDown (char16 key, int16 keyMsg, int16 modifiers) override;
83 	Steinberg::tresult PLUGIN_API onKeyUp (char16 key, int16 keyMsg, int16 modifiers) override;
84 	Steinberg::tresult PLUGIN_API onWheel (float distance) override;
85 	Steinberg::tresult PLUGIN_API setFrame (IPlugFrame* frame) override;
86 	Steinberg::tresult PLUGIN_API attached (void* parent, FIDString type) override;
87 	Steinberg::tresult PLUGIN_API removed () override;
88 
89 	Steinberg::tresult PLUGIN_API setContentScaleFactor (ScaleFactor factor) override;
90 
91 	// IParameterFinder
92 	Steinberg::tresult PLUGIN_API findParameter (Steinberg::int32 xPos, Steinberg::int32 yPos,
93 	                                             Steinberg::Vst::ParamID& resultTag) override;
94 
95 	//---from CBaseObject---------------
96 	CMessageResult notify (CBaseObject* sender, const char* message) SMTG_OVERRIDE;
97 
98 private:
99 	CVSTGUITimer* checkTimer = nullptr;
100 	HostCheckerController* hostController = nullptr;
101 
102 	uint32 openCount = 0;
103 	bool wasAlreadyClosed = false;
104 	bool onSizeWanted = false;
105 	bool inOpen = false;
106 	bool inOnsize = false;
107 	bool mCanResize = true;
108 	bool mAttached = false;
109 };
110 
111 //-----------------------------------------------------------------------------
MyVST3Editor(HostCheckerController * controller,UTF8StringPtr templateName,UTF8StringPtr xmlFile)112 MyVST3Editor::MyVST3Editor (HostCheckerController* controller, UTF8StringPtr templateName,
113                             UTF8StringPtr xmlFile)
114 : VST3Editor (controller, templateName, xmlFile), hostController (controller)
115 {
116 }
117 
118 //-----------------------------------------------------------------------------
~MyVST3Editor()119 MyVST3Editor::~MyVST3Editor ()
120 {
121 	if (checkTimer)
122 		checkTimer->forget ();
123 }
124 
125 //-----------------------------------------------------------------------------
open(void * parent,const PlatformType & type)126 bool PLUGIN_API MyVST3Editor::open (void* parent, const PlatformType& type)
127 {
128 	inOpen = true;
129 
130 	openCount++;
131 
132 	if (wasAlreadyClosed)
133 		hostController->addFeatureLog (kLogIdIPlugViewmultipleAttachSupported);
134 
135 	bool res = VST3Editor::open (parent, type);
136 	auto hcController = dynamic_cast<HostCheckerController*> (controller);
137 	if (hcController)
138 	{
139 		ViewRect rect;
140 		if (hcController->getSavedSize (rect))
141 			onSize (&rect);
142 	}
143 	inOpen = false;
144 
145 	return res;
146 }
147 
148 //-----------------------------------------------------------------------------
close()149 void PLUGIN_API MyVST3Editor::close ()
150 {
151 	wasAlreadyClosed = true;
152 
153 	openCount--;
154 	return VST3Editor::close ();
155 }
156 
157 //-----------------------------------------------------------------------------
beforeSizeChange(const CRect & newSize,const CRect & oldSize)158 bool MyVST3Editor::beforeSizeChange (const CRect& newSize, const CRect& oldSize)
159 {
160 	if (!inOpen && !inOnsize)
161 	{
162 		if (!requestResizeGuard && newSize != oldSize)
163 		{
164 			onSizeWanted = true;
165 		}
166 	}
167 
168 	bool res = VST3Editor::beforeSizeChange (newSize, oldSize);
169 
170 	if (!inOpen && !inOnsize && !requestResizeGuard)
171 	{
172 		if (!res)
173 			onSizeWanted = false;
174 		else
175 			hostController->addFeatureLog (kLogIdIPlugFrameonResizeViewSupported);
176 
177 		if (onSizeWanted)
178 		{
179 			if (checkTimer == nullptr)
180 				checkTimer = new CVSTGUITimer (this, 500);
181 			checkTimer->stop ();
182 			checkTimer->start ();
183 		}
184 	}
185 	return res;
186 }
187 
188 //-----------------------------------------------------------------------------
onSize(Steinberg::ViewRect * newSize)189 Steinberg::tresult PLUGIN_API MyVST3Editor::onSize (Steinberg::ViewRect* newSize)
190 {
191 	inOnsize = true;
192 	if (!inOpen)
193 	{
194 		if (requestResizeGuard)
195 			hostController->addFeatureLog (kLogIdIPlugViewCalledSync);
196 		else if (onSizeWanted)
197 			hostController->addFeatureLog (kLogIdIPlugViewCalledAsync);
198 
199 		onSizeWanted = false;
200 
201 		hostController->addFeatureLog (kLogIdIPlugViewonSizeSupported);
202 	}
203 
204 	if (openCount == 0)
205 		hostController->addFeatureLog (kLogIdIPlugViewCalledBeforeOpen);
206 
207 	auto res = VST3Editor::onSize (newSize);
208 	inOnsize = false;
209 
210 	return res;
211 }
212 
213 //-----------------------------------------------------------------------------
canResize()214 Steinberg::tresult PLUGIN_API MyVST3Editor::canResize ()
215 {
216 	hostController->addFeatureLog (kLogIdIPlugViewcanResizeSupported);
217 	return mCanResize ? kResultTrue : kResultFalse;
218 }
219 
220 //-----------------------------------------------------------------------------
checkSizeConstraint(Steinberg::ViewRect * rect)221 Steinberg::tresult PLUGIN_API MyVST3Editor::checkSizeConstraint (Steinberg::ViewRect* rect)
222 {
223 	hostController->addFeatureLog (kLogIdIPlugViewcheckSizeConstraintSupported);
224 	return VST3Editor::checkSizeConstraint (rect);
225 }
226 
227 //------------------------------------------------------------------------
onKeyDown(char16 key,int16 keyMsg,int16 modifiers)228 tresult PLUGIN_API MyVST3Editor::onKeyDown (char16 key, int16 keyMsg, int16 modifiers)
229 {
230 	if (!mAttached)
231 		hostController->addFeatureLog (kLogIdIPlugViewKeyCalledBeforeAttach);
232 
233 	return VSTGUIEditor::onKeyDown (key, keyMsg, modifiers);
234 }
235 
236 //------------------------------------------------------------------------
onKeyUp(char16 key,int16 keyMsg,int16 modifiers)237 tresult PLUGIN_API MyVST3Editor::onKeyUp (char16 key, int16 keyMsg, int16 modifiers)
238 {
239 	if (!mAttached)
240 		hostController->addFeatureLog (kLogIdIPlugViewKeyCalledBeforeAttach);
241 
242 	return VSTGUIEditor::onKeyUp (key, keyMsg, modifiers);
243 }
244 
245 //------------------------------------------------------------------------
onWheel(float distance)246 tresult PLUGIN_API MyVST3Editor::onWheel (float distance)
247 {
248 	if (!mAttached)
249 		hostController->addFeatureLog (kLogIdIPlugViewKeyCalledBeforeAttach);
250 
251 	return VSTGUIEditor::onWheel (distance);
252 }
253 
254 //------------------------------------------------------------------------
setFrame(IPlugFrame * frame)255 tresult PLUGIN_API MyVST3Editor::setFrame (IPlugFrame* frame)
256 {
257 	hostController->addFeatureLog (kLogIdIPlugViewsetFrameSupported);
258 	return VSTGUIEditor::setFrame (frame);
259 }
260 
261 //-----------------------------------------------------------------------------
attached(void * parent,FIDString type)262 Steinberg::tresult PLUGIN_API MyVST3Editor::attached (void* parent, FIDString type)
263 {
264 	if (mAttached)
265 		hostController->addFeatureLog (kLogIdIPlugViewattachedWithoutRemoved);
266 
267 	mAttached = true;
268 	return VSTGUIEditor::attached (parent, type);
269 }
270 
271 //-----------------------------------------------------------------------------
removed()272 Steinberg::tresult PLUGIN_API MyVST3Editor::removed ()
273 {
274 	if (!mAttached)
275 		hostController->addFeatureLog (kLogIdIPlugViewremovedWithoutAttached);
276 
277 	mAttached = false;
278 	return VSTGUIEditor::removed ();
279 }
280 
281 //-----------------------------------------------------------------------------
setContentScaleFactor(ScaleFactor factor)282 Steinberg::tresult PLUGIN_API MyVST3Editor::setContentScaleFactor (ScaleFactor factor)
283 {
284 	hostController->addFeatureLog (kLogIdIPlugViewsetContentScaleFactorSupported);
285 	return VST3Editor::setContentScaleFactor (factor);
286 }
287 
288 //-----------------------------------------------------------------------------
findParameter(Steinberg::int32 xPos,Steinberg::int32 yPos,Steinberg::Vst::ParamID & resultTag)289 Steinberg::tresult PLUGIN_API MyVST3Editor::findParameter (Steinberg::int32 xPos,
290                                                            Steinberg::int32 yPos,
291                                                            Steinberg::Vst::ParamID& resultTag)
292 {
293 	hostController->addFeatureLog (kLogIdIParameterFinderSupported);
294 	return VST3Editor::findParameter (xPos, yPos, resultTag);
295 }
296 
297 //-----------------------------------------------------------------------------
notify(CBaseObject * sender,const char * message)298 VSTGUI::CMessageResult MyVST3Editor::notify (CBaseObject* sender, const char* message)
299 {
300 	if (sender == checkTimer)
301 	{
302 		if (onSizeWanted)
303 			hostController->addFeatureLog (kLogIdIPlugViewNotCalled);
304 
305 		checkTimer->forget ();
306 		checkTimer = nullptr;
307 		return kMessageNotified;
308 	}
309 
310 	return VST3Editor::notify (sender, message);
311 }
312 
313 //-----------------------------------------------------------------------------
314 //-----------------------------------------------------------------------------
315 //-----------------------------------------------------------------------------
initialize(FUnknown * context)316 tresult PLUGIN_API HostCheckerController::initialize (FUnknown* context)
317 {
318 	tresult result = EditControllerEx1::initialize (context);
319 	if (result == kResultOk)
320 	{
321 		// create a unit Latency parameter
322 		UnitInfo unitInfo;
323 		unitInfo.id = kUnitId;
324 		unitInfo.parentUnitId = kRootUnitId; // attached to the root unit
325 		Steinberg::UString (unitInfo.name, USTRINGSIZE (unitInfo.name)).assign (USTRING ("Setup"));
326 		unitInfo.programListId = kNoProgramListId;
327 
328 		auto* unit = new Unit (unitInfo);
329 		addUnit (unit);
330 
331 		parameters.addParameter (STR16 ("Param1"), STR16 (""), 0, 0, ParameterInfo::kCanAutomate,
332 		                         kParam1Tag);
333 		parameters.addParameter (STR16 ("Generate Peaks"), STR16 (""), 0, 0, 0, kGeneratePeaksTag);
334 		parameters.addParameter (STR16 ("Latency"), STR16 (""), 0, 0, 0, kLatencyTag, kUnitId);
335 		parameters.addParameter (STR16 ("CanResize"), STR16 (""), 1, 1, 0, kCanResizeTag);
336 
337 		parameters.addParameter (STR16 ("Scoring"), STR16 (""), 10, 0, 0, kScoreTag);
338 		parameters.addParameter (STR16 ("Bypass"), STR16 (""), 1, 0,
339 		                         ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass,
340 		                         kBypassTag);
341 
342 		mDataBrowser = nullptr;
343 		mDataSource = nullptr;
344 
345 		if (!mDataSource)
346 			mDataSource = VSTGUI::owned (new EventLogDataBrowserSource (this));
347 
348 		if (!mDataBrowser)
349 			mDataBrowser = VSTGUI::owned (new CDataBrowser (
350 			    CRect (0, 0, 100, 100), mDataSource,
351 			    CDataBrowser::kDrawRowLines | CDataBrowser::kDrawColumnLines |
352 			        CDataBrowser::kDrawHeader | CDataBrowser::kVerticalScrollbar));
353 	}
354 
355 	FUnknownPtr<IPlugInterfaceSupport> plugInterfaceSupport (context);
356 	if (plugInterfaceSupport)
357 	{
358 		addFeatureLog (kLogIdIPlugInterfaceSupportSupported);
359 
360 		if (plugInterfaceSupport->isPlugInterfaceSupported (IMidiMapping::iid) == kResultTrue)
361 			addFeatureLog (kLogIdIMidiMappingSupported);
362 		if (plugInterfaceSupport->isPlugInterfaceSupported (IMidiLearn::iid) == kResultTrue)
363 			addFeatureLog (kLogIdIMidiLearnSupported);
364 		if (plugInterfaceSupport->isPlugInterfaceSupported (ChannelContext::IInfoListener::iid) == kResultTrue)
365 			addFeatureLog (kLogIdChannelContextSupported);
366 		if (plugInterfaceSupport->isPlugInterfaceSupported (INoteExpressionController::iid) == kResultTrue)
367 			addFeatureLog (kLogIdINoteExpressionControllerSupported);
368 		if (plugInterfaceSupport->isPlugInterfaceSupported (INoteExpressionPhysicalUIMapping::iid) == kResultTrue)
369 			addFeatureLog (kLogIdINoteExpressionPhysicalUIMappingSupported);
370 		if (plugInterfaceSupport->isPlugInterfaceSupported (IXmlRepresentationController::iid) == kResultTrue)
371 			addFeatureLog (kLogIdIXmlRepresentationControllerSupported);
372 	}
373 
374 	return result;
375 }
376 
377 //-----------------------------------------------------------------------------
terminate()378 tresult PLUGIN_API HostCheckerController::terminate ()
379 {
380 	tresult result = EditControllerEx1::terminate ();
381 	if (result == kResultOk)
382 	{
383 		mDataSource = nullptr;
384 		mDataBrowser = nullptr;
385 	}
386 	return result;
387 }
388 
389 //-----------------------------------------------------------------------------
setComponentState(IBStream * state)390 tresult PLUGIN_API HostCheckerController::setComponentState (IBStream* state)
391 {
392 	if (!state)
393 		return kResultFalse;
394 
395 	IBStreamer streamer (state, kLittleEndian);
396 
397 	float saved = 0.f;
398 	if (streamer.readFloat (saved) == false)
399 		return kResultFalse;
400 	if (saved != 12345.67f)
401 	{
402 		SMTG_ASSERT (false)
403 	}
404 
405 	uint32 latency;
406 	if (streamer.readInt32u (latency) == false)
407 		return kResultFalse;
408 
409 	uint32 bypass;
410 	if (streamer.readInt32u (bypass) == false)
411 		return kResultFalse;
412 
413 	setParamNormalized (kBypassTag, bypass > 0 ? 1 : 0);
414 
415 	return kResultOk;
416 }
417 
418 //-----------------------------------------------------------------------------
getUnitByBus(MediaType type,BusDirection dir,int32 busIndex,int32 channel,UnitID & unitId)419 tresult PLUGIN_API HostCheckerController::getUnitByBus (MediaType type, BusDirection dir,
420                                                         int32 busIndex, int32 channel,
421                                                         UnitID& unitId /*out*/)
422 {
423 	if (type == kEvent && dir == kInput)
424 	{
425 		if (busIndex == 0 && channel == 0)
426 		{
427 			unitId = kRootUnitId;
428 			return kResultTrue;
429 		}
430 	}
431 	addFeatureLog (kLogIdGetUnitByBusSupported);
432 	return kResultFalse;
433 }
434 
435 //-----------------------------------------------------------------------------
setComponentHandler(IComponentHandler * handler)436 tresult PLUGIN_API HostCheckerController::setComponentHandler (IComponentHandler* handler)
437 {
438 	tresult res = EditControllerEx1::setComponentHandler (handler);
439 	if (componentHandler2)
440 	{
441 		addFeatureLog (kLogIdIComponentHandler2Supported);
442 
443 		if (componentHandler2->requestOpenEditor () == kResultTrue)
444 			addFeatureLog (kLogIdIComponentHandler2RequestOpenEditorSupported);
445 	}
446 
447 	FUnknownPtr<IComponentHandler3> handler3 (handler);
448 	if (handler3)
449 		addFeatureLog (kLogIdIComponentHandler3Supported);
450 
451 	return res;
452 }
453 
454 //-----------------------------------------------------------------------------
getUnitCount()455 int32 PLUGIN_API HostCheckerController::getUnitCount ()
456 {
457 	addFeatureLog (kLogIdUnitSupported);
458 	return EditControllerEx1::getUnitCount ();
459 }
460 
461 //-----------------------------------------------------------------------------
setParamNormalized(ParamID tag,ParamValue value)462 tresult PLUGIN_API HostCheckerController::setParamNormalized (ParamID tag, ParamValue value)
463 {
464 	if (tag == kLatencyTag && mLatencyInEdit)
465 	{
466 		mWantedLatency = value;
467 		return kResultTrue;
468 	}
469 	return EditControllerEx1::setParamNormalized (tag, value);
470 }
471 
472 //------------------------------------------------------------------------
beginEdit(ParamID tag)473 tresult HostCheckerController::beginEdit (ParamID tag)
474 {
475 	if (tag == kLatencyTag)
476 		mLatencyInEdit = true;
477 
478 	return EditControllerEx1::beginEdit (tag);
479 }
480 
481 //-----------------------------------------------------------------------------
endEdit(ParamID tag)482 tresult HostCheckerController::endEdit (ParamID tag)
483 {
484 	if (tag == kLatencyTag && mLatencyInEdit)
485 	{
486 		EditControllerEx1::setParamNormalized (tag, mWantedLatency);
487 		mLatencyInEdit = false;
488 	}
489 	return EditControllerEx1::endEdit (tag);
490 }
491 
492 //-----------------------------------------------------------------------------
createView(FIDString name)493 IPlugView* PLUGIN_API HostCheckerController::createView (FIDString name)
494 {
495 	if (ConstString (name) == ViewType::kEditor)
496 	{
497 		if (componentHandler2)
498 		{
499 			if (componentHandler2->setDirty (true) == kResultTrue)
500 				addFeatureLog (kLogIdIComponentHandler2SetDirtySupported);
501 		}
502 
503 		auto view = new MyVST3Editor (this, "HostCheckerEditor", "hostchecker.uidesc");
504 		if (sizeFactor != 0)
505 		{
506 			ViewRect rect (0, 0, width, height);
507 			view->setRect (rect);
508 			view->setZoomFactor (sizeFactor);
509 		}
510 		view->canResize (parameters.getParameter (kCanResizeTag)->getNormalized () > 0);
511 
512 		return view;
513 	}
514 	return nullptr;
515 }
516 
517 //-----------------------------------------------------------------------------
createCustomView(UTF8StringPtr name,const UIAttributes & attributes,const IUIDescription * description,VST3Editor * editor)518 CView* HostCheckerController::createCustomView (UTF8StringPtr name, const UIAttributes& attributes,
519                                                 const IUIDescription* description,
520                                                 VST3Editor* editor)
521 {
522 	if (ConstString (name) == "HostCheckerDataBrowser")
523 	{
524 		if (mDataBrowser)
525 			mDataBrowser->remember ();
526 		return mDataBrowser;
527 	}
528 	return nullptr;
529 }
530 
531 //-----------------------------------------------------------------------------
connect(IConnectionPoint * other)532 tresult PLUGIN_API HostCheckerController::connect (IConnectionPoint* other)
533 {
534 	Steinberg::tresult tResult = ComponentBase::connect (other);
535 	if (peerConnection)
536 	{
537 		for (Steinberg::int32 paramIdx = 0; paramIdx < getParameterCount (); ++paramIdx)
538 		{
539 			Steinberg::Vst::ParameterInfo paramInfo = {0};
540 			if (getParameterInfo (paramIdx, paramInfo) == Steinberg::kResultOk)
541 			{
542 				IPtr<IMessage> newMsg = owned (allocateMessage ());
543 				if (newMsg)
544 				{
545 					newMsg->setMessageID ("Parameter");
546 					Steinberg::Vst::IAttributeList* attr = newMsg->getAttributes ();
547 					if (attr)
548 					{
549 						attr->setInt ("ID", paramInfo.id);
550 					}
551 
552 					sendMessage (newMsg);
553 				}
554 			}
555 		}
556 
557 		FUnknownPtr<IAudioProcessor> proc (other);
558 		if (proc)
559 		{
560 			IPtr<IMessage> newMsg = owned (allocateMessage ());
561 			if (newMsg)
562 			{
563 				newMsg->setMessageID ("LogEvent");
564 				Steinberg::Vst::IAttributeList* attr = newMsg->getAttributes ();
565 				if (attr)
566 				{
567 					attr->setInt ("ID", kLogIdProcessorControllerConnection);
568 					attr->setInt ("Count", 1);
569 				}
570 
571 				notify (newMsg);
572 			}
573 		}
574 	}
575 
576 	return tResult;
577 }
578 
579 //-----------------------------------------------------------------------------
notify(IMessage * message)580 tresult PLUGIN_API HostCheckerController::notify (IMessage* message)
581 {
582 	if (!message)
583 		return kInvalidArgument;
584 
585 	if (FIDStringsEqual (message->getMessageID (), "LogEvent"))
586 	{
587 		LogEvent logEvt;
588 		if (message->getAttributes ()->getInt ("ID", logEvt.id) != kResultOk)
589 			return kResultFalse;
590 		if (message->getAttributes ()->getInt ("Count", logEvt.count) != kResultOk)
591 			return kResultFalse;
592 
593 		if (mDataSource && mDataBrowser && mDataSource->updateLog (logEvt))
594 			mDataBrowser->invalidateRow (logEvt.id);
595 	}
596 
597 	if (FIDStringsEqual (message->getMessageID (), "Latency"))
598 	{
599 		ParamValue value;
600 		if (message->getAttributes ()->getFloat ("Value", value) == kResultOk)
601 		{
602 			componentHandler->restartComponent (kLatencyChanged);
603 		}
604 	}
605 
606 	return ComponentBase::notify (message);
607 }
608 
609 //-----------------------------------------------------------------------------
addFeatureLog(int32 iD)610 void HostCheckerController::addFeatureLog (int32 iD)
611 {
612 	LogEvent logEvt;
613 	logEvt.id = iD;
614 	logEvt.count = 1;
615 
616 	if (mDataSource && mDataBrowser && mDataSource->updateLog (logEvt))
617 		mDataBrowser->invalidateRow (logEvt.id);
618 }
619 
620 //-----------------------------------------------------------------------------
setKnobMode(KnobMode mode)621 tresult PLUGIN_API HostCheckerController::setKnobMode (KnobMode mode)
622 {
623 	addFeatureLog (kLogIdIEditController2Supported);
624 	return EditControllerEx1::setKnobMode (mode);
625 }
626 
627 //-----------------------------------------------------------------------------
openHelp(TBool onlyCheck)628 tresult PLUGIN_API HostCheckerController::openHelp (TBool onlyCheck)
629 {
630 	addFeatureLog (kLogIdIEditController2Supported);
631 	return EditControllerEx1::openHelp (onlyCheck);
632 }
633 
634 //-----------------------------------------------------------------------------
openAboutBox(TBool onlyCheck)635 tresult PLUGIN_API HostCheckerController::openAboutBox (TBool onlyCheck)
636 {
637 	addFeatureLog (kLogIdIEditController2Supported);
638 	return EditControllerEx1::openAboutBox (onlyCheck);
639 }
640 
641 //-----------------------------------------------------------------------------
setChannelContextInfos(IAttributeList * list)642 tresult PLUGIN_API HostCheckerController::setChannelContextInfos (IAttributeList* list)
643 {
644 	if (!list)
645 		return kResultFalse;
646 
647 	// optional we can ask for the Channel Name Length
648 	int64 length;
649 	if (list->getInt (ChannelContext::kChannelNameLengthKey, length) == kResultTrue)
650 	{
651 	}
652 
653 	// get the Channel Name where we, as Plug-in, are instantiated
654 	String128 name;
655 	if (list->getString (ChannelContext::kChannelNameKey, name, sizeof (name)) == kResultTrue)
656 	{
657 	}
658 
659 	// get the Channel UID
660 	if (list->getString (ChannelContext::kChannelUIDKey, name, sizeof (name)) == kResultTrue)
661 	{
662 	}
663 
664 	// get Channel Index
665 	int64 index;
666 	if (list->getInt (ChannelContext::kChannelIndexKey, index) == kResultTrue)
667 	{
668 	}
669 
670 	// get the Channel Color
671 	int64 color;
672 	if (list->getInt (ChannelContext::kChannelColorKey, color) == kResultTrue)
673 	{
674 		//	ColorSpec channelColor = (ColorSpec)color;
675 	}
676 
677 	addFeatureLog (kLogIdChannelContextSupported);
678 
679 	return kResultTrue;
680 }
681 
682 //-----------------------------------------------------------------------------
getXmlRepresentationStream(RepresentationInfo & info,IBStream * stream)683 tresult PLUGIN_API HostCheckerController::getXmlRepresentationStream (
684     RepresentationInfo& info /*in*/, IBStream* stream /*out*/)
685 {
686 	addFeatureLog (kLogIdIXmlRepresentationControllerSupported);
687 
688 	String name (info.name);
689 	if (name == GENERIC_8_CELLS)
690 	{
691 		Vst::XmlRepresentationHelper helper (info, "Steinberg Media Technologies",
692 		                                     "VST3 Host Checker",
693 		                                     HostCheckerProcessor::cid.toTUID (), stream);
694 
695 		helper.startPage ("Main Page");
696 		helper.startEndCellOneLayer (Vst::LayerType::kKnob, 0);
697 		helper.startEndCellOneLayer (Vst::LayerType::kKnob, 1);
698 		helper.startEndCell (); // empty cell
699 		helper.startEndCell (); // empty cell
700 		helper.startEndCell (); // empty cell
701 		helper.startEndCell (); // empty cell
702 		helper.startEndCell (); // empty cell
703 		helper.startEndCell (); // empty cell
704 		helper.endPage ();
705 
706 		helper.startPage ("Page 2");
707 		helper.startEndCellOneLayer (Vst::LayerType::kSwitch, 2);
708 		helper.startEndCell (); // empty cell
709 		helper.startEndCell (); // empty cell
710 		helper.startEndCell (); // empty cell
711 		helper.startEndCell (); // empty cell
712 		helper.startEndCell (); // empty cell
713 		helper.startEndCell (); // empty cell
714 		helper.startEndCell (); // empty
715 		helper.endPage ();
716 
717 		return kResultTrue;
718 	}
719 	return kResultFalse;
720 }
721 
722 //-----------------------------------------------------------------------------
getMidiControllerAssignment(int32 busIndex,int16 channel,CtrlNumber midiControllerNumber,ParamID & id)723 tresult PLUGIN_API HostCheckerController::getMidiControllerAssignment (
724     int32 busIndex, int16 channel, CtrlNumber midiControllerNumber, ParamID& id /*out*/)
725 {
726 	addFeatureLog (kLogIdIMidiMappingSupported);
727 
728 	if (busIndex != 0)
729 		return kResultFalse;
730 
731 	switch (midiControllerNumber)
732 	{
733 		case ControllerNumbers::kCtrlPan: id = kParam1Tag; return kResultOk;
734 		case ControllerNumbers::kCtrlExpression: id = kGeneratePeaksTag; return kResultOk;
735 		case ControllerNumbers::kCtrlEffect1: id = kBypassTag; return kResultOk;
736 	}
737 	return kResultFalse;
738 }
739 
740 //-----------------------------------------------------------------------------
onLiveMIDIControllerInput(int32 busIndex,int16 channel,CtrlNumber midiCC)741 tresult PLUGIN_API HostCheckerController::onLiveMIDIControllerInput (int32 busIndex, int16 channel, CtrlNumber midiCC)
742 {
743 	addFeatureLog (kLogIdIMidiLearn_onLiveMIDIControllerInputSupported);
744 	return kResultTrue;
745 }
746 
747 //-----------------------------------------------------------------------------
getNoteExpressionCount(int32 busIndex,int16 channel)748 int32 PLUGIN_API HostCheckerController::getNoteExpressionCount (int32 busIndex, int16 channel)
749 {
750 	addFeatureLog (kLogIdINoteExpressionControllerSupported);
751 	return 0;
752 }
753 
754 //-----------------------------------------------------------------------------
getNoteExpressionInfo(int32 busIndex,int16 channel,int32 noteExpressionIndex,NoteExpressionTypeInfo & info)755 tresult PLUGIN_API HostCheckerController::getNoteExpressionInfo (
756     int32 busIndex, int16 channel, int32 noteExpressionIndex, NoteExpressionTypeInfo& info /*out*/)
757 {
758 	return kResultFalse;
759 }
760 
761 //-----------------------------------------------------------------------------
getNoteExpressionStringByValue(int32 busIndex,int16 channel,NoteExpressionTypeID id,NoteExpressionValue valueNormalized,String128 string)762 tresult PLUGIN_API HostCheckerController::getNoteExpressionStringByValue (
763     int32 busIndex, int16 channel, NoteExpressionTypeID id,
764     NoteExpressionValue valueNormalized /*in*/, String128 string /*out*/)
765 {
766 	return kResultFalse;
767 }
768 
769 //-----------------------------------------------------------------------------
getNoteExpressionValueByString(int32 busIndex,int16 channel,NoteExpressionTypeID id,const TChar * string,NoteExpressionValue & valueNormalized)770 tresult PLUGIN_API HostCheckerController::getNoteExpressionValueByString (
771     int32 busIndex, int16 channel, NoteExpressionTypeID id, const TChar* string /*in*/,
772     NoteExpressionValue& valueNormalized /*out*/)
773 {
774 	return kResultFalse;
775 }
776 
777 //------------------------------------------------------------------------
getPhysicalUIMapping(int32 busIndex,int16 channel,PhysicalUIMapList & list)778 tresult PLUGIN_API HostCheckerController::getPhysicalUIMapping (int32 busIndex, int16 channel,
779                                                                 PhysicalUIMapList& list)
780 {
781 	addFeatureLog (kLogIdINoteExpressionPhysicalUIMappingSupported);
782 	return kResultTrue;
783 }
784 
785 //------------------------------------------------------------------------
extractCurrentInfo(EditorView * editor)786 void HostCheckerController::extractCurrentInfo (EditorView* editor)
787 {
788 	auto rect = editor->getRect ();
789 	height = rect.getHeight ();
790 	width = rect.getWidth ();
791 
792 	auto* vst3editor = dynamic_cast<VST3Editor*> (editor);
793 	if (vst3editor)
794 		sizeFactor = vst3editor->getZoomFactor ();
795 }
796 
797 //------------------------------------------------------------------------
editorRemoved(EditorView * editor)798 void HostCheckerController::editorRemoved (EditorView* editor)
799 {
800 	extractCurrentInfo (editor);
801 	editors.erase (std::find (editors.begin (), editors.end (), editor));
802 
803 	editorsSubCtlerMap.erase (editor);
804 }
805 
806 //------------------------------------------------------------------------
editorDestroyed(EditorView * editor)807 void HostCheckerController::editorDestroyed (EditorView* editor)
808 {
809 }
810 
811 //------------------------------------------------------------------------
editorAttached(EditorView * editor)812 void HostCheckerController::editorAttached (EditorView* editor)
813 {
814 	editors.push_back (editor);
815 	extractCurrentInfo (editor);
816 }
817 
818 //------------------------------------------------------------------------
createSubController(UTF8StringPtr name,const IUIDescription * description,VST3Editor * editor)819 VSTGUI::IController* HostCheckerController::createSubController (UTF8StringPtr name,
820                                                                  const IUIDescription* description,
821                                                                  VST3Editor* editor)
822 {
823 	if (UTF8StringView (name) == "EditorSizeController")
824 	{
825 		auto sizeFunc = [&] (float _sizeFactor) {
826 			sizeFactor = _sizeFactor;
827 			for (auto& editor : editors)
828 			{
829 				auto* vst3editor = dynamic_cast<VST3Editor*> (editor);
830 				if (vst3editor)
831 					vst3editor->setZoomFactor (sizeFactor);
832 			}
833 		};
834 		auto subController = new EditorSizeController (this, sizeFunc, sizeFactor);
835 		editorsSubCtlerMap.insert ({editor, subController});
836 		return subController;
837 	}
838 	return nullptr;
839 }
840 
841 //-----------------------------------------------------------------------------
queryInterface(const Steinberg::TUID iid,void ** obj)842 tresult PLUGIN_API HostCheckerController::queryInterface (const Steinberg::TUID iid, void** obj)
843 {
844 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, IMidiMapping::iid))
845 	{
846 		addRef ();
847 		*obj = static_cast<IMidiMapping*> (this);
848 		addFeatureLog (kLogIdIMidiMappingSupported);
849 		return ::Steinberg::kResultOk;
850 	}
851 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, IXmlRepresentationController::iid))
852 	{
853 		addRef ();
854 		*obj = static_cast<IXmlRepresentationController*> (this);
855 		addFeatureLog (kLogIdIXmlRepresentationControllerSupported);
856 		return ::Steinberg::kResultOk;
857 	}
858 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, ChannelContext::IInfoListener::iid))
859 	{
860 		addRef ();
861 		*obj = static_cast<ChannelContext::IInfoListener*> (this);
862 		addFeatureLog (kLogIdChannelContextSupported);
863 		return ::Steinberg::kResultOk;
864 	}
865 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, INoteExpressionController::iid))
866 	{
867 		addRef ();
868 		*obj = static_cast<INoteExpressionController*> (this);
869 		addFeatureLog (kLogIdINoteExpressionControllerSupported);
870 		return ::Steinberg::kResultOk;
871 	}
872 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, INoteExpressionPhysicalUIMapping::iid))
873 	{
874 		addRef ();
875 		*obj = static_cast<INoteExpressionPhysicalUIMapping*> (this);
876 		addFeatureLog (kLogIdINoteExpressionPhysicalUIMappingSupported);
877 		return ::Steinberg::kResultOk;
878 	}
879 
880 	if (::Steinberg::FUnknownPrivate::iidEqual (iid, IMidiLearn::iid))
881 	{
882 		addRef ();
883 		*obj = static_cast<IMidiLearn*> (this);
884 		addFeatureLog (kLogIdIMidiLearnSupported);
885 		return ::Steinberg::kResultOk;
886 	}
887 	return EditControllerEx1::queryInterface (iid, obj);
888 }
889 
890 //-----------------------------------------------------------------------------
setState(IBStream * state)891 tresult PLUGIN_API HostCheckerController::setState (IBStream* state)
892 {
893 	if (!state)
894 		return kResultFalse;
895 
896 	IBStreamer streamer (state, kLittleEndian);
897 
898 	uint32 version = 1;
899 	if (streamer.readInt32u (version) == false)
900 		return kResultFalse;
901 
902 	if (streamer.readInt32u (height) == false)
903 		return kResultFalse;
904 	if (streamer.readInt32u (width) == false)
905 		return kResultFalse;
906 	if (streamer.readDouble (sizeFactor) == false)
907 		return kResultFalse;
908 
909 	for (auto& item : editorsSubCtlerMap)
910 	{
911 		item.second->setSizeFactor (sizeFactor);
912 	}
913 
914 	// since version 2
915 	if (version > 1)
916 	{
917 		bool canResize = true;
918 		streamer.readBool (canResize);
919 		parameters.getParameter (kCanResizeTag)->setNormalized (canResize ? 1 : 0);
920 	}
921 
922 	return kResultOk;
923 }
924 
925 //-----------------------------------------------------------------------------
getState(IBStream * state)926 tresult PLUGIN_API HostCheckerController::getState (IBStream* state)
927 {
928 	if (!state)
929 		return kResultFalse;
930 
931 	IBStreamer streamer (state, kLittleEndian);
932 
933 	uint32 version = 2;
934 	streamer.writeInt32u (version);
935 	streamer.writeInt32u (height);
936 	streamer.writeInt32u (width);
937 	streamer.writeDouble (sizeFactor);
938 
939 	// since version 2
940 	bool canResize = parameters.getParameter (kCanResizeTag)->getNormalized () > 0;
941 	streamer.writeBool (canResize);
942 
943 	return kResultOk;
944 }
945 
946 //-----------------------------------------------------------------------------
947 }
948 } // namespaces
949