VST 3 Interfaces VST 3.6.11 SDK for developing VST Plug-in

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Groups Pages
Key Switch Support

Allows information exchange between the Plug-in and Host about which key switches are currently used.

# Introduction

Some instrument Plug-ins support Key switching functionality, which allows a user to switch between different layered sounds while playing notes, to achieve this the user has to pressed a specific key associated to this wanted layer before playing new notes.
A typical example is a sample-based-Player Plug-in with a violin sound which could include different layers or articulations: pizzicato, legato, tremolo... By pressing or by keeping pressed a specific key, for example C-1, before playing new notes, the Plug-in will choose to play pizzicato, by using D-1, it will play legato...
With VST Expression Map (feature of Cubase since 4.0), these Key switches could be used in score editor to associated a symbol (articulation) to a note and each time this note will be played the corresponding Key switch will be used (send to the Plug-in as noteOn event).
In order to help the creation of such Map, VST 3.5 defines a new interface Steinberg::Vst::IKeyswitchController. When a (instrument) Plug-in supports such interface, the host could get from the Plug-in the current set of used Key switches (megatrigg / articulation: Steinberg::Vst::KeyswitchInfo) for a given channel of a Event Bus and then automatically use them (like in Cubase 6) to create VST Expression Map.

# How does it work?

Here the Step by Step example.
We want a Plug-in with 1 event bus and mono-timbral (1 channel) which supports 2 Key switches:

1. The instrument Plug-in should have one input event bus (could be more).
   //------------------------------------------------------------------------
   tresult PLUGIN_API MyExampleProcessor::initialize (FUnknown* context)
   {
   //---always initialize the parent-------
   tresult result = AudioEffect::initialize (context);
   if (result == kResultTrue)
   {
   // we want a Stereo Output
   addAudioOutput (STR16 ("Stereo Output"), SpeakerArr::kStereo);
   // create Event In bus (1 bus with only 1 channel)
   addEventInput (STR16 ("Event Input"), 1);
   }
   return result;
   }
   //------------------------------------------------------------------------
2. The controller should have the interface Steinberg::Vst::IKeyswitchController, here in the class declaration:
   //-----------------------------------------------------------------------------
   class MyExampleController: public EditController, public IKeyswitchController
   {
   public:
   ...
   //---from IKeyswitchController
   virtual int32 PLUGIN_API getKeyswitchCount (int32 busIndex, int16 channel);
   virtual tresult PLUGIN_API getKeyswitchInfo (int32 busIndex, int16 channel, int32 keySwitchIndex, KeyswitchInfo& info);
   ...
   OBJ_METHODS (MyExampleController, EditController)
   DEFINE_INTERFACES
   DEF_INTERFACE (IKeyswitchController)
   END_DEFINE_INTERFACES (EditController)
   REFCOUNT_METHODS(EditController)
   ...
   };
   //------------------------------------------------------------------------

1. Now we have to implement the interface Steinberg::Vst::IKeyswitchController (only 2 functions), in our example Steinberg::Vst::IKeyswitchController::getKeyswitchCount should return 2 (2 keyswitches):
   //------------------------------------------------------------------------
   int32 MyExampleController::getKeyswitchCount (int32 busIndex, int16 channel)
   {
   // we accept only the first bus and 1 channel
   if (busIndex == 0 && channel == 0)
   return 2;
   return 0;
   }
   //------------------------------------------------------------------------

1. Then we have to implement Steinberg::Vst::IKeyswitchController::getKeyswitchInfo which allows to inform the host about what the Plug-in supports:
   //------------------------------------------------------------------------
   tresult PLUGIN_API MyExampleController::getKeyswitchInfo (int32 busIndex, int16 channel, int32 keySwitchIndex, KeyswitchInfo& info)
   {
   // we accept only the first bus and 1 channel and only 2 keyswitches
   if (busIndex == 0 && channel == 0 && (keySwitchIndex == 0 || keySwitchIndex == 1)
   {
   memset (&info, 0, sizeof (KeyswitchInfo));
   info.typeId = kKeyRangeTypeID; // in this case we want that Keyswitch should be maintained pressed for playíng
   // we could use keyRemapped to make easier the use of the keyswitch (near the available instrument key range)
   // take care that there are no overlap between keyswitches and real key (playing sound)
   if (keySwitchIndex == 0)
   {
   USTRING ("Accentuation").copyTo (info.title, 128);
   USTRING ("Acc").copyTo (info.shortTitle, 128);
   // if the user keeps pressed C-1 or C#-1 or C-0 then the Accentuation sound should be played
   info.keyswitchMin = 12; // C-1
   info.keyswitchMax = 13; // C#-1
   info.keyRemapped = 24; // C-0
   }
   else
   {
   USTRING ("Softly").copyTo (info.title, 128);
   USTRING ("Soft").copyTo (info.shortTitle, 128);
   // if the user keeps pressed D-1 or D#-1 or D-0 then the Softly sound should be played
   info.keyswitchMin = 14; // D-1
   info.keyswitchMax = 15; // D#-1
   info.keyRemapped = 26; // D-0
   }
   info.unitID = -1; // not used
   info.flags = 0; // not used
   return kResultTrue;
   }
   return kResultFalse;
   }
   //------------------------------------------------------------------------

1. Last step, in the processor component we have to adapt the process call to switch to the wanted articulation:
   //------------------------------------------------------------------------
   tresult MyExampleProcessor::process (ProcessData& data)
   {
   ....
   // get the input event queue
   IEventList* inputEvents = data.inputEvents;
   if (inputEvents)
   {
   Event e;
   int32 numEvents = inputEvents->getEventCount ();
   // for each events check it..
   for (int32 i = 0; i < numEvents; i++)
   {
   if (inputEvents->getEvent (i, e) == kResultTrue)
   {
   switch (e.type)
   {
   //-----------------------
   case Event::kNoteOnEvent:
   {
   // here a note On
   // check if this is a Keyswitch
   switch (e.noteOn.pitch)
   {
   // Accentuation Keyswitch
   case 12:
   case 13:
   case 24:
   currentLayer = kAccentuationLayer;
   break;
   // Softly Keyswitch
   case 14:
   case 15:
   case 26:
   currentLayer = kSoftlyLayer;
   break;
   default:
   // play the note in the currentLayer
   ...
   }
   } break;
   //-----------------------
   case Event::kNoteOffEvent:
   {
   // check if keyswitch is released
   switch (e.noteOff.pitch)
   {
   // Accentuation Keyswitch
   case 12:
   case 13:
   case 24:
   case 14:
   case 15:
   case 26:
   currentLayer = kDefaultLayer;
   break;
   default:
   // released note...
   ...
   }
   } break;
   ....
   }
   }
   }
   }
   ...
   }
   //------------------------------------------------------------------------

That is it!

Back to Contents

Empty

Copyright ©2018 Steinberg Media Technologies GmbH. All Rights Reserved. This documentation is under this license.