Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.25.0)
project(smtg-vst3-again-sampleaccurate
VERSION ${vstsdk_VERSION}.0
DESCRIPTION "Steinberg VST 3 AGain example"
)
smtg_add_vst3plugin(again-sample-accurate
source/agsa_controller.cpp
source/agsa_factory.cpp
source/agsa_processor.cpp
source/agsa.h
source/tutorial.cpp
source/tutorial.h
source/version.h
${SDK_ROOT}/public.sdk/source/vst/utility/test/sampleaccuratetest.cpp
${SDK_ROOT}/public.sdk/source/vst/utility/test/rttransfertest.cpp
)
target_link_libraries(again-sample-accurate
PRIVATE
sdk_hosting
)
smtg_target_setup_as_vst3_example(again-sample-accurate)
@@ -0,0 +1,18 @@
# AGain Sample Accurate
## Introduction
AGain Sample Accurate is the variant of the AGain FX plug-in showing how to achieve sample-accurate processing for the gain value.
> See also: [Online Documentation](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Examples.html#again-sample-accurate).
## Getting Started
This plug-in is part of the VST 3 SDK package. It is created with the VST 3 SDK root project.
> See the top-level README of the VST 3 SDK: https://github.com/steinbergmedia/vst3sdk.git
## Getting Help
* Read through the SDK documentation on the **[VST 3 Developer Portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html)**
* Ask some real people in the official **[VST 3 Developer Forum](https://forums.steinberg.net/c/developer/103)**
@@ -0,0 +1,45 @@
#include <windows.h>
#include "../source/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Version
/////////////////////////////////////////////////////////////////////////////
VS_VERSION_INFO VERSIONINFO
FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040004e4"
BEGIN
VALUE "FileVersion", FULL_VERSION_STR
VALUE "ProductVersion", FULL_VERSION_STR
VALUE "OriginalFilename", stringOriginalFilename
VALUE "FileDescription", stringFileDescription
VALUE "InternalName", stringFileDescription
VALUE "ProductName", stringFileDescription
VALUE "CompanyName", stringCompanyName
VALUE "LegalCopyright", stringLegalCopyright
VALUE "LegalTrademarks", stringLegalTrademarks
//VALUE "PrivateBuild", " \0"
//VALUE "SpecialBuild", " \0"
//VALUE "Comments", " \0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END
@@ -0,0 +1,46 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa.h
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/vst/vsttypes.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
static const FUID ProcessorID (0xC18D3C1E, 0x719E4E29, 0x924D3ECA, 0xA5E4DA18);
static const FUID ControllerID (0xC244B7E6, 0x24084E20, 0xA24A8C43, 0xF84C8BE8);
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*);
FUnknown* createControllerInstance (void*);
//------------------------------------------------------------------------
enum ParameterID : ParamID
{
Bypass,
Gain,
};
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,92 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_controller.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.h"
#include "public.sdk/source/vst/vsteditcontroller.h"
#include "base/source/fstreamer.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
class Controller : public EditController
{
tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
tresult PLUGIN_API terminate () 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 ("Bypass"), nullptr, 1, 0.,
ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass,
ParameterID::Bypass);
parameters.addParameter (STR ("Gain"), STR ("%"), 0, 1., ParameterInfo::kCanAutomate,
ParameterID::Gain);
return kResultOk;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::terminate ()
{
return EditController::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API Controller::setComponentState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
uint32 numParams;
if (streamer.readInt32u (numParams) == false)
return kResultFalse;
ParamID pid;
ParamValue value;
for (uint32 i = 0u; i < numParams; ++i)
{
if (!streamer.readInt32u (pid))
break;
if (!streamer.readDouble (value))
break;
if (auto param = parameters.getParameter (pid))
param->setNormalized (value);
}
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createControllerInstance (void*)
{
return static_cast<IEditController*> (new Controller);
}
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,60 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_factory.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.h"
#include "tutorial.h"
#include "version.h"
#include "public.sdk/source/main/pluginfactory.h"
#include "public.sdk/source/vst/utility/testing.h"
#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"
#define stringPluginName "AGain Sample Accurate"
using namespace Steinberg;
using namespace Steinberg::Vst;
using namespace Steinberg::Vst::AgainSampleAccurate;
//------------------------------------------------------------------------
// VST Plug-in Factory
//------------------------------------------------------------------------
BEGIN_FACTORY_DEF (stringCompanyName, stringCompanyWeb, stringCompanyEmail)
// AGain sample accurate
DEF_CLASS2 (INLINE_UID_FROM_FUID (ProcessorID), PClassInfo::kManyInstances, kVstAudioEffectClass,
stringPluginName, Vst::kDistributable, "Fx", FULL_VERSION_STR, kVstVersionString,
createProcessorInstance)
DEF_CLASS2 (INLINE_UID_FROM_FUID (ControllerID), PClassInfo::kManyInstances,
kVstComponentControllerClass, stringPluginName "Controller", 0, "", FULL_VERSION_STR,
kVstVersionString, createControllerInstance)
// Test
DEF_CLASS2 (INLINE_UID_FROM_FUID (getTestFactoryUID ()), PClassInfo::kManyInstances, kTestClass,
stringPluginName "Test Factory", 0, "", "", "", createTestFactoryInstance)
// Tutorial
DEF_CLASS2 (INLINE_UID_FROM_FUID (Tutorial::ProcessorID), PClassInfo::kManyInstances,
kVstAudioEffectClass, "Advanced Tutorial", Vst::kDistributable, "Fx", FULL_VERSION_STR,
kVstVersionString, Tutorial::createProcessorInstance)
DEF_CLASS2 (INLINE_UID_FROM_FUID (Tutorial::ControllerID), PClassInfo::kManyInstances,
kVstComponentControllerClass, "Advanced Tutorial Controller", 0, "", FULL_VERSION_STR,
kVstVersionString, Tutorial::createControllerInstance)
END_FACTORY
@@ -0,0 +1,264 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/agsa_processor.cpp
// Created by : Steinberg, 04/2021
// Description : AGain with Sample Accurate Parameter Changes
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "agsa.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 {
namespace Vst {
namespace AgainSampleAccurate {
//------------------------------------------------------------------------
struct Processor : public AudioEffect
{
using ParameterVector = std::vector<std::pair<ParamID, ParamValue>>;
using RTTransfer = RTTransferT<ParameterVector>;
Processor ();
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);
std::array<SampleAccurate::Parameter, 2> parameters;
RTTransfer stateTransfer;
};
//------------------------------------------------------------------------
Processor::Processor ()
{
setControllerClass (ControllerID);
parameters[0].setParamID (ParameterID::Bypass);
parameters[1].setParamID (ParameterID::Gain);
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::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 Processor::terminate ()
{
stateTransfer.clear_ui ();
return AudioEffect::terminate ();
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::setState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
uint32 numParams;
if (streamer.readInt32u (numParams) == false)
return kResultFalse;
auto paramChanges = std::make_unique<ParameterVector> ();
ParamID pid;
ParamValue value;
for (uint32 i = 0u; i < numParams; ++i)
{
if (!streamer.readInt32u (pid))
break;
if (!streamer.readDouble (value))
break;
for (auto& param : parameters)
{
if (param.getParamID () == pid)
{
paramChanges->emplace_back (std::make_pair (pid, value));
break;
}
}
}
stateTransfer.transferObject_ui (std::move (paramChanges));
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::getState (IBStream* state)
{
if (!state)
return kInvalidArgument;
IBStreamer streamer (state, kLittleEndian);
streamer.writeInt32u (static_cast<uint32> (parameters.size ()));
for (auto& param : parameters)
{
streamer.writeInt32u (param.getParamID ());
streamer.writeDouble (param.getValue ());
}
return kResultTrue;
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::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 Processor::canProcessSampleSize (int32 symbolicSampleSize)
{
return (symbolicSampleSize == SymbolicSampleSizes::kSample32 ||
symbolicSampleSize == SymbolicSampleSizes::kSample64) ?
kResultTrue :
kResultFalse;
}
//------------------------------------------------------------------------
template <SymbolicSampleSizes SampleSize>
void Processor::process (ProcessData& data)
{
using SampleT = typename std::conditional<SampleSize == SymbolicSampleSizes::kSample32, float,
double>::type;
static constexpr auto SliceSize = 16u;
ProcessDataSlicer slicer (SliceSize);
std::array<SampleT, SliceSize> againValueBuffer;
auto doProcessing = [this, &againValueBuffer] (ProcessData& data) {
parameters[ParameterID::Bypass].advance (data.numSamples);
auto inputs = data.inputs;
auto outputs = data.outputs;
if (parameters[ParameterID::Bypass].getValue () > 0.5)
{
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
{
auto inChannelBuffer = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
auto outChannelBuffer = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
{
outChannelBuffer[sampleIndex] = inChannelBuffer[sampleIndex];
}
}
return;
}
for (auto i = 0; i < data.numSamples; ++i)
againValueBuffer[i] = static_cast<SampleT> (parameters[ParameterID::Gain].advance (1));
for (auto channelIndex = 0; channelIndex < inputs[0].numChannels; ++channelIndex)
{
auto inChannelBuffer = getChannelBuffers<SampleSize> (inputs[0])[channelIndex];
auto outChannelBuffer = getChannelBuffers<SampleSize> (outputs[0])[channelIndex];
for (auto sampleIndex = 0; sampleIndex < data.numSamples; ++sampleIndex)
{
auto sample = inChannelBuffer[sampleIndex] * againValueBuffer[sampleIndex];
outChannelBuffer[sampleIndex] = sample;
}
}
};
slicer.process<SampleSize> (data, doProcessing);
}
//------------------------------------------------------------------------
void Processor::handleParameterChanges (IParameterChanges* changes)
{
if (changes)
{
auto changeCount = changes->getParameterCount ();
for (auto i = 0; i < changeCount; ++i)
{
if (auto queue = changes->getParameterData (i))
{
auto paramID = queue->getParameterId ();
if (paramID >= ParameterID::Bypass && paramID <= ParameterID::Gain)
parameters[paramID].beginChanges (queue);
}
}
}
}
//------------------------------------------------------------------------
tresult PLUGIN_API Processor::process (ProcessData& data)
{
stateTransfer.accessTransferObject_rt ([this] (const auto& stateChanges) {
for (const auto& change : stateChanges)
{
if (change.first >= ParameterID::Bypass && change.first <= ParameterID::Gain)
parameters[change.first].setValue (change.second);
}
});
handleParameterChanges (data.inputParameterChanges);
if (data.numSamples > 0)
{
if (processSetup.symbolicSampleSize == SymbolicSampleSizes::kSample32)
process<SymbolicSampleSizes::kSample32> (data);
else
process<SymbolicSampleSizes::kSample64> (data);
}
for (auto& param : parameters)
param.endChanges ();
return kResultTrue;
}
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*)
{
return static_cast<IAudioProcessor*> (new Processor);
}
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,273 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/tutorial.cpp
// Created by : Steinberg, 04/2021
// Description : Tutorial
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#include "tutorial.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 "public.sdk/source/vst/vsteditcontroller.h"
#include "base/source/fstreamer.h"
#include <array>
#include <cassert>
#include <limits>
#include <vector>
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace Tutorial {
//------------------------------------------------------------------------
enum ParameterID
{
Gain = 1,
};
//------------------------------------------------------------------------
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 (ControllerID);
}
//------------------------------------------------------------------------
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);
}
//------------------------------------------------------------------------
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);
}
//------------------------------------------------------------------------
} // Tutorial
} // Vst
} // Steinberg
@@ -0,0 +1,39 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/tutorial.h
// Created by : Steinberg, 04/2021
// Description : Tutorial
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/vst/vsttypes.h"
//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {
namespace Tutorial {
//------------------------------------------------------------------------
static const FUID ProcessorID (0xCC48BF25, 0x529043DA, 0x80223510, 0xFFE8BD02);
static const FUID ControllerID (0x3A89B2B2, 0x4F474E02, 0x9C96EE27, 0x0AD2A15B);
//------------------------------------------------------------------------
FUnknown* createProcessorInstance (void*);
FUnknown* createControllerInstance (void*);
//------------------------------------------------------------------------
} // AgainSampleAccurate
} // Vst
} // Steinberg
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------
// Project : VST SDK
//
// Category : Examples
// Filename : public.sdk/samples/vst/again_sampleaccurate/source/version.h
// Created by : Steinberg, 04/2021
// Description : Example of handle the versioning and copyright info of again sampleaccurate plug-in
// used for the resources (RC file for example)
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/fplatform.h"
// Plain project version file generated by cmake
#include "projectversion.h"
#define stringOriginalFilename "again_sampleaccurate.vst3"
#if SMTG_PLATFORM_64
#define stringFileDescription "AGain SampleAccurate VST3-SDK (64Bit)"
#else
#define stringFileDescription "AGain SampleAccurate VST3-SDK"
#endif
#define stringCompanyWeb "http://www.steinberg.net"
#define stringCompanyEmail "mailto:info@steinberg.de"
#define stringCompanyName "Steinberg Media Technologies"
#define stringLegalCopyright "© 2025 Steinberg Media Technologies"
#define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH"