vestige.cpp 26.9 KB
Newer Older
1
2
3
4
/**
 * @file VST2 Implementation. Its hard to find Doku and examples for it. It is
 * also deprecated, so maybe other formats are more important.
 */
5
#include "interfaces/IPlugin.hpp"
6
#include "vst_def.hpp"
Benjamin Heisch's avatar
Benjamin Heisch committed
7

8
#include <GlobalData.hpp>
9
10
#include <algorithm>
#include <cstring>
11
#include <interfaces/IPlugin.hpp>
Benjamin Heisch's avatar
Benjamin Heisch committed
12
#include <tools/PortHandling.hpp>
13
using namespace XPlug;
14

Benjamin Heisch's avatar
Benjamin Heisch committed
15
/**
16
17
18
 * @brief Struct for  use in the vst2 implementation. This struct is stored in
 * the AEffect->user pointer. So it can be casted to this struct. If the VST2
 * implementation needs to hold implementationData, pack it in here.
Benjamin Heisch's avatar
Benjamin Heisch committed
19
 */
20
21
22
23
struct VST2ImplementationData
{
  audioMasterCallback audioMaster;
  IPlugin* plug;
Benjamin Heisch's avatar
Benjamin Heisch committed
24
};
25

26
27
28
static intptr_t
vst_dispatcher(AEffect* effect,
               int32_t opcode,
29
               int32_t, // index
30
31
               intptr_t value,
               void* ptr,
32
               float) // opt
33
{
34
35
  auto data = static_cast<VST2ImplementationData*>(effect->user);
  switch (opcode) {
36
    case effOpen: ///< no arguments  @see AudioEffect::open
37
38
39
40
41
42
43
      data->plug->init();
      if (data->plug->getFeatureComponent()->supportsFeature(
            Feature::MidiInput) &&
          data->audioMaster)
        data->audioMaster(
          effect, audioMasterWantMidi, 0, 1, 0, 0); // legacy handling
      break;
44
    case effClose: ///< no arguments  @see AudioEffect::open
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
      data->plug->deinit();
      break;
      /*  case effSetProgram: ///< [value]: new program number  @see
        AudioEffect::setProgram break; case effGetProgram: ///< [return value]:
        current program number  @see AudioEffect::getProgram break; case
        effSetProgramName: ///< [ptr]: char* with new program name, limited to
        #kVstMaxProgNameLen  @see AudioEffect::setProgramName break; case
        effGetProgramName: ///< [ptr]: char buffer for current program name,
        limited to #kVstMaxProgNameLen  @see AudioEffect::getProgramName break;
        case effGetParamLabel: ///< [ptr]: char buffer for parameter label,
        limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterLabel
            break;
        case effGetParamDisplay: ///< [ptr]: char buffer for parameter display,
        limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterDisplay
            break;
        case effGetParamName: ///< [ptr]: char buffer for parameter name,
        limited to #kVstMaxParamStrLen  @see AudioEffect::getParameterName
            break;
        case effSetSampleRate: ///< [opt]: new sample rate for audio processing
        @see AudioEffect::setSampleRate break; case effSetBlockSize: ///<
        [value]: new maximum block size for audio processing  @see
        AudioEffect::setBlockSize break;*/
    case effMainsChanged: ///< [value]: 0 means "turn off", 1 means "turn on"
                          ///< @see AudioEffect::suspend @see
                          ///< AudioEffect::resume
      if (value == 0)
        data->plug->deactivate();
      else
        data->plug->activate();
      break;
      /*  case effEditGetRect: ///< [ptr]: #ERect** receiving pointer to editor
        size  @see ERect @see AEffEditor::getRect break; case effEditOpen: ///<
        [ptr]: system dependent Window pointer, e.g. HWND on Windows  @see
        AEffEditor::open break; case effEditClose: ///< no arguments @see
        AEffEditor::close break; case effEditIdle: ///< no arguments @see
        AEffEditor::idle break; case effGetChunk: ///< [ptr]: void** for chunk
        implementationData address [index]: 0 for bank, 1 for program  @see
        AudioEffect::getChunk break; case effSetChunk: ///< [ptr]: chunk
        implementationData [value]: byte size [index]: 0 for bank, 1 for program
        @see AudioEffect::setChunk break;*/
85

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
      /**************************EXTENDING
       * OPCODES*******************************/
    case effProcessEvents: ///< [ptr]: #VstEventsVstEvents*  @see
                           ///< AudioEffectX::processEvents = effSetChunk + 1
                           ///< ///< [ptr]: #VstEvents*  @see
                           ///< AudioEffectX::processEventsdes:
      if (data->plug->getFeatureComponent()->supportsFeature(
            Feature::MidiInput)) {
        auto events = (VstEvents*)ptr;
        if (events->numEvents == 0)
          break;
        for (int i = 0, count = events->numEvents; i < count; ++i) {
          auto midiEvent = (const VstMidiEvent*)events->events[i];
          if (midiEvent != nullptr && midiEvent->type == kVstMidiType) {
            auto midiPort =
              getPortAt<IMidiPort>(data->plug, 0, PortDirection::Input);
            if (midiPort != nullptr)
              midiPort->feed(
                MidiMessage{ static_cast<uint8_t>(midiEvent->midiData[0]),
                             static_cast<uint8_t>(midiEvent->midiData[1]),
                             static_cast<uint8_t>(midiEvent->midiData[2]) });
          }
        }
      }
      break;
      /*   case effCanBeAutomated: ///< [index]: parameter index [return value]:
         1=true, 0=false  @see AudioEffectX::canParameterBeAutomated break; case
         effString2Parameter: ///< [index]: parameter index [ptr]: parameter
         string [return value]: true for success  @see
         AudioEffectX::string2parameter break; case effGetProgramNameIndexed:
         ///< [index]: program index [ptr]: buffer for program name, limited to
         #kVstMaxProgNameLen [return value]: true for success  @see
         AudioEffectX::getProgramNameIndexed break; case effGetInputProperties:
         ///< [index]: input index [ptr]: #VstPinProperties* [return value]: 1
         if supported  @see AudioEffectX::getInputProperties break; case
         effGetOutputProperties: ///< [index]: output index [ptr]:
         #VstPinProperties* [return value]: 1 if supported  @see
         AudioEffectX::getOutputProperties break; case effGetPlugCategory: ///<
         [return value]: category  @see VstPlugCategory @see
         AudioEffectX::getPlugCategory break; case effOfflineNotify: ///< [ptr]:
         #VstAudioFile array [value]: count [index]: start flag  @see
         AudioEffectX::offlineNotify break; case effOfflinePrepare: ///< [ptr]:
         #VstOfflineTask array [value]: count  @see AudioEffectX::offlinePrepare
             break;
         case effOfflineRun: ///< [ptr]: #VstOfflineTask array [value]: count
         @see AudioEffectX::offlineRun break;
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
         case effProcessVarIo: ///< [ptr]: #VstVariableIo*  @see
         AudioEffectX::processVariableIo break;*/
    case effSetSpeakerArrangement: ///< [value]: input #VstSpeakerArrangement*
                                   ///< [ptr]: output #VstSpeakerArrangement*
                                   ///< @see AudioEffectX::setSpeakerArrangement
      if (getNumberOfPorts<IAudioPort>(data->plug, PortDirection::Input) == 0 ||
          getNumberOfPorts<IAudioPort>(data->plug, PortDirection::Output) == 0)
        return 0;
      return reinterpret_cast<VstSpeakerArrangement*>(value)->numChannels ==
               (int32_t)getPortAt<IAudioPort>(
                 data->plug, 0, PortDirection::Input)
                 ->size() &&
             reinterpret_cast<VstSpeakerArrangement*>(ptr)->numChannels ==
               (int32_t)getPortAt<IAudioPort>(
                 data->plug, 0, PortDirection::Output)
                 ->size();
      break;
    case effSetBypass: ///< [value]: 1 = bypass, 0 = no bypass  @see
                       ///< AudioEffectX::setBypass
      break;
    case effGetEffectName: ///< [ptr]: buffer for effect name, limited to
                           ///< #kVstMaxEffectNameLen  @see
                           ///< AudioEffectX::getEffectName
      break;
    case effGetVendorString: ///< [ptr]: buffer for effect vendor string,
                             ///< limited to #kVstMaxVendorStrLen  @see
                             ///< AudioEffectX::getVendorString
      strncpy(static_cast<char*>(ptr),
              data->plug->getInfoComponent()->getCreatorName().data(),
              std::min<size_t>(
                data->plug->getInfoComponent()->getCreatorName().size(),
                kVstMaxVendorStrLen));
      return true;
    case effGetProductString: ///< [ptr]: buffer for effect vendor string,
                              ///< limited to #kVstMaxProductStrLen  @see
                              ///< AudioEffectX::getProductString
      strncpy(
        static_cast<char*>(ptr),
        data->plug->getInfoComponent()->getPluginName().data(),
        std::min<size_t>(data->plug->getInfoComponent()->getPluginName().size(),
                         kVstMaxProductStrLen));
      return true;
    case effGetVendorVersion: ///< [return value]: vendor-specific version  @see
                              ///< AudioEffectX::getVendorVersion
      break;
    case effVendorSpecific: ///< no definition, vendor specific handling  @see
                            ///< AudioEffectX::vendorSpecific
      break;
    case effCanDo: ///< [ptr]: "can do" string [return value]: 0: "don't know"
                   ///< -1: "no" 1: "yes"  @see
                   ///< AudioEffectX::canDo//strcmp((const char*)ptr,
                   ///< "dididing");
Benjamin Heisch's avatar
Benjamin Heisch committed
185
    {
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
      static const auto boolToCando = [](bool val) { return val ? 1 : -1; };
      auto canDo = static_cast<const char*>(ptr);
      if (std::strcmp(canDo, "receiveVstEvents") ==
            0 ///< plug-in can receive MIDI events from Host
          || std::strcmp(canDo, "receiveVstMidiEvent") ==
               0) ///< plug-in can receive MIDI events from Host
        return boolToCando(data->plug->getFeatureComponent()->supportsFeature(
          Feature::MidiInput));
      else if (std::strcmp(canDo, "sendVstEvents") ==
                 0 ///< plug-in will send Vst events to Host
               || std::strcmp(canDo, "sendVstMidiEvent") ==
                    0) ///< plug-in will send MIDI events to Host
        return boolToCando(data->plug->getFeatureComponent()->supportsFeature(
          Feature::MidiOutput));
      else if (std::strcmp(canDo, "receiveVstTimeInfo") ==
               0) ///< plug-in can receive Time info from Host
        return 0;
      else if (std::strcmp(canDo, "offline") ==
               0) ///< plug-in supports offline functions (#offlineNotify,
                  ///< #offlinePrepare, #offlineRun)
        return -1;
      else if (std::strcmp(canDo, "midiProgramNames") ==
               0) ///< plug-in supports function #getMidiProgramName ()
        return -1;
      else if (std::strcmp(canDo, "bypass") ==
               0) ///< plug-in supports function #setBypass ()
        return -1;
      return 0; // return that you absolutly dont know, how to handle the
                // requested feature.
Benjamin Heisch's avatar
Benjamin Heisch committed
215
    }
216
217
218
219
220
221
222
223
224
    case effGetTailSize: ///< [return value]: tail size (for example the reverb
                         ///< time of a reverb plug-in); 0 is default (return 1
                         ///< for 'no tail')
      return 1;
      /*    case effGetParameterProperties: ///< [index]: parameter index [ptr]:
         #VstParameterProperties* [return value]: 1 if supported  @see
         AudioEffectX::getParameterProperties break; case effGetVstVersion: ///<
         [return value]: VST version  @see AudioEffectX::getVstVersion return
         kVstVersion;
225

226
227
228
229
230
231
232
233
              //#if VST_2_1_EXTENSIONS
          case effEditKeyDown: ///< [index]: ASCII character [value]: virtual
         key [opt]: modifiers [return value]: 1 if key used  @see
         AEffEditor::onKeyDown break; case effEditKeyUp: ///< [index]: ASCII
         character [value]: virtual key [opt]: modifiers [return value]: 1 if
         key used  @see AEffEditor::onKeyUp break; case effSetEditKnobMode: ///<
         [value]: knob mode 0: circular, 1: circular relativ, 2: linear
         (CKnobMode in VSTGUI)  @see AEffEditor::setKnobMode break;
234

235
236
237
238
239
240
241
242
243
244
245
246
247
248
          case effGetMidiProgramName: ///< [index]: MIDI channel [ptr]:
         #MidiProgramName* [return value]: number of used programs, 0 if
         unsupported  @see AudioEffectX::getMidiProgramName break; case
         effGetCurrentMidiProgram: ///< [index]: MIDI channel [ptr]:
         #MidiProgramName* [return value]: index of current program  @see
         AudioEffectX::getCurrentMidiProgram break; case
         effGetMidiProgramCategory: ///< [index]: MIDI channel [ptr]:
         #MidiProgramCategory* [return value]: number of used categories, 0 if
         unsupported  @see AudioEffectX::getMidiProgramCategory break; case
         effHasMidiProgramsChanged: ///< [index]: MIDI channel [return value]: 1
         if the #MidiProgramName(s) or #MidiKeyName(s) have changed  @see
         AudioEffectX::hasMidiProgramsChanged break; case effGetMidiKeyName:
         ///< [index]: MIDI channel [ptr]: #MidiKeyName* [return value]: true if
         supported, false otherwise  @see AudioEffectX::getMidiKeyName break;
249

250
251
252
253
          case effBeginSetProgram: ///< no arguments  @see
         AudioEffectX::beginSetProgram break; case effEndSetProgram: ///< no
         arguments  @see AudioEffectX::endSetProgram break;
              //#endif // VST_2_1_EXTENSIONS
254

255
256
257
258
259
260
261
262
263
264
              //#if VST_2_3_EXTENSIONS
          case effGetSpeakerArrangement: ///< [value]: input
         #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement*  @see
         AudioEffectX::getSpeakerArrangement
              // IMplement changing of Inputconfiguration here.
              return false;
              break;
          case effShellGetNextPlugin: ///< [ptr]: buffer for plug-in name,
         limited to #kVstMaxProductStrLen [return value]: next plugin's uniqueID
         @see AudioEffectX::getNextShellPlugin break;
265

266
267
268
269
270
271
272
          case effStartProcess: ///< no arguments  @see
         AudioEffectX::startProcess break; case effStopProcess: ///< no
         arguments  @see AudioEffectX::stopProcess break; case
         effSetTotalSampleToProcess: ///< [value]: number of samples to process,
         offline only!  @see AudioEffectX::setTotalSampleToProcess break; case
         effSetPanLaw: ///< [value]: pan law [opt]: gain  @see VstPanLawType
         @see AudioEffectX::setPanLaw break;
273

274
275
276
277
278
279
280
          case effBeginLoadBank: ///< [ptr]: #VstPatchChunkInfo* [return value]:
         -1: bank can't be loaded, 1: bank can be loaded, 0: unsupported  @see
         AudioEffectX::beginLoadBank break; case effBeginLoadProgram: ///<
         [ptr]: #VstPatchChunkInfo* [return value]: -1: prog can't be loaded, 1:
         prog can be loaded, 0: unsupported  @see AudioEffectX::beginLoadProgram
              break;
              //#endif // VST_2_3_EXTENSIONS
281

282
283
284
285
286
287
288
289
290
291
292
293
              //#if VST_2_4_EXTENSIONS
          case effSetProcessPrecision: ///< [value]: @see VstProcessPrecision
         @see AudioEffectX::setProcessPrecision break; case
         effGetNumMidiInputChannels: ///< [return value]: number of used MIDI
         input channels (1-15)  @see AudioEffectX::getNumMidiInputChannels
              break;
          case effGetNumMidiOutputChannels: ///< [return value]: number of used
         MIDI output channels (1-15)  @see
         AudioEffectX::getNumMidiOutputChannels break;*/
      //#endif // VST_2_4_EXTENSIONS
  }
  return 0;
294
}
Benjamin Heisch's avatar
Benjamin Heisch committed
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
void
writeMidiOutput(AEffect* effect)
{
  auto data = static_cast<VST2ImplementationData*>(effect->user);
  if (data->plug->getFeatureComponent()->supportsFeature(Feature::MidiOutput)) {
    iteratePorts<IMidiPort>(
      data->plug,
      PortDirection::Output,
      [&data, &effect](IMidiPort* p, size_t ind) {
        while (!p->empty()) {
          auto midiMsg = p->get();
          VstMidiEvent vstMidiEvent{ kVstMidiType,
                                     sizeof(VstMidiEvent),
                                     0,
                                     0,
                                     0,
                                     0,
                                     { static_cast<char>(midiMsg[0]),
                                       static_cast<char>(midiMsg[1]),
                                       static_cast<char>(midiMsg[2]),
                                       0 },
                                     0,
                                     0,
                                     0,
                                     0 };
          VstEvents vstEvents{ 1, 0, (VstEvent*)&vstMidiEvent };
          data->audioMaster(effect,
                            audioMasterProcessEvents,
                            static_cast<int32_t>(ind),
                            0,
                            &vstEvents,
                            0);
        }
        return false;
      });
  }
Benjamin Heisch's avatar
Benjamin Heisch committed
332
333
334
}

audioMasterCallback globalAudioMaster;
335
#include <iostream>
336
// -----------------------------------------------------------------------
337
extern "C"
338
{
339
340
  const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  {
Benjamin Heisch's avatar
Benjamin Heisch committed
341
342
    globalAudioMaster = audioMaster;

343
    // PluginController plugin = GlobalData().getPlugin(0);
344
345
    // old version
    if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
346
      return nullptr;
347
348
349
    // first internal init
    //  vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f);
    AEffect* const effect(new AEffect);
350
351
    VST2ImplementationData* const implementationData(
      new VST2ImplementationData);
352
353
354
    implementationData->audioMaster = audioMaster;
    implementationData->plug = GlobalData().getPlugin(0).get();
    effect->user = implementationData;
355
356
    // std::memset(effect, 0, sizeof(AEffect));
    effect->magic = kEffectMagic;
Benjamin Heisch's avatar
Benjamin Heisch committed
357
    effect->dispatcher = vst_dispatcher;
358
359

    /******************INFORMATION*****************/
360
    effect->uniqueID = implementationData->plug->getInfoComponent()->getID();
361
    effect->version = 0;
362
363
364
365
    effect->numInputs = static_cast<int>(getNumberOfPorts<IAudioPort>(
      implementationData->plug, PortDirection::Input));
    effect->numOutputs = static_cast<int>(getNumberOfPorts<IAudioPort>(
      implementationData->plug, PortDirection::Output));
366
367
    effect->numParams = 0;
    effect->numPrograms = 0;
368

369
    // Do something with the audiomaster. Maybe support it later.
Benjamin Heisch's avatar
Benjamin Heisch committed
370
371
372
    if (audioMaster) {

      /*  //OPCodes
373
374
375
376
377
378
379
380
381
382
383
384
385
386
        audioMaster(nullptr, audioMasterAutomate, 0, 0, nullptr, 0.0f);///<
        [index]: parameter index [opt]: parameter value  @see
        AudioEffect::setParameterAutomated audioMaster(nullptr,
        audioMasterVersion, 0, 0, nullptr, 0.0f);///< [return value]: Host VST
        version (for example 2400 for VST 2.4) @see
        AudioEffect::getMasterVersion audioMaster(nullptr, audioMasterCurrentId,
        0, 0, nullptr, 0.0f);///< [return value]: current unique identifier on
        shell plug-in  @see AudioEffect::getCurrentUniqueId audioMaster(nullptr,
        audioMasterIdle, 0, 0, nullptr, 0.0f);	///< no arguments  @see
        AudioEffect::masterIdle audioMaster(nullptr, audioMasterPinConnected, 0,
        0, nullptr, 0.0f);///< [return value]: 0=true, 1=false [index]: pin
        index [value]: 0=input, 1=output  @see AudioEffect::isInputConnected
        @see AudioEffect::isOutputConnected

Benjamin Heisch's avatar
Benjamin Heisch committed
387
388

        //OPCodes 2.X
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
        audioMaster(nullptr, audioMasterGetTime, 0, 0, nullptr, 0);///< [return
        value]: #VstTimeInfo* or null if not supported [value]: request mask
        @see VstTimeInfoFlags @see AudioEffectX::getTimeInfo
        audioMaster(nullptr, audioMasterProcessEvents, 0, 0, nullptr, 0);///<
        [ptr]: pointer to #VstEvents  @see VstEvents @see
        AudioEffectX::sendVstEventsToHost audioMaster(nullptr,
        audioMasterIOChanged, 0, 0, nullptr, 0);///< [return value]: 1 if
        supported  @see AudioEffectX::ioChanged audioMaster(nullptr,
        audioMasterSizeWindow, 0, 0, nullptr, 0);	///< [index]: new width
        [value]: new height [return value]: 1 if supported  @see
        AudioEffectX::sizeWindow audioMaster(nullptr, audioMasterGetSampleRate,
        0, 0, nullptr, 0);///< [return value]: current sample rate  @see
        AudioEffectX::updateSampleRate audioMaster(nullptr,
        audioMasterGetBlockSize, 0, 0, nullptr, 0);	///< [return value]:
        current block size  @see AudioEffectX::updateBlockSize
        audioMaster(nullptr, audioMasterGetInputLatency, 0, 0, nullptr, 0);///<
        [return value]: input latency in audio samples  @see
        AudioEffectX::getInputLatency audioMaster(nullptr,
        audioMasterGetOutputLatency, 0, 0, nullptr, 0);///< [return value]:
        output latency in audio samples  @see AudioEffectX::getOutputLatency
        audioMaster(nullptr, audioMasterGetCurrentProcessLevel, 0, 0, nullptr,
        0);///< [return value]: current process level  @see VstProcessLevels
        audioMaster(nullptr, audioMasterGetAutomationState, 0, 0, nullptr, 0);
        ///< [return value]: current automation state  @see VstAutomationStates
        audioMaster(nullptr, audioMasterOfflineStart, 0, 0, nullptr, 0);///<
        [index]: numNewAudioFiles [value]: numAudioFiles [ptr]: #VstAudioFile*
        @see AudioEffectX::offlineStart audioMaster(nullptr,
        audioMasterOfflineRead, 0, 0, nullptr, 0);///< [index]: bool readSource
        [value]: #VstOfflineOption* @see VstOfflineOption [ptr]:
        #VstOfflineTask*  @see VstOfflineTask @see AudioEffectX::offlineRead
        audioMaster(nullptr, audioMasterOfflineWrite, 0, 0, nullptr, 0);///<
        @see audioMasterOfflineRead @see AudioEffectX::offlineRead
        audioMaster(nullptr, audioMasterOfflineGetCurrentPass, 0, 0, nullptr,
        0);///< @see AudioEffectX::offlineGetCurrentPass audioMaster(nullptr,
        audioMasterOfflineGetCurrentMetaPass, 0, 0, nullptr, 0);///< @see
        AudioEffectX::offlineGetCurrentMetaPass audioMaster(nullptr,
        audioMasterGetVendorString, 0, 0, nullptr, 0);///< [ptr]: char buffer
        for vendor string, limited to #kVstMaxVendorStrLen  @see
        AudioEffectX::getHostVendorString audioMaster(nullptr,
        audioMasterGetProductString, 0, 0, nullptr, 0);///< [ptr]: char buffer
        for vendor string, limited to #kVstMaxProductStrLen  @see
        AudioEffectX::getHostProductString audioMaster(nullptr,
        audioMasterGetVendorVersion, 0, 0, nullptr, 0);///< [return value]:
        vendor-specific version  @see AudioEffectX::getHostVendorVersion
        audioMaster(nullptr, audioMasterVendorSpecific, 0, 0, nullptr, 0);
        ///< no definition, vendor specific handling  @see
        AudioEffectX::hostVendorSpecific audioMaster(nullptr, audioMasterCanDo,
        0, 0, nullptr, 0);///< [ptr]: "can do" string [return value]: 1 for
        supported audioMaster(nullptr, audioMasterGetLanguage, 0, 0, nullptr,
        0);	///< [return value]: language code  @see VstHostLanguage
        audioMaster(nullptr, audioMasterGetDirectory, 0, 0, nullptr, 0);///<
        [return value]: FSSpec on MAC, else char*  @see
        AudioEffectX::getDirectory audioMaster(nullptr,
        audioMasterUpdateDisplay, 0, 0, nullptr, 0);	///< no arguments
        audioMaster(nullptr, audioMasterBeginEdit, 0, 0, nullptr, 0);   ///<
        [index]: parameter index  @see AudioEffectX::beginEdit
        audioMaster(nullptr, audioMasterEndEdit, 0, 0, nullptr, 0);  ///<
        [index]: parameter index  @see AudioEffectX::endEdit
        audioMaster(nullptr, audioMasterOpenFileSelector, 0, 0, nullptr, 0);///<
        [ptr]: VstFileSelect* [return value]: 1 if supported  @see
        AudioEffectX::openFileSelector audioMaster(nullptr,
        audioMasterCloseFileSelector, 0, 0, nullptr, 0);///< [ptr]:
        VstFileSelect*  @see AudioEffectX::closeFileSelector
Benjamin Heisch's avatar
Benjamin Heisch committed
452
        */
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

      // Deprecated:
      /* audioMaster(nullptr, audioMasterWantMidi, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterSetTime, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterTempoAt, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterGetNumAutomatableParameters, 0, 0,
       nullptr, 0); audioMaster(nullptr, audioMasterGetParameterQuantization, 0,
       0, nullptr, 0); audioMaster(nullptr, audioMasterNeedIdle, 0, 0, nullptr,
       0); audioMaster(nullptr, audioMasterGetPreviousPlug, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterGetNextPlug, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterWillReplaceOrAccumulate, 0, 0, nullptr,
       0); audioMaster(nullptr, audioMasterSetOutputSampleRate, 0, 0, nullptr,
       0); audioMaster(nullptr, audioMasterGetOutputSpeakerArrangement, 0, 0,
       nullptr, 0); audioMaster(nullptr, audioMasterSetIcon, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterOpenWindow, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterCloseWindow, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterEditFile, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterGetChunkFile, 0, 0, nullptr, 0);
       audioMaster(nullptr, audioMasterGetInputSpeakerArrangement, 0, 0,
       nullptr, 0);*/
Benjamin Heisch's avatar
Benjamin Heisch committed
473
    }
474
475
476
477
478
479
480
481
482
483
484
485

    effect->processReplacing = [](AEffect* _effect,
                                  float** inputs,
                                  float** outputs,
                                  int32_t sampleFrames) {
      auto data = static_cast<VST2ImplementationData*>(_effect->user);
      int inputIndex = 0;
      int outputIndex = 0;
      iteratePorts<IAudioPort>(
        data->plug,
        [sampleFrames, &inputs, &inputIndex, &outputs, &outputIndex](
          IAudioPort* p, size_t) {
486
          p->setSampleCount(static_cast<size_t>(sampleFrames));
487
488
489
490
491
492
493
          for (size_t i = 0; i < p->size(); i++) {
            if (p->getDirection() == PortDirection::Input) {
              p->at(i)->feed(inputs[inputIndex]);
              inputIndex++;
            } else {
              p->at(i)->feed(outputs[outputIndex]);
              outputIndex++;
494
            }
495
496
497
498
499
500
          }
          return false;
        });

      data->plug->processAudio();
      writeMidiOutput(_effect);
501
    };
502
    // Not supported yet.
503
504
505
506
507
    /*effect->processDoubleReplacing = [](AEffect* effect, double** inputs,
    double** outputs, int32_t sampleFrames) { auto implementationData =
    static_cast<VST2ImplementationData*>(effect->user); int inputIndex = 0; int
    outputIndex = 0; iteratePorts<IAudioPort>(implementationData->plug,
    [sampleFrames, inputs, &inputIndex, outputs, &outputIndex](IAudioPort* p,
508
    size_t) { p->setSampleCount(static_cast<size_t>(sampleFrames)); for (size_t i
509
    = 0; i < p->size(); i++) { if (p->getDirection() == PortDirection::Input) {
Benjamin Heisch's avatar
Benjamin Heisch committed
510
                    p->at(i)->feed( nullptr, inputs[inputIndex]);
511
512
                    inputIndex++;
                }
Benjamin Heisch's avatar
Benjamin Heisch committed
513
514
                else {
                    p->at(i)->feed( nullptr, outputs[outputIndex]);
515
516
517
518
519
520
                    outputIndex++;
                }
            }
            return false;
            });

521
        implementationData->plug->processAudio();
522
523
        writeMidiOutput(effect);
    };*/
524
    effect->flags |= effFlagsCanReplacing | effFlagsCanDoubleReplacing;
525
526
527
    if (implementationData->plug->getFeatureComponent()->supportsFeature(
          Feature::GUISupport))
      effect->flags |= effFlagsHasEditor;
528

529
530
531
532
533
534
535
536
537
538
    // effect, index
    effect->getParameter = [](AEffect*, int32_t) -> float {
      // auto implementationData =
      // static_cast<VST2ImplementationData*>(_effect->user);
      return 0;
    };
    // effect, index, parameter
    effect->setParameter = [](AEffect*, int32_t, float) {
      // auto implementationData =
      // static_cast<VST2ImplementationData*>(_effect->user);
Benjamin Heisch's avatar
Benjamin Heisch committed
539
    };
540

541
    return effect;
542
  }
543
}