Initial release
This commit is contained in:
+449
@@ -0,0 +1,449 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Project : SDK Core
|
||||
//
|
||||
// Category : Basic Host Service Interfaces
|
||||
// Filename : pluginterfaces/base/doc.h
|
||||
// Created by : Steinberg, 01/2004
|
||||
// Description : doc for doxygen
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// This file is part of a Steinberg SDK. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this distribution
|
||||
// and at www.steinberg.net/sdklicenses.
|
||||
// No part of the SDK, including this file, may be copied, modified, propagated,
|
||||
// or distributed except according to the terms contained in the LICENSE file.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
********************************************************************
|
||||
\mainpage VST Module Architecture
|
||||
********************************************************************
|
||||
\tableofcontents
|
||||
|
||||
********************************************************************
|
||||
\section piVstMa Introduction
|
||||
********************************************************************
|
||||
\b VST-MA is a component model system which is used in all <a href="http://www.steinberg.net" target=_blank>Steinberg</a> host applications
|
||||
as the basic layer for plug-in support as well as for internal application components.\n
|
||||
It is object-oriented, cross-platform and (almost) compiler-independent. \n
|
||||
The basics are very much like Microsoft(R) COM, so if you are familiar with
|
||||
this technology, understanding VST-MA should be quite easy.
|
||||
|
||||
\b VST-MA is provided in C++ only. Interfaces in C++ are expressed as pure virtual class
|
||||
(which is a class with nothing but abstract methods). Unlike COM there is no support for C or other
|
||||
languages yet - simply because there has been no need for this so far. But all \b VST-MA interfaces
|
||||
can be transformed into different representations in case this should be inevitable some day. \n
|
||||
It is currently available for Windows and Mac OS X.
|
||||
|
||||
The C++ files belonging to \b VST-MA are located in the following folders:
|
||||
- <a href="../../pluginterfaces/base" target=_blank>pluginterfaces/base</a>
|
||||
- <a href="../../pluginterfaces/gui" target=_blank>pluginterfaces/gui</a>
|
||||
|
||||
\b Note: The name 'VST Module Architecture' has only little relation to the 'Virtual Studio Technology' itself. \n
|
||||
It describes the basic layer for any plug-in category supported in <a href="http://www.steinberg.net" target=_blank>Steinberg</a> hosts. \b VST-MA
|
||||
existed long before it was used as a base for VST 3 ifself.
|
||||
\n
|
||||
\n
|
||||
********************************************************************
|
||||
\section piInterfaces Interfaces
|
||||
********************************************************************
|
||||
|
||||
**********************************
|
||||
\subsection funknown FUnknown
|
||||
**********************************
|
||||
Steinberg::FUnknown is the basic interface of \b VST-MA. All other interfaces are directly or
|
||||
indirectly derived from it.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection iid IID/CID
|
||||
**********************************
|
||||
Each interface has a unique identifier (IID) of type Steinberg::FUID. It is used to retrieve a new
|
||||
interface from another one (Steinberg::FUnknown::queryInterface). It is important to understand the
|
||||
difference between interface identifier and component identifier.\n
|
||||
A component-ID or class-ID (CID) is used to identify a concrete implementation class and is usually passed to a class factory in order
|
||||
to create the corresponding component. \n
|
||||
So a lot of different classes (with different class identifiers) can implement the same interfaces.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection direction Direction
|
||||
**********************************
|
||||
An interface may have a \b direction, meaning that the interface is expected to be
|
||||
implemented either in the plug-in or in the host. The nature of an interface is documented like this:
|
||||
\n \n
|
||||
- <b>[host imp] </b>: the host implements the interface
|
||||
- <b>[plug imp] </b>: the plug-in implements the interface
|
||||
.
|
||||
\n
|
||||
When neither of these is specified, the interface can be used in both ways.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection version Versioning and inheritance
|
||||
**********************************
|
||||
Unlike C++ classes, interfaces do not use inheritance to express specializations of objects.
|
||||
Inheritance is used for versioning only. One of the strict rules is, that once an interface has been
|
||||
released, it must never change again. Adding new functionality to an interface requires a new version
|
||||
(usually an ordinal number is added to its name in this case).\n
|
||||
A new version inherits the old version(s)
|
||||
of the interface, so the old and the new methods are combined in one interface. This is why specializations
|
||||
need to be modeled as separate interfaces! If a specialized interface were to inherit from the basic interface
|
||||
as well, an implementation class that needs to implement all of these interfaces would inherit the base
|
||||
interface twice, causing the compiler to run into ambiguities. So the specialization relation
|
||||
to a basic interface can only be expressed in the documentation: \n \n
|
||||
- ISpecialInterface [\b extends IBaseInterface] => means IBaseInterface::queryInterface (ISpecialInterface::iid, ...) can be used to retrieve the derived
|
||||
interface.
|
||||
.
|
||||
\n
|
||||
You can find some example code here: \ref versionInheritance
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection com COM Compatibility
|
||||
**********************************
|
||||
The first layer of \b VST-MA is binary-compatible to \b COM. The Vtable and interface identifier of
|
||||
FUnknown match with the corresponding COM interface IUnknown. The main difference is the organization
|
||||
and creation of components by a host application. \b VST-MA does not require any Microsoft(R) COM source file.
|
||||
You can find information about \b COM on pages like: \n
|
||||
- \htmlonly <a href="http://www.microsoft.com/Com/resources/comdocs.asp" target="_blank">http://www.microsoft.com/Com/resources/comdocs.asp</a>\endhtmlonly.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection basic Basic Interfaces
|
||||
**********************************
|
||||
- Steinberg::FUnknown
|
||||
- Steinberg::IPluginBase
|
||||
- Steinberg::IPluginFactory
|
||||
.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection helper Helper Classes
|
||||
**********************************
|
||||
- Steinberg::FUID
|
||||
- Steinberg::FUnknownPtr
|
||||
.
|
||||
\n
|
||||
\see \ref howtoClass
|
||||
\n
|
||||
\n
|
||||
********************************************************************
|
||||
\section piPlugins Plug-ins
|
||||
********************************************************************
|
||||
|
||||
**********************************
|
||||
\subsection module Module Factory
|
||||
**********************************
|
||||
A module (Windows: Dynamic Link Library, MAC: Mach-O Bundle) contains the implementation
|
||||
of one or more components (e.g. VST 3 effects). A \b VST-MA module must contain a class factory
|
||||
where meta-data and create-methods for the components are registered. \n
|
||||
The host has access to this factory through the Steinberg::IPluginFactory interface. This is the anchor point for the module
|
||||
and it is realized as a C-style export function named GetPluginFactory. You can find an export
|
||||
definition file in folder - <a href="../../public.sdk/win/stdplug.def" target=_blank>public.sdk/win/stdplug.def</a>
|
||||
which can be used to export this function. \n
|
||||
GetPluginFactory is declared as follows:
|
||||
|
||||
\code{.cpp}
|
||||
IPluginFactory* PLUGIN_API GetPluginFactory ()
|
||||
\endcode
|
||||
\n
|
||||
|
||||
**********************************
|
||||
\subsection Locations
|
||||
**********************************
|
||||
Component modules do not require registration like DirectX. The host application expects component modules to be located in predefined folders of the file system.
|
||||
These folders and their subfolders are scanned for \b VST-MA modules during application startup. Each folder serves a special purpose:
|
||||
- The application's \c Components subfolder (e.g. "C:\Program Files\Steinberg\Cubase SX\Components") is used for components tightly bound to the application. No other application should use it.
|
||||
- Components that are shared between all <a href="http://www.steinberg.net" target=_blank>Steinberg</a> hosts are located at:
|
||||
- Win: "/Program Files/Common Files/Steinberg/shared components"
|
||||
- Mac: "/Library/Application Support/Steinberg/Components/"
|
||||
- For special purpose plug-in types, additional locations can be defined. Please refer to the corresponding documentation to find out if additional folders are used and where to find them.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection Categories
|
||||
**********************************
|
||||
Any class that the factory can create is assigned to a category. It is this category that tells
|
||||
the host the purpose of the class (and gives a hint of which interfaces it might implement). \n
|
||||
A class is also described with a name and it has a unique id.
|
||||
- For example, the category for import/export filters is <b>"Project Filter"</b> and for VST 3 audio plug-ins <b>"Audio Module Class"</b>.
|
||||
- "Service" is a special category. The purpose of a class of this category is completely
|
||||
unknown to the host. It is be loaded automatically during program start
|
||||
(provided that the user did not deactivate it).
|
||||
- Since the factory can create any number of classes, one component library can contain
|
||||
multiple components of any type.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection IPluginBase
|
||||
**********************************
|
||||
The entry-point interface for any component class is Steinberg::IPluginBase. The host uses this
|
||||
interface to initialize and to terminate the plug-in component. When the host initializes the
|
||||
plug-in, it passes a so called context. This context contains any interface to the host that
|
||||
the plug-in will need to work.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection purpose Purpose-specific interfaces
|
||||
**********************************
|
||||
Each plug-in category (VST 3 Effects, Project import/export Filters, Audio Codecs, etc...) defines its own set of purpose-specific interfaces. These are not part of the basic VST-MA layer.
|
||||
\n
|
||||
\n
|
||||
\see \ref loadPlugin
|
||||
\n
|
||||
\n
|
||||
********************************************************************
|
||||
\section Unicode Unicode
|
||||
********************************************************************
|
||||
|
||||
Beginning with version 5 of Cubase and Nuendo, the internal structure of the host was modified to
|
||||
better support internationalization. Therefore, string handling was changed to utilize
|
||||
<A HREF="http://en.wikipedia.org/wiki/Unicode">Unicode</A> strings whenever strings are passed
|
||||
around. As a consequence, all the interfaces to plug-ins have changed from using ASCI to Unicode strings
|
||||
for call and return parameters. So in turn, all plug-in must be adapted to support
|
||||
Unicode. This has major consequences in that:
|
||||
- Unicode hosts (Cubase 5 or later) will only work with Unicode plug-ins. When loading a plug-in,
|
||||
a Unicode host checks the plug-in's type and will not load any non-Unicode plug-ins.
|
||||
\n
|
||||
- Unicode plug-ins will <b>not</b> load in non-Unicode hosts. When loading a Unicode plug-in
|
||||
requests information from the host and will not load, if no Unicode host is detected.
|
||||
Therefore, if a plug-in is supposed to work with both older and newer hosts, it is best to provide
|
||||
two versions of the plug-in.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection plugunicode Plug-ins for Unicode hosts
|
||||
**********************************
|
||||
Writing plug-ins that are supposed to work only with Unicode hosts is easy. Use a current version
|
||||
of this SDK and develop a plug-in as usual. Make sure that you only ever pass Unicode
|
||||
<a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a> strings to interfaces that
|
||||
have strings as call parameters and also be prepared that strings returned by these interfaces are
|
||||
always <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>. Therefore, to make things easier, it is recommended that Unicode strings are used throughout the
|
||||
plug-in's implementation, in order to avoid back and forth conversions.
|
||||
Also, use the Steinberg::String and Steinberg::ConstString classes from
|
||||
the Base module, they have been designed to work universally on both Mac and Win.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection migrating Migrating from non-Unicode to Unicode
|
||||
**********************************
|
||||
In <a href="http://www.steinberg.net" target="_blank">Steinberg</a> SDKs released before Cubase 5 the interface functions were using pointers of type <c> char </c>
|
||||
for passing strings to and from the host. These have been changed now to using Steinberg's defined
|
||||
type <c> tchar </c> which is equivalent to <c> char16 </c>, i.e. 16 bit character. In theory, there are
|
||||
many ways for representing 16 bits characters, but we chose
|
||||
to use the industry standard <a href="http://en.wikipedia.org/wiki/Unicode">Unicode</a>, so strings
|
||||
are expected to be encoded in <a href="http://en.wikipedia.org/wiki/UTF-16">UTF-16</a>. \n
|
||||
Accordingly, also the implementation of a plug-in needs to be adapted to deal correctly with Unicode
|
||||
encoded strings, as well as only ever passing Unicode strings to the host.
|
||||
\n
|
||||
\n
|
||||
<b>Technical note</b>: Changing a function from using 8 bit to 16 bit character pointers may seem as only a
|
||||
minor modification, but in interface design this is a major intrusion, because an interface is
|
||||
a contract to the outside world that is never to be changed. Therefore, classes that are changed
|
||||
to use Unicode strings are distinguished and also receive a new unique class ID.
|
||||
\n
|
||||
\n
|
||||
**********************************
|
||||
\subsection backward SDK backward compatibility
|
||||
**********************************
|
||||
Even with the current SDK it is still possible to develop non-Unicode plug-ins. In the
|
||||
file <a href="../../pluginterfaces/base/ftypes.h">pluginterfaces/base/ftypes.h</a>, the line "#define UNICODE_OFF"
|
||||
is commented out, by uncommenting it you can revert all interfaces to using single byte ASCII strings.
|
||||
Alternatively you can also specify UNICODE_OFF as a preprocessor definition in your project file.\n
|
||||
Also, the plug-in's factory info now does not define the Unicode flag anymore, so a Unicode host sees the compiled
|
||||
plug-in as non-Unicode. Also, when reverting to single byte strings the plug-in's implementation also
|
||||
has to be changed to behave correctly.
|
||||
\n
|
||||
\n
|
||||
<b>Technical note</b>: When undefining Unicode, the class IDs also revert to the old ones.
|
||||
\n
|
||||
\n
|
||||
*/
|
||||
|
||||
//******************************************************
|
||||
/**
|
||||
\page howtoClass How to derive a class from an interface
|
||||
*********************************************************
|
||||
In the first example we derive a class directly from FUnknown, using some of the helper macros provided by the SDK.
|
||||
|
||||
\code{.cpp}
|
||||
class CMyClass: public FUnknown
|
||||
{
|
||||
public:
|
||||
CMyClass ();
|
||||
virtual ~CMyClass ();
|
||||
|
||||
DECLARE_FUNKNOWN_METHODS // declares queryInterface, addRef and release
|
||||
};
|
||||
|
||||
|
||||
CMyClass::CMyClass ()
|
||||
{
|
||||
FUNKNOWN_CTOR // init reference counter, increment global object counter
|
||||
}
|
||||
|
||||
CMyClass::~CMyClass ()
|
||||
{
|
||||
FUNKNOWN_DTOR // decrement global object counter
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNT (CMyClass) // implements reference counting
|
||||
|
||||
tresult CMyClass::queryInterface (const char* iid, void** obj)
|
||||
{
|
||||
QUERY_INTERFACE (iid, obj, ::FUnknown::iid, CMyClass)
|
||||
return kNoInterface;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Developing a class with more than one interface is done by multiple inheritance. Additionally you have to provide an appropriate cast for each interface in the queryInterface method.
|
||||
|
||||
\code{.cpp}
|
||||
class CMyMultiClass : public Steinberg::IPluginBase,
|
||||
public Steinberg::IPlugController,
|
||||
public Steinberg::IEditorFactory
|
||||
{
|
||||
public:
|
||||
DECLARE_FUNKNOWN_METHODS
|
||||
|
||||
// declare the methods of all inherited interfaces here...
|
||||
};
|
||||
|
||||
IMPLEMENT_REFCOUNT (CMyMultiClass) // implements reference counting
|
||||
|
||||
tresult CMyMultiClass::queryInterface (const char* iid, void** obj)
|
||||
{
|
||||
QUERY_INTERFACE (iid, obj, Steinberg::FUnknown::iid, IPluginBase)
|
||||
QUERY_INTERFACE (iid, obj, Steinberg::IPluginBase::iid, IPluginBase)
|
||||
QUERY_INTERFACE (iid, obj, Steinberg::IPlugController::iid, IPlugController)
|
||||
QUERY_INTERFACE (iid, obj, Steinberg::IEditorFactory::iid, IEditorFactory)
|
||||
*obj = 0;
|
||||
return kNoInterface;
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//********************************************************************
|
||||
/** \page versionInheritance Interface Versions and Inheritance
|
||||
********************************************************************
|
||||
\par
|
||||
|
||||
Unlike C++ classes, \b VST-MA interfaces do not use inheritance to express
|
||||
specializations of objects. Usually all interfaces are derived from
|
||||
FUnknown. This is because interfaces must \b never change after they
|
||||
have been released. The VST Module Architecture Interfaces use inheritance
|
||||
only for versioning! All specializations will be modeled as
|
||||
separate interfaces!
|
||||
|
||||
For example the C++ classes
|
||||
\code{.cpp}
|
||||
class Shape
|
||||
{
|
||||
public:
|
||||
void setPosition (long x, long y);
|
||||
protected:
|
||||
long x;
|
||||
long y;
|
||||
};
|
||||
class Rect : public Shape
|
||||
{
|
||||
public:
|
||||
void setDimension (long width, long height);
|
||||
protected:
|
||||
long width;
|
||||
long height;
|
||||
};
|
||||
\endcode
|
||||
|
||||
expressed in \b VST-MA, define an interface for each inheritance level:
|
||||
|
||||
\code{.cpp}
|
||||
class IShape : public FUnknown
|
||||
{
|
||||
public:
|
||||
virtual void setPosition (long x, long y) = 0;
|
||||
};
|
||||
class IRect : public FUnknown
|
||||
{
|
||||
public:
|
||||
virtual void setDimension (long width, long height) = 0;
|
||||
};
|
||||
\endcode
|
||||
|
||||
In the next program version there need to be changes to
|
||||
the \c Shape class that look like this:
|
||||
\code{.cpp}
|
||||
class Shape
|
||||
{
|
||||
public:
|
||||
void setPosition (long x, long y);
|
||||
void setColor (Color color);
|
||||
protected:
|
||||
long x;
|
||||
long y;
|
||||
Color color;
|
||||
};
|
||||
\endcode
|
||||
|
||||
The \b VST-MA representation now reflect the changes to Shape by adding a
|
||||
new interface that inherits from IShape and looks like the following
|
||||
code, while the former interface definitions remain the same:
|
||||
\code{.cpp}
|
||||
class IShape2 : public IShape
|
||||
{
|
||||
public:
|
||||
virtual void setColor (Color color) = 0;
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//********************************************************************
|
||||
/** \page loadPlugin How the host will load a plug-in
|
||||
********************************************************************
|
||||
\par
|
||||
|
||||
The host application will handle a plug-in in the following manner
|
||||
(some code is Windows-specific!):
|
||||
|
||||
\code{.cpp}
|
||||
HMODULE hModule = LoadLibrary ("SomePlugin.dll");
|
||||
if (hModule)
|
||||
{
|
||||
InitModuleProc initProc = (InitModuleProc)GetProcAddress (hModule, "InitDll");
|
||||
if (initProc)
|
||||
{
|
||||
if (initProc () == false)
|
||||
{
|
||||
FreeLibrary (module);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GetFactoryProc proc = (GetFactoryProc)GetProcAddress (hModule, "GetPluginFactory");
|
||||
|
||||
IPluginFactory* factory = proc ? proc () : 0;
|
||||
if (factory)
|
||||
{
|
||||
for (int32 i = 0; i < factory->countClasses (); i++)
|
||||
{
|
||||
PClassInfo ci;
|
||||
factory->getClassInfo (i, &ci);
|
||||
|
||||
FUnknown* obj;
|
||||
factory->createInstance (ci.cid, FUnknown::iid, (void**)&obj);
|
||||
...
|
||||
obj->release ();
|
||||
}
|
||||
|
||||
factory->release ();
|
||||
}
|
||||
|
||||
ExitModuleProc exitProc = (ExitModuleProc)GetProcAddress (hModule, "ExitDll");
|
||||
if (exitProc)
|
||||
exitProc ();
|
||||
|
||||
FreeLibrary (hModule);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
Reference in New Issue
Block a user