1 //-----------------------------------------------------------------------------
2 // Project     : VST SDK
3 //
4 // Category    : Helpers
5 // Filename    : public.sdk/source/vst/vsteditcontroller.cpp
6 // Created by  : Steinberg, 04/2005
7 // Description : VST Edit Controller Implementation
8 //
9 //-----------------------------------------------------------------------------
10 // LICENSE
11 // (c) 2020, 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 "public.sdk/source/vst/vsteditcontroller.h"
38 #include "base/source/updatehandler.h"
39 #include "pluginterfaces/base/ustring.h"
40 
41 #include <cstdio>
42 
43 namespace Steinberg {
44 namespace Vst {
45 
46 KnobMode EditController::hostKnobMode = kCircularMode;
47 
48 //------------------------------------------------------------------------
49 // EditController Implementation
50 //------------------------------------------------------------------------
EditController()51 EditController::EditController () : componentHandler (nullptr), componentHandler2 (nullptr)
52 {
53 }
54 
55 //------------------------------------------------------------------------
initialize(FUnknown * context)56 tresult PLUGIN_API EditController::initialize (FUnknown* context)
57 {
58 	return ComponentBase::initialize (context);
59 }
60 
61 //------------------------------------------------------------------------
terminate()62 tresult PLUGIN_API EditController::terminate ()
63 {
64 	parameters.removeAll ();
65 
66 	if (componentHandler)
67 	{
68 		componentHandler->release ();
69 		componentHandler = nullptr;
70 	}
71 
72 	if (componentHandler2)
73 	{
74 		componentHandler2->release ();
75 		componentHandler2 = nullptr;
76 	}
77 
78 	return ComponentBase::terminate ();
79 }
80 
81 //------------------------------------------------------------------------
setComponentState(IBStream *)82 tresult PLUGIN_API EditController::setComponentState (IBStream* /*state*/)
83 {
84 	return kNotImplemented;
85 }
86 
87 //------------------------------------------------------------------------
setState(IBStream *)88 tresult PLUGIN_API EditController::setState (IBStream* /*state*/)
89 {
90 	return kNotImplemented;
91 }
92 
93 //------------------------------------------------------------------------
getState(IBStream *)94 tresult PLUGIN_API EditController::getState (IBStream* /*state*/)
95 {
96 	return kNotImplemented;
97 }
98 
99 //------------------------------------------------------------------------
getParameterCount()100 int32 PLUGIN_API EditController::getParameterCount ()
101 {
102 	return parameters.getParameterCount ();
103 }
104 
105 //------------------------------------------------------------------------
getParameterInfo(int32 paramIndex,ParameterInfo & info)106 tresult PLUGIN_API EditController::getParameterInfo (int32 paramIndex, ParameterInfo& info)
107 {
108 	if (Parameter* parameter = parameters.getParameterByIndex (paramIndex))
109 	{
110 		info = parameter->getInfo ();
111 		return kResultTrue;
112 	}
113 	return kResultFalse;
114 }
115 
116 //------------------------------------------------------------------------
getParamStringByValue(ParamID tag,ParamValue valueNormalized,String128 string)117 tresult PLUGIN_API EditController::getParamStringByValue (ParamID tag, ParamValue valueNormalized,
118                                                           String128 string)
119 {
120 	if (Parameter* parameter = getParameterObject (tag))
121 	{
122 		parameter->toString (valueNormalized, string);
123 		return kResultTrue;
124 	}
125 	return kResultFalse;
126 }
127 
128 //------------------------------------------------------------------------
getParamValueByString(ParamID tag,TChar * string,ParamValue & valueNormalized)129 tresult PLUGIN_API EditController::getParamValueByString (ParamID tag, TChar* string,
130                                                           ParamValue& valueNormalized)
131 {
132 	if (Parameter* parameter = getParameterObject (tag))
133 	{
134 		if (parameter->fromString (string, valueNormalized))
135 		{
136 			return kResultTrue;
137 		}
138 	}
139 	return kResultFalse;
140 }
141 
142 //------------------------------------------------------------------------
normalizedParamToPlain(ParamID tag,ParamValue valueNormalized)143 ParamValue PLUGIN_API EditController::normalizedParamToPlain (ParamID tag,
144                                                               ParamValue valueNormalized)
145 {
146 	if (Parameter* parameter = getParameterObject (tag))
147 	{
148 		return parameter->toPlain (valueNormalized);
149 	}
150 	return valueNormalized;
151 }
152 
153 //------------------------------------------------------------------------
plainParamToNormalized(ParamID tag,ParamValue plainValue)154 ParamValue PLUGIN_API EditController::plainParamToNormalized (ParamID tag, ParamValue plainValue)
155 {
156 	if (Parameter* parameter = getParameterObject (tag))
157 	{
158 		return parameter->toNormalized (plainValue);
159 	}
160 	return plainValue;
161 }
162 
163 //------------------------------------------------------------------------
getParamNormalized(ParamID tag)164 ParamValue PLUGIN_API EditController::getParamNormalized (ParamID tag)
165 {
166 	if (Parameter* parameter = getParameterObject (tag))
167 	{
168 		return parameter->getNormalized ();
169 	}
170 	return 0.;
171 }
172 
173 //------------------------------------------------------------------------
setParamNormalized(ParamID tag,ParamValue value)174 tresult PLUGIN_API EditController::setParamNormalized (ParamID tag, ParamValue value)
175 {
176 	if (Parameter* parameter = getParameterObject (tag))
177 	{
178 		parameter->setNormalized (value);
179 		return kResultTrue;
180 	}
181 	return kResultFalse;
182 }
183 
184 //------------------------------------------------------------------------
setComponentHandler(IComponentHandler * newHandler)185 tresult PLUGIN_API EditController::setComponentHandler (IComponentHandler* newHandler)
186 {
187 	if (componentHandler == newHandler)
188 	{
189 		return kResultTrue;
190 	}
191 
192 	if (componentHandler)
193 	{
194 		componentHandler->release ();
195 	}
196 
197 	componentHandler = newHandler;
198 	if (componentHandler)
199 	{
200 		componentHandler->addRef ();
201 	}
202 
203 	// try to get the extended version
204 	if (componentHandler2)
205 	{
206 		componentHandler2->release ();
207 		componentHandler2 = nullptr;
208 	}
209 
210 	if (newHandler)
211 	{
212 		newHandler->queryInterface (IComponentHandler2::iid, (void**)&componentHandler2);
213 	}
214 	return kResultTrue;
215 }
216 
217 //------------------------------------------------------------------------
beginEdit(ParamID tag)218 tresult EditController::beginEdit (ParamID tag)
219 {
220 	if (componentHandler)
221 	{
222 		return componentHandler->beginEdit (tag);
223 	}
224 	return kResultFalse;
225 }
226 
227 //------------------------------------------------------------------------
performEdit(ParamID tag,ParamValue valueNormalized)228 tresult EditController::performEdit (ParamID tag, ParamValue valueNormalized)
229 {
230 	if (componentHandler)
231 	{
232 		return componentHandler->performEdit (tag, valueNormalized);
233 	}
234 	return kResultFalse;
235 }
236 
237 //------------------------------------------------------------------------
endEdit(ParamID tag)238 tresult EditController::endEdit (ParamID tag)
239 {
240 	if (componentHandler)
241 	{
242 		return componentHandler->endEdit (tag);
243 	}
244 	return kResultFalse;
245 }
246 
247 //------------------------------------------------------------------------
startGroupEdit()248 tresult EditController::startGroupEdit ()
249 {
250 	if (componentHandler2)
251 	{
252 		return componentHandler2->startGroupEdit ();
253 	}
254 	return kNotImplemented;
255 }
256 
257 //------------------------------------------------------------------------
finishGroupEdit()258 tresult EditController::finishGroupEdit ()
259 {
260 	if (componentHandler2)
261 	{
262 		return componentHandler2->finishGroupEdit ();
263 	}
264 	return kNotImplemented;
265 }
266 
267 //------------------------------------------------------------------------
getParameterInfoByTag(ParamID tag,ParameterInfo & info)268 tresult EditController::getParameterInfoByTag (ParamID tag, ParameterInfo& info)
269 {
270 	if (Parameter* parameter = getParameterObject (tag))
271 	{
272 		info = parameter->getInfo ();
273 		return kResultTrue;
274 	}
275 	return kResultFalse;
276 }
277 
278 //------------------------------------------------------------------------
setDirty(TBool state)279 tresult EditController::setDirty (TBool state)
280 {
281 	if (componentHandler2)
282 	{
283 		return componentHandler2->setDirty (state);
284 	}
285 	return kNotImplemented;
286 }
287 
288 //------------------------------------------------------------------------
requestOpenEditor(FIDString name)289 tresult EditController::requestOpenEditor (FIDString name)
290 {
291 	if (componentHandler2)
292 	{
293 		return componentHandler2->requestOpenEditor (name);
294 	}
295 	return kNotImplemented;
296 }
297 
298 #ifndef NO_PLUGUI
299 //------------------------------------------------------------------------
300 // EditorView Implementation
301 //------------------------------------------------------------------------
EditorView(EditController * _controller,ViewRect * size)302 EditorView::EditorView (EditController* _controller, ViewRect* size)
303 : CPluginView (size), controller (_controller)
304 {
305 	if (controller)
306 	{
307 		controller->addRef ();
308 	}
309 }
310 
311 //------------------------------------------------------------------------
~EditorView()312 EditorView::~EditorView ()
313 {
314 	if (controller)
315 	{
316 		controller->editorDestroyed (this);
317 		controller->release ();
318 	}
319 }
320 
321 //------------------------------------------------------------------------
attachedToParent()322 void EditorView::attachedToParent ()
323 {
324 	if (controller)
325 	{
326 		controller->editorAttached (this);
327 	}
328 }
329 
330 //------------------------------------------------------------------------
removedFromParent()331 void EditorView::removedFromParent ()
332 {
333 	if (controller)
334 	{
335 		controller->editorRemoved (this);
336 	}
337 }
338 #endif // NO_PLUGUI
339 
340 //------------------------------------------------------------------------
341 // EditControllerEx1 implementation
342 //------------------------------------------------------------------------
EditControllerEx1()343 EditControllerEx1::EditControllerEx1 () : selectedUnit (kRootUnitId)
344 {
345 	UpdateHandler::instance ();
346 }
347 
348 //------------------------------------------------------------------------
~EditControllerEx1()349 EditControllerEx1::~EditControllerEx1 ()
350 {
351 }
352 
353 //------------------------------------------------------------------------
terminate()354 tresult PLUGIN_API EditControllerEx1::terminate ()
355 {
356 	units.clear ();
357 
358 	for (const auto& programList : programLists)
359 	{
360 		if (programList)
361 			programList->removeDependent (this);
362 	}
363 	programLists.clear ();
364 	programIndexMap.clear ();
365 
366 	return EditController::terminate ();
367 }
368 
369 //------------------------------------------------------------------------
addUnit(Unit * unit)370 bool EditControllerEx1::addUnit (Unit* unit)
371 {
372 	units.emplace_back (unit, false);
373 	return true;
374 }
375 
376 //------------------------------------------------------------------------
getUnitInfo(int32 unitIndex,UnitInfo & info)377 tresult PLUGIN_API EditControllerEx1::getUnitInfo (int32 unitIndex, UnitInfo& info /*out*/)
378 {
379 	if (Unit* unit = units.at (unitIndex))
380 	{
381 		info = unit->getInfo ();
382 		return kResultTrue;
383 	}
384 	return kResultFalse;
385 }
386 
387 //------------------------------------------------------------------------
notifyUnitSelection()388 tresult EditControllerEx1::notifyUnitSelection ()
389 {
390 	tresult result = kResultFalse;
391 	FUnknownPtr<IUnitHandler> unitHandler (componentHandler);
392 	if (unitHandler)
393 		result = unitHandler->notifyUnitSelection (selectedUnit);
394 	return result;
395 }
396 
397 //------------------------------------------------------------------------
addProgramList(ProgramList * list)398 bool EditControllerEx1::addProgramList (ProgramList* list)
399 {
400 	programIndexMap[list->getID ()] = programLists.size ();
401 	programLists.emplace_back (list, false);
402 	list->addDependent (this);
403 	return true;
404 }
405 
406 //------------------------------------------------------------------------
getProgramList(ProgramListID listId) const407 ProgramList* EditControllerEx1::getProgramList (ProgramListID listId) const
408 {
409 	auto it = programIndexMap.find (listId);
410 	return it == programIndexMap.end () ? nullptr : programLists[it->second];
411 }
412 
413 //------------------------------------------------------------------------
notifyProgramListChange(ProgramListID listId,int32 programIndex)414 tresult EditControllerEx1::notifyProgramListChange (ProgramListID listId, int32 programIndex)
415 {
416 	tresult result = kResultFalse;
417 	FUnknownPtr<IUnitHandler> unitHandler (componentHandler);
418 	if (unitHandler)
419 		result = unitHandler->notifyProgramListChange (listId, programIndex);
420 	return result;
421 }
422 
423 //------------------------------------------------------------------------
getProgramListCount()424 int32 PLUGIN_API EditControllerEx1::getProgramListCount ()
425 {
426 	return static_cast<int32> (programLists.size ());
427 }
428 
429 //------------------------------------------------------------------------
getProgramListInfo(int32 listIndex,ProgramListInfo & info)430 tresult PLUGIN_API EditControllerEx1::getProgramListInfo (int32 listIndex,
431                                                           ProgramListInfo& info /*out*/)
432 {
433 	if (listIndex < 0 || listIndex >= static_cast<int32> (programLists.size ()))
434 		return kResultFalse;
435 	info = programLists[listIndex]->getInfo ();
436 	return kResultTrue;
437 }
438 
439 //------------------------------------------------------------------------
getProgramName(ProgramListID listId,int32 programIndex,String128 name)440 tresult PLUGIN_API EditControllerEx1::getProgramName (ProgramListID listId, int32 programIndex,
441                                                       String128 name /*out*/)
442 {
443 	ProgramIndexMap::const_iterator it = programIndexMap.find (listId);
444 	if (it != programIndexMap.end ())
445 	{
446 		return programLists[it->second]->getProgramName (programIndex, name);
447 	}
448 	return kResultFalse;
449 }
450 
451 //------------------------------------------------------------------------
setProgramName(ProgramListID listId,int32 programIndex,const String128 name)452 tresult EditControllerEx1::setProgramName (ProgramListID listId, int32 programIndex,
453                                            const String128 name /*in*/)
454 {
455 	ProgramIndexMap::const_iterator it = programIndexMap.find (listId);
456 	if (it != programIndexMap.end ())
457 	{
458 		return programLists[it->second]->setProgramName (programIndex, name);
459 	}
460 	return kResultFalse;
461 }
462 
463 //------------------------------------------------------------------------
getProgramInfo(ProgramListID listId,int32 programIndex,CString attributeId,String128 attributeValue)464 tresult PLUGIN_API EditControllerEx1::getProgramInfo (ProgramListID listId, int32 programIndex,
465                                                       CString attributeId /*in*/,
466                                                       String128 attributeValue /*out*/)
467 {
468 	ProgramIndexMap::const_iterator it = programIndexMap.find (listId);
469 	if (it != programIndexMap.end ())
470 	{
471 		return programLists[it->second]->getProgramInfo (programIndex, attributeId, attributeValue);
472 	}
473 	return kResultFalse;
474 }
475 
476 //------------------------------------------------------------------------
hasProgramPitchNames(ProgramListID listId,int32 programIndex)477 tresult PLUGIN_API EditControllerEx1::hasProgramPitchNames (ProgramListID listId,
478                                                             int32 programIndex)
479 {
480 	ProgramIndexMap::const_iterator it = programIndexMap.find (listId);
481 	if (it != programIndexMap.end ())
482 	{
483 		return programLists[it->second]->hasPitchNames (programIndex);
484 	}
485 	return kResultFalse;
486 }
487 
488 //------------------------------------------------------------------------
getProgramPitchName(ProgramListID listId,int32 programIndex,int16 midiPitch,String128 name)489 tresult PLUGIN_API EditControllerEx1::getProgramPitchName (ProgramListID listId, int32 programIndex,
490                                                            int16 midiPitch, String128 name /*out*/)
491 {
492 	ProgramIndexMap::const_iterator it = programIndexMap.find (listId);
493 	if (it != programIndexMap.end ())
494 	{
495 		return programLists[it->second]->getPitchName (programIndex, midiPitch, name);
496 	}
497 	return kResultFalse;
498 }
499 
500 //------------------------------------------------------------------------
update(FUnknown * changedUnknown,int32)501 void PLUGIN_API EditControllerEx1::update (FUnknown* changedUnknown, int32 /*message*/)
502 {
503 	auto* programList = FCast<ProgramList> (changedUnknown);
504 	if (programList)
505 	{
506 		FUnknownPtr<IUnitHandler> unitHandler (componentHandler);
507 		if (unitHandler)
508 			unitHandler->notifyProgramListChange (programList->getID (), kAllProgramInvalid);
509 	}
510 }
511 
512 //------------------------------------------------------------------------
513 // Unit implementation
514 //------------------------------------------------------------------------
Unit()515 Unit::Unit ()
516 {
517 	memset (&info, 0, sizeof (UnitInfo));
518 }
519 
520 //------------------------------------------------------------------------
Unit(const String128 name,UnitID unitId,UnitID parentUnitId,ProgramListID programListId)521 Unit::Unit (const String128 name, UnitID unitId, UnitID parentUnitId, ProgramListID programListId)
522 {
523 	setName (name);
524 	info.id = unitId;
525 	info.parentUnitId = parentUnitId;
526 	info.programListId = programListId;
527 }
528 
529 //------------------------------------------------------------------------
Unit(const UnitInfo & info)530 Unit::Unit (const UnitInfo& info) : info (info)
531 {
532 }
533 
534 //------------------------------------------------------------------------
setName(const String128 newName)535 void Unit::setName (const String128 newName)
536 {
537 	UString128 (newName).copyTo (info.name, 128);
538 }
539 
540 //------------------------------------------------------------------------
541 // ProgramList implementation
542 //------------------------------------------------------------------------
ProgramList(const String128 name,ProgramListID listId,UnitID unitId)543 ProgramList::ProgramList (const String128 name, ProgramListID listId, UnitID unitId)
544 : unitId (unitId), parameter (nullptr)
545 {
546 	UString128 (name).copyTo (info.name, 128);
547 	info.id = listId;
548 	info.programCount = 0;
549 }
550 
551 //------------------------------------------------------------------------
ProgramList(const ProgramList & programList)552 ProgramList::ProgramList (const ProgramList& programList)
553 : info (programList.info)
554 , unitId (programList.unitId)
555 , programNames (programList.programNames)
556 , parameter (nullptr)
557 {
558 }
559 
560 //------------------------------------------------------------------------
addProgram(const String128 name)561 int32 ProgramList::addProgram (const String128 name)
562 {
563 	++info.programCount;
564 	programNames.emplace_back (name);
565 	programInfos.emplace_back ();
566 	return static_cast<int32> (programNames.size ()) - 1;
567 }
568 
569 //------------------------------------------------------------------------
setProgramInfo(int32 programIndex,CString attributeId,const String128 value)570 bool ProgramList::setProgramInfo (int32 programIndex, CString attributeId, const String128 value)
571 {
572 	if (programIndex >= 0 && programIndex < static_cast<int32> (programNames.size ()))
573 	{
574 		programInfos.at (programIndex).insert (std::make_pair (attributeId, value));
575 		return true;
576 	}
577 	return false;
578 }
579 
580 //------------------------------------------------------------------------
getProgramInfo(int32 programIndex,CString attributeId,String128 value)581 tresult ProgramList::getProgramInfo (int32 programIndex, CString attributeId,
582                                      String128 value /*out*/)
583 {
584 	if (programIndex >= 0 && programIndex < static_cast<int32> (programNames.size ()))
585 	{
586 		StringMap::const_iterator it = programInfos[programIndex].find (attributeId);
587 		if (it != programInfos[programIndex].end ())
588 		{
589 			if (!it->second.isEmpty ())
590 			{
591 				it->second.copyTo16 (value, 0, 128);
592 				return kResultTrue;
593 			}
594 		}
595 	}
596 	return kResultFalse;
597 }
598 
599 //------------------------------------------------------------------------
getProgramName(int32 programIndex,String128 name)600 tresult ProgramList::getProgramName (int32 programIndex, String128 name /*out*/)
601 {
602 	if (programIndex >= 0 && programIndex < static_cast<int32> (programNames.size ()))
603 	{
604 		programNames.at (programIndex).copyTo16 (name, 0, 128);
605 		return kResultTrue;
606 	}
607 	return kResultFalse;
608 }
609 
610 //------------------------------------------------------------------------
setProgramName(int32 programIndex,const String128 name)611 tresult ProgramList::setProgramName (int32 programIndex, const String128 name /*in*/)
612 {
613 	if (programIndex >= 0 && programIndex < static_cast<int32> (programNames.size ()))
614 	{
615 		programNames.at (programIndex) = name;
616 		if (parameter)
617 		{
618 			static_cast<StringListParameter*> (parameter)->replaceString (programIndex, name);
619 		}
620 		return kResultTrue;
621 	}
622 	return kResultFalse;
623 }
624 
625 //------------------------------------------------------------------------
getParameter()626 Parameter* ProgramList::getParameter ()
627 {
628 	if (parameter == nullptr)
629 	{
630 		auto* listParameter = new StringListParameter (
631 			info.name, info.id, nullptr,
632 			ParameterInfo::kCanAutomate | ParameterInfo::kIsList | ParameterInfo::kIsProgramChange,
633 			unitId);
634 		for (const auto& programName : programNames)
635 		{
636 			listParameter->appendString (programName);
637 		}
638 		parameter = listParameter;
639 	}
640 	return parameter;
641 }
642 
643 //------------------------------------------------------------------------
644 // ProgramListWithPitchNames implementation
645 //-----------------------------------------------------------------------------
ProgramListWithPitchNames(const String128 name,ProgramListID listId,UnitID unitId)646 ProgramListWithPitchNames::ProgramListWithPitchNames (const String128 name, ProgramListID listId,
647                                                       UnitID unitId)
648 : ProgramList (name, listId, unitId)
649 {
650 }
651 
652 //-----------------------------------------------------------------------------
addProgram(const String128 name)653 int32 ProgramListWithPitchNames::addProgram (const String128 name)
654 {
655 	int32 index = ProgramList::addProgram (name);
656 	if (index >= 0)
657 		pitchNames.emplace_back ();
658 	return index;
659 }
660 
661 //-----------------------------------------------------------------------------
setPitchName(int32 programIndex,int16 pitch,const String128 pitchName)662 bool ProgramListWithPitchNames::setPitchName (int32 programIndex, int16 pitch,
663                                               const String128 pitchName)
664 {
665 	if (programIndex < 0 || programIndex >= getCount ())
666 		return false;
667 
668 	bool nameChanged = true;
669 	std::pair<PitchNameMap::iterator, bool> res =
670 	    pitchNames[programIndex].insert (std::make_pair (pitch, pitchName));
671 	if (!res.second)
672 	{
673 		if (res.first->second == pitchName)
674 			nameChanged = false;
675 		else
676 			res.first->second = pitchName;
677 	}
678 
679 	if (nameChanged)
680 		changed ();
681 	return true;
682 }
683 
684 //-----------------------------------------------------------------------------
removePitchName(int32 programIndex,int16 pitch)685 bool ProgramListWithPitchNames::removePitchName (int32 programIndex, int16 pitch)
686 {
687 	bool result = false;
688 	if (programIndex >= 0 && programIndex < getCount ())
689 	{
690 		result = pitchNames.at (programIndex).erase (pitch) != 0;
691 	}
692 	if (result)
693 		changed ();
694 	return result;
695 }
696 
697 //-----------------------------------------------------------------------------
hasPitchNames(int32 programIndex)698 tresult ProgramListWithPitchNames::hasPitchNames (int32 programIndex)
699 {
700 	if (programIndex >= 0 && programIndex < getCount ())
701 		return (pitchNames.at (programIndex).empty () == true) ? kResultFalse : kResultTrue;
702 	return kResultFalse;
703 }
704 
705 //-----------------------------------------------------------------------------
getPitchName(int32 programIndex,int16 midiPitch,String128 name)706 tresult ProgramListWithPitchNames::getPitchName (int32 programIndex, int16 midiPitch,
707                                                  String128 name /*out*/)
708 {
709 	if (programIndex >= 0 && programIndex < getCount ())
710 	{
711 		PitchNameMap::const_iterator it = pitchNames[programIndex].find (midiPitch);
712 		if (it != pitchNames[programIndex].end ())
713 		{
714 			it->second.copyTo16 (name, 0, 128);
715 			return kResultTrue;
716 		}
717 	}
718 	return kResultFalse;
719 }
720 
721 //------------------------------------------------------------------------
722 } // namespace Vst
723 } // namespace Steinberg
724