iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugVST3_ControllerBase.h
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
13#include "pluginterfaces/base/ibstream.h"
14#include "public.sdk/source/vst/vsteditcontroller.h"
15#include "pluginterfaces/vst/ivstchannelcontextinfo.h"
16
17#include "IPlugAPIBase.h"
18#include "IPlugVST3_Parameter.h"
19#include "IPlugVST3_Defs.h"
20
21#include "IPlugMidi.h"
22
23BEGIN_IPLUG_NAMESPACE
24
27{
28public:
29
30 IPlugVST3ControllerBase(Steinberg::Vst::ParameterContainer& parameters) : mParameters(parameters) {}
31
33 IPlugVST3ControllerBase& operator=(const IPlugVST3ControllerBase&) = delete;
34
35 void Initialize(IPlugAPIBase* pPlug, bool plugIsInstrument, bool midiIn)
36 {
37 Steinberg::Vst::EditControllerEx1* pEditController = dynamic_cast<Steinberg::Vst::EditControllerEx1*>(pPlug);
38
39 Steinberg::Vst::UnitInfo unitInfo;
40 unitInfo.id = Steinberg::Vst::kRootUnitId;
41 unitInfo.parentUnitId = Steinberg::Vst::kNoParentUnitId;
42 Steinberg::UString unitNameSetter(unitInfo.name, 128);
43 unitNameSetter.fromAscii("Root");
44
45 Steinberg::Vst::UnitID unitID = Steinberg::Vst::kRootUnitId;
46
47 #ifdef VST3_PRESET_LIST
48 if (pPlug->NPresets())
49 {
50 unitInfo.programListId = kPresetParam;
51 mParameters.addParameter(new IPlugVST3PresetParameter(pPlug->NPresets()));
52
53 Steinberg::Vst::ProgramListWithPitchNames* pList = new Steinberg::Vst::ProgramListWithPitchNames(STR16("Factory Presets"), 0 /* list id */, Steinberg::Vst::kRootUnitId);
54
55 Steinberg::Vst::String128 programName;
56 Steinberg::Vst::String128 pitchName;
57
58 for (int programIdx=0; programIdx<pPlug->NPresets(); programIdx++)
59 {
60 Steinberg::UString(programName, str16BufferSize(Steinberg::Vst::String128)).assign(pPlug->GetPresetName(programIdx));
61 pList->addProgram (programName);
62
63 //Set named notes. This could be different per-preset in VST3
64 for (int pitch = 0; pitch < 128; pitch++)
65 {
66 char pNoteText[32] = "";
67 if(pPlug->GetMidiNoteText(pitch, pNoteText))
68 {
69 Steinberg::UString(pitchName, str16BufferSize(Steinberg::Vst::String128)).assign(pNoteText);
70 pList->setPitchName(programIdx, pitch, pitchName);
71 }
72 }
73 }
74
75 pEditController->addProgramList(pList);
76 }
77 else
78 #endif
79 unitInfo.programListId = Steinberg::Vst::kNoProgramListId;
80
81 if (!plugIsInstrument)
82 mParameters.addParameter(mBypassParameter = new IPlugVST3BypassParameter());
83
84 pEditController->addUnit(new Steinberg::Vst::Unit(unitInfo));
85
86 for (int i = 0; i < pPlug->NParams(); i++)
87 {
88 IParam* pParam = pPlug->GetParam(i);
89 unitID = Steinberg::Vst::kRootUnitId; // reset unitID
90
91 const char* paramGroupName = pParam->GetGroup();
92
93 if (CStringHasContents(paramGroupName)) // if the parameter has a group
94 {
95 for (int j = 0; j < pPlug->NParamGroups(); j++) // loop through previously added groups
96 {
97 if (strcmp(paramGroupName, pPlug->GetParamGroupName(j)) == 0) // if group name found in existing groups
98 {
99 unitID = j + 1; // increment unitID
100 }
101 }
102
103 if (unitID == Steinberg::Vst::kRootUnitId) // if unitID was still kRootUnitId, we found a new group, so add it and add the unit
104 {
105 unitID = pPlug->AddParamGroup(paramGroupName); // updates unitID
106 unitInfo.id = unitID;
107 unitInfo.parentUnitId = Steinberg::Vst::kRootUnitId;
108 unitInfo.programListId = Steinberg::Vst::kNoProgramListId;
109 unitNameSetter.fromAscii(paramGroupName);
110 pEditController->addUnit (new Steinberg::Vst::Unit (unitInfo));
111 }
112 }
113
114 Steinberg::Vst::Parameter* pVST3Parameter = new IPlugVST3Parameter(pParam, i, unitID);
115 mParameters.addParameter(pVST3Parameter);
116 }
117
118 assert(VST3_NUM_CC_CHANS <= VST3_NUM_MIDI_IN_CHANS && "VST3_NUM_CC_CHANS must be less than or equal to VST3_NUM_MIDI_IN_CHANS");
119
120#if VST3_NUM_CC_CHANS > 0
121 if (midiIn)
122 {
123 unitInfo.id = unitID = pEditController->getUnitCount() + 1;
124 unitInfo.parentUnitId = Steinberg::Vst::kRootUnitId;
125 unitInfo.programListId = Steinberg::Vst::kNoProgramListId;
126 unitNameSetter.fromAscii(VST3_CC_UNITNAME);
127 pEditController->addUnit(new Steinberg::Vst::Unit(unitInfo));
128
129 Steinberg::Vst::ParamID paramIdx = kMIDICCParamStartIdx;
130
131 WDL_String chanGroupStr;
132 Steinberg::Vst::UnitID midiCCsUnitID = unitID;
133
134 for (int chan = 0; chan < VST3_NUM_CC_CHANS; chan++)
135 {
136 chanGroupStr.SetFormatted(32, "CH%i", chan + 1);
137
138 unitInfo.id = unitID = pEditController->getUnitCount() + 1;
139 unitInfo.parentUnitId = midiCCsUnitID;
140 unitInfo.programListId = Steinberg::Vst::kNoProgramListId;
141 unitNameSetter.fromAscii(chanGroupStr.Get());
142 pEditController->addUnit(new Steinberg::Vst::Unit(unitInfo));
143 // add 128 MIDI CCs
144 Steinberg::Vst::String128 paramName;
145 for (int i = 0; i < 128; i++)
146 {
147 Steinberg::UString(paramName, str16BufferSize(Steinberg::Vst::String128)).assign(IMidiMsg::CCNameStr(i));
148 mParameters.addParameter(paramName, STR16(""), 0, 0, 0, paramIdx++, unitID);
149 }
150
151 mParameters.addParameter(STR16("Channel Aftertouch"), STR16(""), 0, 0, 0, paramIdx++, unitID);
152 mParameters.addParameter(STR16("Pitch Bend"), STR16(""), 0, 0.5, 0, paramIdx++, unitID);
153 }
154 }
155#endif
156 }
157
158 Steinberg::tresult PLUGIN_API GetProgramName(IPlugAPIBase* pPlug, Steinberg::Vst::ProgramListID listId, Steinberg::int32 programIndex, Steinberg::Vst::String128 name)
159 {
160 if (pPlug->NPresets() && listId == kPresetParam)
161 {
162 Steinberg::UString(name, 128).fromAscii(pPlug->GetPresetName(programIndex));
163 return Steinberg::kResultTrue;
164 }
165
166 return Steinberg::kResultFalse;
167 }
168
169 Steinberg::int32 PLUGIN_API GetProgramListCount(IPlugAPIBase* pPlug)
170 {
171#ifdef VST3_PRESET_LIST
172 return (pPlug->NPresets() > 0);
173#else
174 return 0;
175#endif
176 }
177
178 Steinberg::tresult PLUGIN_API GetProgramListInfo(IPlugAPIBase* pPlug, Steinberg::int32 listIndex, Steinberg::Vst::ProgramListInfo& info)
179 {
180#ifdef VST3_PRESET_LIST
181 if (listIndex == 0 && pPlug->NPresets() > 0)
182 {
183 info.id = kPresetParam;
184 info.programCount = (Steinberg::int32) pPlug->NPresets();
185 Steinberg::UString name(info.name, 128);
186 name.fromAscii("Factory Presets");
187 return Steinberg::kResultTrue;
188 }
189#endif
190
191 return Steinberg::kResultFalse;
192 }
193
194 Steinberg::Vst::ParamValue GetParamNormalized(Steinberg::Vst::ParamID tag)
195 {
196 Steinberg::Vst::Parameter* parameter = mParameters.getParameter(tag);
197 return parameter ? parameter->getNormalized() : 0.0;
198 }
199
200 bool SetParamNormalized(IPlugAPIBase* pPlug, Steinberg::Vst::ParamID tag, Steinberg::Vst::ParamValue value)
201 {
202 if (!SetVST3ParamNormalized(tag, value))
203 return false;
204
205 if (tag >= kBypassParam)
206 {
207 switch (tag)
208 {
209 case kPresetParam:
210 {
211 pPlug->RestorePreset(std::round((pPlug->NPresets() - 1) * value));
212 break;
213 }
214 default:
215 break;
216 }
217 }
218 else
219 {
220 IParam* pParam = pPlug->GetParam(tag);
221
222 if (pParam)
223 {
224 pParam->SetNormalized(value);
225 pPlug->OnParamChangeUI(tag, kHost);
226 pPlug->SendParameterValueFromDelegate(tag, value, true);
227 }
228 }
229
230 return true;
231 }
232
233 bool SetChannelContextInfos(Steinberg::Vst::IAttributeList* pList)
234 {
235 using namespace Steinberg;
236 using namespace Vst;
237
238 if (pList)
239 {
240 // optional we can ask for the channel name length
241 int64 length;
242 if (pList->getInt(ChannelContext::kChannelNameLengthKey, length) == kResultTrue)
243 {
244 // get the channel name where we, as plug-in, are instantiated
245 // Note: length is multiplied by two because Ableton Live 10.1.13 is buggy
246 // and pList->getString() size parameter is interpreted as TChar instead
247 // of byte: end of string zero value is written in an out of memory position
248 std::vector<TChar> name((length+1)*2);
249 if (pList->getString(ChannelContext::kChannelNameKey, name.data(), static_cast<Steinberg::uint32>(length+1)*sizeof(TChar)) == kResultTrue)
250 {
251 Steinberg::String str(name.data());
252 str.toMultiByte(kCP_Utf8);
253 mChannelName.Set(str);
254 }
255 }
256
257 // get the channel uid namespace length
258 if (pList->getInt(ChannelContext::kChannelUIDLengthKey, length) == kResultTrue)
259 {
260 // get the channel UID
261 // Note: length is multiplied by two because Ableton Live 10.1.13 is buggy
262 // and pList->getString() size parameter is interpreted as TChar instead
263 // of byte: end of string zero value is written in an out of memory position
264 std::vector<TChar> name((length+1)*2);
265 if (pList->getString(ChannelContext::kChannelUIDKey, name.data(), static_cast<Steinberg::uint32>(length+1)*sizeof(TChar)) == kResultTrue)
266 {
267 Steinberg::String str(name.data());
268 str.toMultiByte(kCP_Utf8);
269 mChannelUID.Set(str);
270 }
271 }
272
273 // get channel index
274 int64 index;
275 if (pList->getInt(ChannelContext::kChannelIndexKey, index) == kResultTrue)
276 {
277 mChannelIndex = static_cast<int>(index);
278 }
279
280 // get the channel color
281 int64 color;
282 if (pList->getInt(ChannelContext::kChannelColorKey, color) == kResultTrue)
283 {
284 mChannelColor = (uint32) color;
285 }
286
287 // get channel index namespace order of the current used index namespace
288 if (pList->getInt(ChannelContext::kChannelIndexNamespaceOrderKey, index) == kResultTrue)
289 {
290 mChannelNamespaceIndex = static_cast<int>(index);
291 }
292
293 // get the channel index namespace length
294 if (pList->getInt(ChannelContext::kChannelIndexNamespaceLengthKey, length) == kResultTrue)
295 {
296 // get the channel index namespace
297 // Note: length is multiplied by two because Ableton Live 10.1.13 is buggy
298 // and pList->getString() size parameter is interpreted as TChar instead
299 // of byte: end of string zero value is written in an out of memory position
300 std::vector<TChar> name((length+1)*2);
301 if (pList->getString(ChannelContext::kChannelIndexNamespaceKey, name.data(), static_cast<Steinberg::uint32>(length+1)*sizeof(TChar)) == kResultTrue)
302 {
303 Steinberg::String str(name.data());
304 str.toMultiByte(kCP_Utf8);
305 mChannelNamespace.Set(str);
306 }
307 }
308
309 // get plug-in channel location
310 int64 location;
311 if (pList->getInt(ChannelContext::kChannelPluginLocationKey, location) == kResultTrue)
312 {
313 String128 string128;
314 switch (location)
315 {
316 case ChannelContext::kPreVolumeFader:
317 Steinberg::UString(string128, 128).fromAscii("PreVolFader");
318 break;
319 case ChannelContext::kPostVolumeFader:
320 Steinberg::UString(string128, 128).fromAscii("PostVolFader");
321 break;
322 case ChannelContext::kUsedAsPanner:
323 Steinberg::UString(string128, 128).fromAscii("UsedAsPanner");
324 break;
325 default: Steinberg::UString(string128, 128).fromAscii("unknown!");
326 break;
327 }
328 }
329
330 return true;
331 }
332
333 return false;
334 }
335
336 void UpdateParams(IPlugAPIBase* pPlug, int savedBypass)
337 {
338 for (int i = 0; i < pPlug->NParams(); i++)
339 {
340 double normalized = pPlug->GetParam(i)->GetNormalized();
341 mParameters.getParameter(i)->setNormalized(normalized);
342 }
343
344 if (mBypassParameter)
345 mBypassParameter->setNormalized(savedBypass);
346 }
347
348protected:
349
350 bool SetVST3ParamNormalized(Steinberg::Vst::ParamID tag, Steinberg::Vst::ParamValue value)
351 {
352 Steinberg::Vst::Parameter* parameter = mParameters.getParameter(tag);
353
354 if (!parameter)
355 return false;
356
357 parameter->setNormalized(value);
358 return true;
359 }
360
361public:
362 Steinberg::Vst::ParameterContainer& mParameters;
363 IPlugVST3BypassParameter* mBypassParameter = nullptr;
364
365 // ChannelContext::IInfoListener
366 WDL_String mChannelName;
367 WDL_String mChannelNamespace;
368 WDL_String mChannelUID;
369 int mChannelNamespaceIndex = 0;
370 int mChannelIndex = 0;
371 unsigned int mChannelColor = 0;
372};
373
374END_IPLUG_NAMESPACE
MIDI and sysex structs/utilites.
IPlug's parameter class.
void SetNormalized(double normalizedValue)
Sets the parameter value from a normalized range (usually coming from the linked IControl)
const char * GetGroup() const
Returns the parameter's group.
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
Definition: IPlugAPIBase.h:43
virtual bool GetMidiNoteText(int noteNumber, char *str) const
Override this method to provide custom text linked to MIDI note numbers in API classes that support t...
Definition: IPlugAPIBase.h:96
VST3 bypass parameter helper.
Shared VST3 controller code.
VST3 preset parameter helper.
int AddParamGroup(const char *name)
Called to add a parameter group name, when a unique group name is discovered.
bool RestorePreset(int idx)
Restore a preset by index.
const char * GetParamGroupName(int idx) const
Get the parameter group name as a particular index.
const char * GetPresetName(int idx) const
Get the name a preset.
int NPresets() const
Gets the number of factory presets.
int NParamGroups() const
static const char * CCNameStr(int idx)
Get the CC name as a CString.
Definition: IPlugMidi.h:386