Initial release
This commit is contained in:
+26
@@ -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)**
|
||||
+45
@@ -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
|
||||
|
||||
+46
@@ -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
|
||||
Vendored
+92
@@ -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
|
||||
+60
@@ -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
|
||||
Vendored
+264
@@ -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
|
||||
+273
@@ -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
|
||||
+39
@@ -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
|
||||
+35
@@ -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"
|
||||
Reference in New Issue
Block a user