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