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