Mittwoch, 27. Februar 2013

Teile eines VST Plugins

Heyho,

In Teil eins unseres Workshops geht es mal darum, wie so ein VST Plugin aufgebaut ist.
Erstelle wir zuerst mal ein neues Projekt.

Wie das geht steht auf

 http://teragonaudio.com/article/Making-a-VST-plugin-from-scratch-with-Xcode.html

Eine grandiose Resource ;)

Wenn ihr das geschafft habt, ist das meiste schon getan.
Jetzt geht ihr auf den Tree in der linken Seite und klickt  ctrl + apfel auf source.
Dann auf "add existing file". Dann navigiert ihr zu eurem VST SDK. Bei "public.sdk" gibts den Ordner "samples". Da drinnen gibts 2 Files: again.h und again.cpp.
Beide Dateien auswählen und dem Projekt hinzufügen. WICHTIG: IN DAS PROJEKT KOPIEREN!

Gut. Anhand dieses Beispiels werden wir nun das Plugin veranschaulichen.

Beginnen wir mit der Datei "again.h":
In dieser Datei wird mal alles deklariert, was wir in unserer again.cpp Datei dann verwenden wollen.


//-------------------------------------------------------------------------------------------------------
// VST Plug-Ins SDK
// Version 2.4 $Date: 2006/11/13 09:08:27 $
//
// Category     : VST 2.x SDK Samples
// Filename     : again.h
// Created by   : Steinberg Media Technologies
// Description  : Stereo plugin which applies Gain [-oo, 0dB]
//
//  2006, Steinberg Media Technologies, All Rights Reserved
//-------------------------------------------------------------------------------------------------------

#ifndef __again__
#define __again__

//- Wir fügen die externe Klasse audioeffectx.h hinzu. Ohne die geht gar nix ;)

#include "public.sdk/source/vst2.x/audioeffectx.h"

//-------------------------------------------------------------------------------------------------------
//- Erstellen der Klasse, welche auf AudioEffectX zugreift. 
//- Der Name der Klasse ist AGain.

class AGain : public AudioEffectX
{
public:
AGain (audioMasterCallback audioMaster);
~AGain ();

//- Der Teil in dem dann unser Prozess passiert und die eigentliche DSP Arbeit.Für den Anfang...
// Processing
virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames);

//- Nun folgen die Anweisungen für den Programm Namen. Das kennt ihr aus den sogenannten "Presets" eines VST Plugins

// Program
virtual void setProgramName (char* name);
virtual void getProgramName (char* name);
//- Die Parameter: set, get, das Label, das Display, der Name der Parameter 
// Parameters
virtual void setParameter (VstInt32 index, float value);
virtual float getParameter (VstInt32 index);
virtual void getParameterLabel (VstInt32 index, char* label);
virtual void getParameterDisplay (VstInt32 index, char* text);
virtual void getParameterName (VstInt32 index, char* text);

//- Der Name des Plugins, dein Company Name, plugin ID und Version

virtual bool getEffectName (char* name);
virtual bool getVendorString (char* text);
virtual bool getProductString (char* text);
virtual VstInt32 getVendorVersion ();

//- Der geschützte Teil des plugins: Hier kommen unsere z.B. fader, values etc. die wir verwenden wollen. 
protected:
float fGain ;
char programName[kVstMaxProgNameLen + 1];
};

#endif


Das wars schon mit der again.h Datei! Mehr gibt es dazu vorerst nicht zu sagen.
Da wir nur einen Parameter im Plugin haben, verzichten wir gezielt auf "enum". Falls du nicht weißt was das ist, dann zerbrich dir an dieser Stelle nicht den kopf darüber. Dazu etwas später mehr.


Weiter gehts mit der "again.cpp" Datei!



//-------------------------------------------------------------------------------------------------------
// VST Plug-Ins SDK
// Version 2.4 $Date: 2006/11/13 09:08:27 $
//
// Category     : VST 2.x SDK Samples
// Filename     : again.cpp
// Created by   : Steinberg Media Technologies
// Description  : Stereo plugin which applies Gain [-oo, 0dB]
//
//  2006, Steinberg Media Technologies, All Rights Reserved
//-------------------------------------------------------------------------------------------------------

//- WICHTIG: Die Header Datei includen!!!

#include "again.h"


//-------------------------------------------------------------------------------------------------------

//- Erstelle eine neue Effekt Instanz

AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
{
return new AGain (audioMaster);
}

//-------------------------------------------------------------------------------------------------------

//- Initialisiere das plugin

AGain::AGain (audioMasterCallback audioMaster)
: AudioEffectX (audioMaster, 1, 1) // 1 Programm, 1 Parameter->(fGain)!!
{
setNumInputs (2); // Zwei Eingangs Kanäle
setNumOutputs (2); // Zwei Ausgangs Kanäle
setUniqueID ('cis1'); // 4 Zeichen, zur Identifikation des Plugins im Host
canProcessReplacing (); // Unterstützung der Replacing Funktion
// canDoubleReplacing (); //mit doppelter Präzision - nicht so wichtig im Moment

fGain = 1.f; // fGain auf höchsten Wert initialisieren: 0 dB

vst_strncpy (programName, "Erser Eintrag!", kVstMaxProgNameLen); // Programmname
}

//- den Deconstructor vergessen wir mal am Anfang.
//-------------------------------------------------------------------------------------------------------
AGain::~AGain ()
{
// nothing to do here
}

//-------------------------------------------------------------------------------------------------------
//- Wir setzen unseren Programmnamen

void AGain::setProgramName (char* name)
{
vst_strncpy (programName, name, kVstMaxProgNameLen);
}

//-----------------------------------------------------------------------------------------
//- Wir lesen unseren Programmnamen
void AGain::getProgramName (char* name)
{
vst_strncpy (name, programName, kVstMaxProgNameLen);
}


//-----------------------------------------------------------------------------------------

//- Setzen der Parameter: Hier ist schon der erste kleine Unterschied zu dem Steinberg Template: Für den Fall, dass mehrere Parameter hinzugefügt werden sollen, habe ich hier gleich von Anfang an eine Switch Anweisung erstellt. Das ist wichtig für das korrekte erkennen und verarbeiten der Parameter. Ich gehe davon aus, dass ihr C++ ein wenig beherrscht und werde eine Switch Anweisung nicht näher erklären ;)
void AGain::setParameter (VstInt32 index, float value)
{
switch(index){
case 0: fGain = value;break;

}
}

//-----------------------------------------------------------------------------------------

//- Auslesen der Parameter - ebenfalls mit einer Switch Anweisung
float AGain::getParameter (VstInt32 index)
{
float v = 0;

switch(index){
case 0: v = fGain;break;
}
return v;
}

//-----------------------------------------------------------------------------------------

//- Der Name unseres Parameters fGain
void AGain::getParameterName (VstInt32 index, char* label)
{
switch(index){
case 0: vst_strncpy (label, "Gain", kVstMaxParamStrLen);break;
}
}

//-----------------------------------------------------------------------------------------

//- Anzeigen des veränderten Werts von fGain. Zu beachten ist hier die fertige Klasse dB2string(). Diese wandelt mir den angezeigten "float" Standard Wert 0-1 zu -oo zu 0 dB um. Klasse, nicht? :p  Du kannst dich ein wenig spielen und "dB2string" zu "float2string" umschreiben und schauen was dann passiert. Richtig: Es wir eine Fließkommazahl anstatt der dB angezeigt.

void AGain::getParameterDisplay (VstInt32 index, char* text)
{
switch(index){
case 0: dB2string (fGain, text, kVstMaxParamStrLen);break;
}
}

//-----------------------------------------------------------------------------------------
//- Natürlich wollen wir auch wissen was wir da ausgelesen haben. In diesem Fall: Dezibel
void AGain::getParameterLabel (VstInt32 index, char* label)
{
switch(index){
case 0: vst_strncpy (label, "dB", kVstMaxParamStrLen);break;
}
}

//------------------------------------------------------------------------

//- Dieser Teil gibt den Namen des Plugins aus. Hier: "Gain"
bool AGain::getEffectName (char* name)
{
vst_strncpy (name, "Gain", kVstMaxEffectNameLen);
return true;
}

//------------------------------------------------------------------------
//- Wie heisst unser Plugin? 
bool AGain::getProductString (char* text)
{
vst_strncpy (text, "Gain", kVstMaxProductStrLen);
return true;
}


//------------------------------------------------------------------------

//- DEIN Firmenname steht hier
bool AGain::getVendorString (char* text)
{
vst_strncpy (text, "YOUR COMPANY", kVstMaxVendorStrLen);
return true;
}

//-----------------------------------------------------------------------------------------

//- Unsere Produktversion. Wenn du z.B. an Version 1.1 arbeitest, gibst du bei return einfach "1100" ein! So einfach ist das ;)

VstInt32 AGain::getVendorVersion ()
return 1000; 
}

//-----------------------------------------------------------------------------------------

//- Jetzt kommen wir zum interessanten Teil, nachdem wir schon jede Menge an Code geschrieben haben. die Funktion processReplacing! 
void AGain::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames)
{
    float* in1  =  inputs[0]; //- Zeiger in1 auf input1
    float* in2  =  inputs[1]; //- das selbe auf in2
    float* out1 = outputs[0]; //- und auf output1
    float* out2 = outputs[1]; //- das selbe


//- Nun gibt es viele Möglichkeiten wie man die Daten verarbeitet. Hier verwenden wir ma eine while Schleife. Diese sagt folgendes (ungefähr): Während unsere Samples größer oder gleich 0 sind berechne den Inhalt! 

    while (--sampleFrames >= 0)
    {
        //- In der Schleife multiplizieren wir nun unsere Eingänge mit unserem Gain Fader. Vergesst nicht: hier geht es um einsen und nullen. Das heisst, unser Eingang ist immer EINS. Wenn  wir nun unseren Gain Fader auf die Hälfte einstellen, dann gibt er 0.5 zurück. Das hat nichts mit unserer Dezibel Klasse zu tun. Diese ist nur für unser Display verantwortlich! Wir bekommen also den Wert 1*0.5 = 0.5 zurück. 
        (*out1++) = (*in1++) * fGain;
        (*out2++) = (*in2++) * fGain;
    }
}




So das wars eigentlich schon. Wenn ihr nun in eurer IDE alles richtig gemacht habt, dann könnt ihr das mal kompilieren und das Plugin in euren VST Ordner kopieren.

Im nächsten Tutorial basteln wir uns eine kleine Stereoverbreiterung mit Phasenkorrektur!


Chris


  

Was brauche ich um VST Plugins zu programmieren?

Herzlich willkommen auf DSP TUTORIALS!

Warum mache ich dieses BLOG? Ganz einfach: es gibt im gesamten WWW (WorldWideWeb) kein vernünftiges, leicht zu verstehendes Tutorial in deutsch!

Wer bin ich?

Ich habe in der Vergangenheit schon einige Freeware VST Plugins veröffentlicht. Diese habe ich mit der Software "Synthmaker" (jetzt "Flowstone") erstellt. Diese Software ist wirklich cool und hat alles, was man zum Programmieren braucht. UND: es ist ein modulares Echtzeit - System, was die Programmierung ungemein erleichtert. Man hört und sieht sofort was man da eigentlich programmiert.
Ganz gut finde ich auch die "Code" Abteilung der Software. Diese ist der Programmiersprache "C" angelehnt und somit sind fertige Source - Codes mehr oder weniger leicht zu implentieren.
Was mir an der Synthmaker nicht gefällt: es gibt keine Möglichkeit die Plugins für MacOSX zu exportieren. Das heisst, man ist auf Windows eingeschränkt.

Diese Tatsache hat mich dazu bewogen, "echte" Plugins zu schreiben. Ich verwende dazu die Programmiersprache "C++", so wie auch tausende anderer Programmierer weltweit.

Da ich selber nach längerer Pause wieder die Liebe am programmieren entdeckt habe, passt euer Einsteiger Level zu meinem. Ihr könnt quasi mit mir mitlernen. Also wenn du lieber Leser bereits VST Profi bist, gehe bitte nicht zu hart ins Gericht mit mir :-)

Was benötige ich nun wenn ich VST Plugins programmieren will?

1. IDE oder nicht?
Zu allererst mal den Willen stundenlang vor einem Computer zu sitzen.
Dabei kommt es jetzt nicht darauf an ob du auf Mac oder PC arbeitest.
C++ ist universell auf beide Systeme anwendbar.

Eine IDE - integrierte Entwicklungsumgebung (integrated development environment):
Das ist nichts anderes als ein Texteditor mit Compiler für das System auf dem du arbeitest.
Ich werde jetzt nicht weiter auf die Teile und was sie genau machen eingehen. Darüber gibt es genügend Seiten im Netz -> Mr. Google

Da ich im Moment vermehrt auf MacOSX arbeite, werden eventuell auch Bilder von Apple's XCODE vorkommen. Lasse dich davon nicht verwirren. Bei Windows wäre die IDE z.B. VC++ (Visual C++).
Ist im Prinzip nichts anderes. Texteditor, Compiler, blabla...

Gut. Ich nehme an, du hast deine IDE bereits.
Wenn nicht, gehe bei Apple in den Appstore und lade dir  XCode runter.
Falls du auf Windows arbeitest, lade dir VC++ Express runter.
Beide sind kostenlos.

2. Ein SDK (Software Development Kit) 
Hä? Was ist das wieder?
Das ist eine Sammlung von Klasse, welche wir zum programmieren eines VST Plugins brauchen.
Dazu beginnen wir mit dem Steinberg VST SDK 2.4. Dieser ist nicht frei verfügbar.
Als erstes gehst du auf http://www.steinberg.net/en/company/developer.html
Dort musst du einen Account erstellen, um das ZIP File "VSTSDK2.4" runterzuladen.
Wenn du das File runtergeladen hast, entpackst du es nach:
-> Apple: Macintosh HD
-> Windows: C:/

 Diese Adresse musst du dann auch bei den "Header Search Paths" angeben. Aber dazu später.

So, mal einen Zwischencheck:

Wir haben unsere IDE und unseren VST SDK. Wir können beginnen!


Nun genug der Floskeln, let's DSP!


PS: Einige meiner Kreationen findest du auf www.chrisivanschrago.at