again.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 // Project     : VST SDK
00003 // Version     : 3.0
00004 //
00005 // Category    : Examples
00006 // Filename    : again.cpp
00007 // Created by  : Steinberg, 04/2005
00008 // Modified    : $Date: 2008/01/16 07:48:35 $
00009 // Description : AGain Example for VST SDK 3.0
00010 //-----------------------------------------------------------------------------
00011 // LICENSE
00012 // © 2008, Steinberg Media Technologies GmbH, All Rights Reserved
00013 //-----------------------------------------------------------------------------
00014 // This Software Development Kit may not be distributed in parts or its entirety  
00015 // without prior written agreement by Steinberg Media Technologies GmbH. 
00016 // This SDK must not be used to re-engineer or manipulate any technology used  
00017 // in any Steinberg or Third-party application or software module, 
00018 // unless permitted by law.
00019 // Neither the name of the Steinberg Media Technologies nor the names of its
00020 // contributors may be used to endorse or promote products derived from this 
00021 // software without specific prior written permission.
00022 // 
00023 // THIS SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND
00024 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00025 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00026 // IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, 
00027 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
00028 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00029 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
00030 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00031 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032 // OF THE POSSIBILITY OF SUCH DAMAGE.
00033 //-----------------------------------------------------------------------------
00034 
00035 //------------------------------------------------------------------------
00036 #define INIT_CLASS_IID
00037 // This macro definition modifies the behavior of DECLARE_CLASS_IID (funknown.h)
00038 // and produces the actual symbols for all interface identifiers.
00039 // It must be defined before including the interface headers and
00040 // in only one source file!
00041 //------------------------------------------------------------------------
00042 
00043 #include "again.h"
00044 #include "againparamids.h"
00045 #include "againeditor.h" // here in order to produce all interface identifiers required by editor
00046 
00047 #include "pluginterfaces/base/ibstream.h"
00048 #include "pluginterfaces/vst/ivstparameterchanges.h"
00049 #include "pluginterfaces/vst/ivstevents.h"
00050 
00051 #include <stdio.h>
00052 
00053 #define AGAIN_TEST 1 // this allows to enable the communication example between again and its controller
00054 
00055 //------------------------------------------------------------------------
00056 // AGain Implementation
00057 //------------------------------------------------------------------------
00058 AGain::AGain ()
00059 : fGain (1.f)
00060 , fGainReduction (0.f)
00061 , fVuPPMOld (0.f)
00062 , currentProcessMode (-1) // -1 means not initialized
00063 , bHalfGain (false)
00064 , bBypass (false)
00065 {
00066         // register its editor class (the same than used in againentry.cpp)
00067         setControllerClass (FUID (gControllerUID));
00068 }
00069 
00070 //------------------------------------------------------------------------
00071 tresult PLUGIN_API AGain::initialize (FUnknown* context)
00072 {
00073         //---always initialize the parent-------
00074         tresult result = AudioEffect::initialize (context);
00075         // if everything Ok, continue
00076         if (result != kResultOk)
00077                 return result;
00078 
00079         //---create Audio In/Out busses------
00080         // we want a stereo Input and a Stereo Output
00081         addAudioInput  (USTRING ("Stereo In"),  SpeakerArr::kStereo);
00082         addAudioOutput (USTRING ("Stereo Out"), SpeakerArr::kStereo);
00083 
00084         //---create Midi In/Out busses (1 bus with only 1 channel)------
00085         addEventInput (USTRING ("Midi In"), 1);
00086 
00087         return kResultOk;
00088 }
00089 
00090 //------------------------------------------------------------------------
00091 tresult PLUGIN_API AGain::terminate  ()
00092 {
00093         // nothing to do here yet...except calling our parent terminate
00094         return AudioEffect::terminate ();
00095 }
00096 
00097 //------------------------------------------------------------------------
00098 tresult PLUGIN_API AGain::setActive (TBool state)
00099 {
00100 #if AGAIN_TEST
00101         if (state)
00102                 sendTextMessage ("AGain::setActive (true)");
00103         else
00104                 sendTextMessage ("AGain::setActive (false)");
00105 #endif
00106         
00107         // reset the VuMeter value
00108         fVuPPMOld = 0.f;
00109 
00110         // call our parent setActive
00111         return AudioEffect::setActive (state);
00112 }
00113 
00114 //------------------------------------------------------------------------
00115 tresult PLUGIN_API AGain::process (ProcessData& data)
00116 {
00117         // finally the process function
00118         // In this example there are 4 steps:
00119         // 1) Read inputs parameters coming from host (in order to adapt our model values)
00120         // 2) Read inputs events coming from host (we apply a gain reduction depending of the velocity of pressed key)
00121         // 3) Process the gain of the input buffer to the output buffer
00122         // 4) Write the new VUmeter value to the output Parameters queue
00123 
00124 
00125         //---1) Read inputs parameter changes-----------
00126         IParameterChanges* paramChanges = data.inputParameterChanges;
00127         if (paramChanges)
00128         {
00129                 int32 numParamsChanged = paramChanges->getParameterCount ();
00130                 // for each parameter which are some changes in this audio block:
00131                 for (int32 i = 0; i < numParamsChanged; i++)
00132                 {
00133                         IParamValueQueue* paramQueue = paramChanges->getParameterData (i);
00134                         if (paramQueue)
00135                         {
00136                                 int32 offsetSamples;
00137                                 double value;
00138                                 int32 numPoints = paramQueue->getPointCount ();                         
00139                                 switch (paramQueue->getParameterId ())
00140                                 {
00141                                         case kGainId:
00142                                                 // we use in this example only the last point of the queue.
00143                                                 // in some wanted case for specific kind of parameter it makes sense to retrieve all points
00144                                                 // and process the whole audio block in small blocks.
00145                                                 if (paramQueue->getPoint (numPoints - 1,  offsetSamples, value) == kResultTrue)
00146                                                         fGain = (float)value;
00147                                                 break;
00148 
00149                                         case kBypassId:
00150                                                 if (paramQueue->getPoint (numPoints - 1,  offsetSamples, value) == kResultTrue)
00151                                                         bBypass = (value > 0.5f);
00152                                                 break;
00153                                 }
00154                         }
00155                 }
00156         }
00157         
00158         //---2) Read input events-------------
00159         IEventList* eventList = data.inputEvents;
00160         if (eventList) 
00161         {
00162                 int32 numEvent = eventList->getEventCount ();
00163                 for (int32 i = 0; i < numEvent; i++)
00164                 {
00165                         Event event;
00166                         if (eventList->getEvent (i, event) == kResultOk)
00167                         {
00168                                 switch (event.type)
00169                                 {
00170                                         //----------------------
00171                                         case Event::kNoteOnEvent:
00172                                                 // use the velocity as gain modifier
00173                                                 fGainReduction = event.noteOn.velocity;
00174                                                 break;
00175                                         
00176                                         //----------------------
00177                                         case Event::kNoteOffEvent:
00178                                                 // noteOff reset the reduction
00179                                                 fGainReduction = 0.f;
00180                                                 break;
00181                                 }
00182                         }
00183                 }
00184         }
00185                 
00186         //-------------------------------------
00187         //---3) Process Audio---------------------
00188         //-------------------------------------
00189         if (data.numInputs == 0 || data.numOutputs == 0)
00190         {
00191                 // nothing to do
00192                 return kResultOk;
00193         }
00194 
00195         //---check if silence---------------
00196         // normally we have to check each channel (simplification)
00197         if (data.inputs[0].silenceFlags)
00198         {
00199                 // mark output silence too
00200                 data.outputs[0].silenceFlags = data.inputs[0].silenceFlags;
00201                 
00202                 // nothing to do
00203                 return kResultOk;
00204         }
00205 
00206         // (simplification) we suppose in this example that we have the same input channel count than the output
00207         int32 numChannels = data.inputs[0].numChannels;
00208 
00209         //---get audio buffers----------------
00210         float** in  = data.inputs[0].channelBuffers32;
00211         float** out = data.outputs[0].channelBuffers32;
00212         
00213         //---in bypass mode outputs should be like inputs-----
00214         if (bBypass)
00215         {
00216                 int32 sampleFrames = data.numSamples;
00217                 for (int32 i = 0; i < numChannels; i++)
00218                 {
00219                         // dont need to be copied if the buffers are the same
00220                         if (in[i] != out[i])
00221                                 memcpy (out[i], in[i], sampleFrames * sizeof (float));
00222                 }
00223                 // in this example we dont update the VuMeter in Bypass
00224         }
00225         else
00226         {
00227                 float fVuPPM = 0.f;
00228 
00229                 //---apply gain factor----------
00230                 float gain = (fGain - fGainReduction);
00231                 if (gain < 0)
00232                 {
00233                         // output is silent
00234                         for (int32 i = 0; i < numChannels; i++)
00235                         {
00236                                 int32 sampleFrames = data.numSamples;
00237                                 float* ptr = out[i];
00238                                 while (--sampleFrames >= 0)
00239                                 {
00240                                         (*ptr++) = 0.f;
00241                                 }
00242                         }
00243                 }
00244                 else
00245                 {
00246                         if (bHalfGain)
00247                                 gain = gain * 0.5f;
00248 
00249                         // in real plugin it would be better to do dezippering to avoid jump (click) in gain value
00250                         for (int32 i = 0; i < numChannels; i++)
00251                         {
00252                                 int32 sampleFrames = data.numSamples;
00253                                 float* ptrIn  = in[i];
00254                                 float* ptrOut = out[i];
00255                                 float tmp;
00256                                 while (--sampleFrames >= 0)
00257                                 {
00258                                         // apply gain
00259                                         tmp = (*ptrIn++) * gain;
00260                                         (*ptrOut++) = tmp;
00261 
00262                                         // check only positiv values
00263                                         if (tmp > fVuPPM)
00264                                                 fVuPPM = tmp;
00265                                 }
00266                         }
00267                 }
00268 
00269                 //---3) Write outputs parameter changes-----------
00270                 IParameterChanges* paramChanges = data.outputParameterChanges;
00271                 // a new value of VuMeter will be send to the host 
00272                 // (the host will send it back in sync to our controller for updating our editor)
00273                 if (paramChanges && fVuPPMOld != fVuPPM)
00274                 {
00275                         int32 index = 0;
00276                         IParamValueQueue* paramQueue = paramChanges->addParameterData (kVuPPMId, index);
00277                         if (paramQueue)
00278                         {
00279                                 int32 index2 = 0;
00280                                 paramQueue->addPoint (0, fVuPPM, index2); 
00281                         }
00282                 }
00283                 fVuPPMOld = fVuPPM;
00284         }
00285 
00286         return kResultOk;
00287 }
00288 
00289 //------------------------------------------------------------------------
00290 tresult AGain::receiveText (const char* text)
00291 {
00292         // received from Controller
00293         fprintf (stderr, "[AGain] received: ");
00294         fprintf (stderr, text);
00295         fprintf (stderr, "\n");
00296         
00297         bHalfGain = !bHalfGain;
00298 
00299         return kResultOk;
00300 }
00301 
00302 //------------------------------------------------------------------------
00303 tresult PLUGIN_API AGain::setState (IBStream* state)
00304 {
00305         // called when we load a preset, the model has to be reloaded
00306 
00307         float savedGain = 0.f;
00308         if (state->read (&savedGain, 4) != kResultOk)
00309                 return kResultFalse;
00310 
00311         float savedGainReduction = 0.f;
00312         if (state->read (&savedGainReduction, 4) != kResultOk)
00313                 return kResultFalse;
00314 
00315 #if BYTEORDER == kBigEndian
00316         SWAP_32 (savedGain)
00317         SWAP_32 (savedGainReduction)
00318 #endif
00319         
00320         fGain = savedGain;
00321         fGainReduction = savedGainReduction;
00322 
00323         return kResultOk;
00324 }
00325 
00326 //------------------------------------------------------------------------
00327 tresult PLUGIN_API AGain::getState (IBStream* state)
00328 {
00329         // here we need to save the model
00330 
00331         float savedGain = fGain;
00332         float savedGainReduction = fGainReduction;
00333 
00334 #if BYTEORDER == kBigEndian
00335         SWAP_32 (savedGain)
00336         SWAP_32 (savedGainReduction)
00337 #endif
00338 
00339         state->write (&savedGain, 4);
00340         return state->write (&savedGainReduction, 4);
00341 }
00342 
00343 //------------------------------------------------------------------------
00344 tresult PLUGIN_API AGain::setupProcessing (ProcessSetup& newSetup)
00345 {
00346         // called before the process call, always in a disable state (not active)
00347         
00348         // here we keep a trace of the processing mode (offline,...) for example.
00349         currentProcessMode = newSetup.processMode;
00350         
00351         return AudioEffect::setupProcessing (newSetup);
00352 }
00353 
00354 //------------------------------------------------------------------------
00355 tresult PLUGIN_API AGain::setBusArrangements (SpeakerArrangement* inputs, int32 numIns, SpeakerArrangement* outputs, int32 numOuts)
00356 {
00357         if (numIns == 1 && numOuts == 1)
00358         {
00359                 if (inputs[0] == SpeakerArr::kMono && outputs[0] == SpeakerArr::kMono)
00360                 {
00361                         AudioBus* bus = (AudioBus*)(audioInputs.at (0));
00362                         if (bus)
00363                         {
00364                                 if (bus->getArrangement () != SpeakerArr::kMono)
00365                                 {
00366                                         removeAudioBusses ();
00367                                         addAudioInput  (USTRING ("Mono In"),  SpeakerArr::kMono);
00368                                         addAudioOutput (USTRING ("Mono Out"), SpeakerArr::kMono);
00369                                 }
00370                                 return kResultOk;
00371                         }
00372                 }
00373                 else
00374                 {
00375                         AudioBus* bus = (AudioBus*)(audioInputs.at (0));
00376                         if (bus)
00377                         {
00378                                 if (bus->getArrangement () != SpeakerArr::kStereo)
00379                                 {
00380                                         removeAudioBusses ();
00381                                         addAudioInput  (USTRING ("Stereo In"),  SpeakerArr::kStereo);
00382                                         addAudioOutput (USTRING ("Stereo Out"), SpeakerArr::kStereo);
00383                                 }
00384                                 return kResultOk;
00385                         }
00386                 }
00387         }
00388         return kResultFalse;
00389 
00390 }
Empty

Copyright ©2008 Steinberg Media Technologies. All Rights Reserved.