Initial release
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pluginterfaces/base/funknown.h"
|
||||
#include "pluginterfaces/vst/vsttypes.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
//------------------------------------------------------------------------
|
||||
static const FUID ProcessorUID (0xC18D3C1E, 0x719E4E29, 0x924D3ECA, 0xA5E4DA18);
|
||||
static const FUID ControllerUID (0xC244B7E6, 0x24084E20, 0xA24A8C43, 0xF84C8BE8);
|
||||
|
||||
#define DataExchangeVST3Category "Fx"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "pids.h"
|
||||
#include "public.sdk/source/vst/vsteditcontroller.h"
|
||||
#include "base/source/fstreamer.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
using namespace Steinberg::Vst;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class Controller : public EditController
|
||||
{
|
||||
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API Controller::initialize (FUnknown* context)
|
||||
{
|
||||
tresult result = EditController::initialize (context);
|
||||
if (result != kResultOk)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
parameters.addParameter (STR ("Gain"), STR ("%"), 0, 1., ParameterInfo::kCanAutomate,
|
||||
ParameterID::Gain);
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API Controller::setComponentState (IBStream* state)
|
||||
{
|
||||
if (!state)
|
||||
return kInvalidArgument;
|
||||
|
||||
IBStreamer streamer (state, kLittleEndian);
|
||||
|
||||
ParamValue value;
|
||||
if (!streamer.readDouble (value))
|
||||
return kResultFalse;
|
||||
|
||||
if (auto param = parameters.getParameter (ParameterID::Gain))
|
||||
param->setNormalized (value);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
FUnknown* createControllerInstance (void*)
|
||||
{
|
||||
return static_cast<IEditController*> (new Controller);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Steinberg::Tutorial
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "cids.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "public.sdk/source/main/pluginfactory.h"
|
||||
#include "pluginterfaces/vst/ivsteditcontroller.h"
|
||||
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
||||
|
||||
#define stringPluginName "advanced-techniques-tutorial"
|
||||
|
||||
using namespace Steinberg;
|
||||
using namespace Steinberg::Vst;
|
||||
using namespace Steinberg::Tutorial;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg::Tutorial {
|
||||
FUnknown* createProcessorInstance (void*);
|
||||
FUnknown* createControllerInstance (void*);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// VST Plug-in Entry
|
||||
//------------------------------------------------------------------------
|
||||
// Windows: do not forget to include a .def file in your project to export
|
||||
// GetPluginFactory function!
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
BEGIN_FACTORY_DEF ("Steinberg Media Technologies",
|
||||
"https://steinberg.net",
|
||||
"mailto:info@steinberg.de")
|
||||
|
||||
//---First Plug-in included in this factory-------
|
||||
// its kVstAudioEffectClass component
|
||||
DEF_CLASS2 (INLINE_UID_FROM_FUID(ProcessorUID),
|
||||
PClassInfo::kManyInstances, // cardinality
|
||||
kVstAudioEffectClass, // the component category (do not changed this)
|
||||
stringPluginName, // here the Plug-in name (to be changed)
|
||||
Vst::kDistributable, // means that component and controller could be distributed on different computers
|
||||
DataExchangeVST3Category, // Subcategory for this Plug-in (to be changed)
|
||||
FULL_VERSION_STR, // Plug-in version (to be changed)
|
||||
kVstVersionString, // the VST 3 SDK version (do not changed this, use always this define)
|
||||
createProcessorInstance)// function pointer called when this component should be instantiated
|
||||
|
||||
// its kVstComponentControllerClass component
|
||||
DEF_CLASS2 (INLINE_UID_FROM_FUID (ControllerUID),
|
||||
PClassInfo::kManyInstances, // cardinality
|
||||
kVstComponentControllerClass,// the Controller category (do not changed this)
|
||||
stringPluginName "Controller", // controller name (could be the same than component name)
|
||||
0, // not used here
|
||||
"", // not used here
|
||||
FULL_VERSION_STR, // Plug-in version (to be changed)
|
||||
kVstVersionString, // the VST 3 SDK version (do not changed this, use always this define)
|
||||
createControllerInstance)// function pointer called when this component should be instantiated
|
||||
|
||||
//----for others Plug-ins contained in this factory, put like for the first Plug-in different DEF_CLASS2---
|
||||
|
||||
END_FACTORY
|
||||
@@ -0,0 +1,17 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum ParameterID
|
||||
{
|
||||
Gain = 1,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Steinberg::Tutorial
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "cids.h"
|
||||
#include "pids.h"
|
||||
#include "public.sdk/source/vst/utility/audiobuffers.h"
|
||||
#include "public.sdk/source/vst/utility/processdataslicer.h"
|
||||
#include "public.sdk/source/vst/utility/rttransfer.h"
|
||||
#include "public.sdk/source/vst/utility/sampleaccurate.h"
|
||||
#include "public.sdk/source/vst/vstaudioeffect.h"
|
||||
#include "base/source/fstreamer.h"
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
using namespace Steinberg::Vst;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct StateModel
|
||||
{
|
||||
double gain;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct MyEffect : public AudioEffect
|
||||
{
|
||||
using RTTransfer = RTTransferT<StateModel>;
|
||||
|
||||
MyEffect ();
|
||||
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API terminate () SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
|
||||
SpeakerArrangement* outputs,
|
||||
int32 numOuts) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API process (ProcessData& data) SMTG_OVERRIDE;
|
||||
|
||||
void handleParameterChanges (IParameterChanges* changes);
|
||||
|
||||
template <SymbolicSampleSizes SampleSize>
|
||||
void process (ProcessData& data);
|
||||
|
||||
SampleAccurate::Parameter gainParameter {ParameterID::Gain, 1.};
|
||||
RTTransfer stateTransfer;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
MyEffect::MyEffect ()
|
||||
{
|
||||
setControllerClass (ControllerUID);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::initialize (FUnknown* context)
|
||||
{
|
||||
auto result = AudioEffect::initialize (context);
|
||||
if (result == kResultTrue)
|
||||
{
|
||||
addAudioInput (STR ("Input"), SpeakerArr::kStereo);
|
||||
addAudioOutput (STR ("Output"), SpeakerArr::kStereo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::terminate ()
|
||||
{
|
||||
stateTransfer.clear_ui ();
|
||||
return AudioEffect::terminate ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::setState (IBStream* state)
|
||||
{
|
||||
if (!state)
|
||||
return kInvalidArgument;
|
||||
|
||||
IBStreamer streamer (state, kLittleEndian);
|
||||
|
||||
uint32 numParams;
|
||||
if (streamer.readInt32u (numParams) == false)
|
||||
return kResultFalse;
|
||||
|
||||
auto model = std::make_unique<StateModel> ();
|
||||
|
||||
ParamValue value;
|
||||
if (!streamer.readDouble (value))
|
||||
return kResultFalse;
|
||||
|
||||
model->gain = value;
|
||||
|
||||
stateTransfer.transferObject_ui (std::move (model));
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::getState (IBStream* state)
|
||||
{
|
||||
if (!state)
|
||||
return kInvalidArgument;
|
||||
|
||||
IBStreamer streamer (state, kLittleEndian);
|
||||
streamer.writeDouble (gainParameter.getValue ());
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
|
||||
SpeakerArrangement* outputs, int32 numOuts)
|
||||
{
|
||||
if (numIns != 1 || numOuts != 1)
|
||||
return kResultFalse;
|
||||
if (SpeakerArr::getChannelCount (inputs[0]) == SpeakerArr::getChannelCount (outputs[0]))
|
||||
{
|
||||
getAudioInput (0)->setArrangement (inputs[0]);
|
||||
getAudioOutput (0)->setArrangement (outputs[0]);
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::canProcessSampleSize (int32 symbolicSampleSize)
|
||||
{
|
||||
return (symbolicSampleSize == SymbolicSampleSizes::kSample32 ||
|
||||
symbolicSampleSize == SymbolicSampleSizes::kSample64) ?
|
||||
kResultTrue :
|
||||
kResultFalse;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <SymbolicSampleSizes SampleSize>
|
||||
void MyEffect::process (ProcessData& data)
|
||||
{
|
||||
ProcessDataSlicer slicer (8);
|
||||
|
||||
auto doProcessing = [this] (ProcessData& data) {
|
||||
// get the gain value for this block
|
||||
ParamValue gain = gainParameter.advance (data.numSamples);
|
||||
|
||||
// process audio
|
||||
AudioBusBuffers* inputs = data.inputs;
|
||||
AudioBusBuffers* outputs = data.outputs;
|
||||
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
|
||||
{
|
||||
auto inputBuffers = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
|
||||
auto outputBuffers = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
|
||||
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
|
||||
{
|
||||
auto sample = inputBuffers[sampleIndex];
|
||||
outputBuffers[sampleIndex] = sample * gain;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
slicer.process<SampleSize> (data, doProcessing);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MyEffect::handleParameterChanges (IParameterChanges* changes)
|
||||
{
|
||||
if (!changes)
|
||||
return;
|
||||
int32 changeCount = changes->getParameterCount ();
|
||||
for (auto i = 0; i < changeCount; ++i)
|
||||
{
|
||||
if (auto queue = changes->getParameterData (i))
|
||||
{
|
||||
auto paramID = queue->getParameterId ();
|
||||
if (paramID == ParameterID::Gain)
|
||||
{
|
||||
gainParameter.beginChanges (queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API MyEffect::process (ProcessData& data)
|
||||
{
|
||||
stateTransfer.accessTransferObject_rt (
|
||||
[this] (const auto& stateModel) { gainParameter.setValue (stateModel.gain); });
|
||||
|
||||
handleParameterChanges (data.inputParameterChanges);
|
||||
|
||||
if (processSetup.symbolicSampleSize == SymbolicSampleSizes::kSample32)
|
||||
process<SymbolicSampleSizes::kSample32> (data);
|
||||
else
|
||||
process<SymbolicSampleSizes::kSample64> (data);
|
||||
|
||||
gainParameter.endChanges ();
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
FUnknown* createProcessorInstance (void*)
|
||||
{
|
||||
return static_cast<IAudioProcessor*> (new MyEffect);
|
||||
}
|
||||
|
||||
} // Steinberg::Tutorial
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pluginterfaces/base/fplatform.h"
|
||||
|
||||
// Plain project version file generated by cmake
|
||||
#include "projectversion.h"
|
||||
|
||||
#define stringOriginalFilename "advanced-techniques-tutorial.vst3"
|
||||
#if SMTG_PLATFORM_64
|
||||
#define stringFileDescription "advanced-techniques-tutorial VST3 (64Bit)"
|
||||
#else
|
||||
#define stringFileDescription "advanced-techniques-tutorial VST3"
|
||||
#endif
|
||||
#define stringCompanyName "Steinberg Media Technologies\0"
|
||||
#define stringLegalCopyright "Copyright(c) 2023 Steinberg Media Technologies."
|
||||
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"
|
||||
Reference in New Issue
Block a user