Initial release
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pluginterfaces/base/funknown.h"
|
||||
#include "pluginterfaces/vst/vsttypes.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
//------------------------------------------------------------------------
|
||||
static const Steinberg::FUID kDataExchangeProcessorUID (0xE35B96A9, 0x9BB353A9, 0x910130C1, 0x2C55EC26);
|
||||
static const Steinberg::FUID kDataExchangeControllerUID (0xADFD02D2, 0x20525504, 0x90D96683, 0xFD2DDF86);
|
||||
|
||||
#define DataExchangeVST3Category "Fx"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "cids.h"
|
||||
#include "controller.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DataExchangeController Implementation
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeController::notify (Vst::IMessage* message)
|
||||
{
|
||||
if (dataExchange.onMessage (message))
|
||||
return kResultTrue;
|
||||
return EditControllerEx1::notify (message);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void PLUGIN_API DataExchangeController::queueOpened (Vst::DataExchangeUserContextID userContextID,
|
||||
uint32 blockSize,
|
||||
TBool& dispatchOnBackgroundThread)
|
||||
{
|
||||
FDebugPrint ("Data Exchange Queue opened.\n");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void PLUGIN_API DataExchangeController::queueClosed (Vst::DataExchangeUserContextID userContextID)
|
||||
{
|
||||
FDebugPrint ("Data Exchange Queue closed.\n");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void PLUGIN_API DataExchangeController::onDataExchangeBlocksReceived (
|
||||
Vst::DataExchangeUserContextID userContextID, uint32 numBlocks, Vst::DataExchangeBlock* blocks,
|
||||
TBool onBackgroundThread)
|
||||
{
|
||||
for (auto index = 0u; index < numBlocks; ++index)
|
||||
{
|
||||
auto dataBlock = toDataBlock (blocks[index]);
|
||||
FDebugPrint (
|
||||
"Received Data Block: SampleRate: %d, SampleSize: %d, NumChannels: %d, NumSamples: %d\n",
|
||||
dataBlock->sampleRate, static_cast<uint32_t> (dataBlock->sampleSize),
|
||||
static_cast<uint32_t> (dataBlock->numChannels),
|
||||
static_cast<uint32_t> (dataBlock->numSamples));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dataexchange.h"
|
||||
#include "public.sdk/source/vst/vsteditcontroller.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DataExchangeController
|
||||
//------------------------------------------------------------------------
|
||||
class DataExchangeController : public Vst::EditControllerEx1, public Vst::IDataExchangeReceiver
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------
|
||||
// Create function
|
||||
static FUnknown* createInstance (void* /*context*/)
|
||||
{
|
||||
return (Vst::IEditController*)new DataExchangeController;
|
||||
}
|
||||
|
||||
// EditController
|
||||
tresult PLUGIN_API notify (Vst::IMessage* message) override;
|
||||
|
||||
// IDataExchangeReceiver
|
||||
void PLUGIN_API queueOpened (Vst::DataExchangeUserContextID userContextID, uint32 blockSize,
|
||||
TBool& dispatchOnBackgroundThread) override;
|
||||
void PLUGIN_API queueClosed (Vst::DataExchangeUserContextID userContextID) override;
|
||||
void PLUGIN_API onDataExchangeBlocksReceived (Vst::DataExchangeUserContextID userContextID,
|
||||
uint32 numBlocks, Vst::DataExchangeBlock* blocks,
|
||||
TBool onBackgroundThread) override;
|
||||
//---Interface---------
|
||||
DEFINE_INTERFACES
|
||||
// Here you can add more supported VST3 interfaces
|
||||
DEF_INTERFACE (Vst::IDataExchangeReceiver)
|
||||
END_DEFINE_INTERFACES (EditController)
|
||||
DELEGATE_REFCOUNT (EditController)
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
Vst::DataExchangeReceiverHandler dataExchange {this};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "public.sdk/source/vst/utility/dataexchange.h"
|
||||
#include <cstdint>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct DataBlock
|
||||
{
|
||||
uint32_t sampleRate;
|
||||
uint16_t sampleSize;
|
||||
uint16_t numChannels;
|
||||
uint32_t numSamples;
|
||||
float samples[0];
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline DataBlock* toDataBlock (const Vst::DataExchangeBlock& block)
|
||||
{
|
||||
if (block.blockID != Vst::InvalidDataExchangeBlockID)
|
||||
return reinterpret_cast<DataBlock*> (block.data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Steinberg::Tutorial
|
||||
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "processor.h"
|
||||
#include "controller.h"
|
||||
#include "cids.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "public.sdk/source/main/pluginfactory.h"
|
||||
|
||||
#define stringPluginName "dataexchange-tutorial"
|
||||
|
||||
using namespace Steinberg::Vst;
|
||||
using namespace Steinberg::Tutorial;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// 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(kDataExchangeProcessorUID),
|
||||
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)
|
||||
DataExchangeProcessor::createInstance) // function pointer called when this component should be instantiated
|
||||
|
||||
// its kVstComponentControllerClass component
|
||||
DEF_CLASS2 (INLINE_UID_FROM_FUID (kDataExchangeControllerUID),
|
||||
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)
|
||||
DataExchangeController::createInstance)// 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,168 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "cids.h"
|
||||
#include "processor.h"
|
||||
|
||||
#include "base/source/fstreamer.h"
|
||||
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr Vst::DataExchangeBlock kInvalidDataExchangeBlock = {
|
||||
nullptr, 0, Vst::InvalidDataExchangeBlockID};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DataExchangeProcessor
|
||||
//------------------------------------------------------------------------
|
||||
DataExchangeProcessor::DataExchangeProcessor ()
|
||||
{
|
||||
setControllerClass (kDataExchangeControllerUID);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
DataExchangeProcessor::~DataExchangeProcessor () = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::initialize (FUnknown* context)
|
||||
{
|
||||
tresult result = AudioEffect::initialize (context);
|
||||
if (result != kResultOk)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
addAudioInput (STR16 ("Stereo In"), Steinberg::Vst::SpeakerArr::kStereo);
|
||||
addAudioOutput (STR16 ("Stereo Out"), Steinberg::Vst::SpeakerArr::kStereo);
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::connect (Vst::IConnectionPoint* other)
|
||||
{
|
||||
auto result = Vst::AudioEffect::connect (other);
|
||||
if (result == kResultTrue)
|
||||
{
|
||||
auto configCallback = [this] (Vst::DataExchangeHandler::Config& config,
|
||||
const Vst::ProcessSetup& setup) {
|
||||
Vst::SpeakerArrangement arr;
|
||||
getBusArrangement (Vst::BusDirections::kInput, 0, arr);
|
||||
numChannels = static_cast<uint16_t> (Vst::SpeakerArr::getChannelCount (arr));
|
||||
auto sampleSize = sizeof (float);
|
||||
|
||||
config.blockSize = setup.sampleRate * numChannels * sampleSize + sizeof (DataBlock);
|
||||
config.numBlocks = 2;
|
||||
config.alignment = 32;
|
||||
config.userContextID = 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
dataExchange = std::make_unique<Vst::DataExchangeHandler> (this, configCallback);
|
||||
dataExchange->onConnect (other, getHostContext ());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::disconnect (Vst::IConnectionPoint* other)
|
||||
{
|
||||
if (dataExchange)
|
||||
{
|
||||
dataExchange->onDisconnect (other);
|
||||
dataExchange.reset ();
|
||||
}
|
||||
return AudioEffect::disconnect (other);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::setActive (TBool state)
|
||||
{
|
||||
if (state)
|
||||
dataExchange->onActivate (processSetup);
|
||||
else
|
||||
{
|
||||
dataExchange->onDeactivate ();
|
||||
currentExchangeBlock = kInvalidDataExchangeBlock;
|
||||
}
|
||||
|
||||
return AudioEffect::setActive (state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::canProcessSampleSize (int32 symbolicSampleSize)
|
||||
{
|
||||
if (symbolicSampleSize == Vst::kSample32)
|
||||
return kResultTrue;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void DataExchangeProcessor::acquireNewExchangeBlock ()
|
||||
{
|
||||
currentExchangeBlock = dataExchange->getCurrentOrNewBlock ();
|
||||
if (auto block = toDataBlock (currentExchangeBlock))
|
||||
{
|
||||
block->sampleRate = static_cast<uint32_t> (processSetup.sampleRate);
|
||||
block->numChannels = numChannels;
|
||||
block->sampleSize = sizeof (float);
|
||||
block->numSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
tresult PLUGIN_API DataExchangeProcessor::process (Vst::ProcessData& processData)
|
||||
{
|
||||
if (processData.numSamples <= 0)
|
||||
return kResultTrue;
|
||||
|
||||
if (currentExchangeBlock.blockID == Vst::InvalidDataExchangeBlockID)
|
||||
acquireNewExchangeBlock ();
|
||||
|
||||
auto input = processData.inputs[0];
|
||||
auto output = processData.outputs[0];
|
||||
|
||||
if (auto block = toDataBlock (currentExchangeBlock))
|
||||
{
|
||||
auto numSamples = static_cast<uint32> (processData.numSamples);
|
||||
while (numSamples > 0)
|
||||
{
|
||||
uint32 numSamplesFreeInBlock = block->sampleRate - block->numSamples;
|
||||
uint32 numSamplesToCopy = std::min<uint32> (numSamplesFreeInBlock, numSamples);
|
||||
for (auto channel = 0; channel < input.numChannels; ++channel)
|
||||
{
|
||||
const auto channelOffset = channel * block->sampleRate;
|
||||
auto blockChannelData = &block->samples[0] + block->numSamples + channelOffset;
|
||||
auto inputChannel =
|
||||
input.channelBuffers32[channel] + (processData.numSamples - numSamples);
|
||||
memcpy (blockChannelData, inputChannel, numSamplesToCopy * sizeof (float));
|
||||
}
|
||||
block->numSamples += numSamplesToCopy;
|
||||
if (block->numSamples == block->sampleRate)
|
||||
{
|
||||
dataExchange->sendCurrentBlock ();
|
||||
acquireNewExchangeBlock ();
|
||||
block = toDataBlock (currentExchangeBlock);
|
||||
if (block == nullptr)
|
||||
break;
|
||||
}
|
||||
numSamples -= numSamplesToCopy;
|
||||
}
|
||||
}
|
||||
for (auto channel = 0; channel < input.numChannels; ++channel)
|
||||
{
|
||||
if (output.channelBuffers32[channel] != input.channelBuffers32[channel])
|
||||
{
|
||||
memcpy (output.channelBuffers32[channel], input.channelBuffers32[channel],
|
||||
processData.numSamples * sizeof (float));
|
||||
}
|
||||
output.silenceFlags = input.silenceFlags;
|
||||
}
|
||||
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright(c) 2023 Steinberg Media Technologies.
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dataexchange.h"
|
||||
#include "public.sdk/source/vst/vstaudioeffect.h"
|
||||
|
||||
namespace Steinberg::Tutorial {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr Vst::DataExchangeBlock InvalidDataExchangeBlock = {
|
||||
nullptr, 0, Vst::InvalidDataExchangeBlockID};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DataExchangeProcessor
|
||||
//------------------------------------------------------------------------
|
||||
class DataExchangeProcessor : public Vst::AudioEffect
|
||||
{
|
||||
public:
|
||||
DataExchangeProcessor ();
|
||||
~DataExchangeProcessor () override;
|
||||
|
||||
static FUnknown* createInstance (void* /*context*/)
|
||||
{
|
||||
return (Vst::IAudioProcessor*)new DataExchangeProcessor;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API initialize (FUnknown* context) override;
|
||||
tresult PLUGIN_API connect (Vst::IConnectionPoint* other) override;
|
||||
tresult PLUGIN_API disconnect (Vst::IConnectionPoint* other) override;
|
||||
tresult PLUGIN_API setActive (TBool state) override;
|
||||
tresult PLUGIN_API canProcessSampleSize (int32 symbolicSampleSize) override;
|
||||
tresult PLUGIN_API process (Vst::ProcessData& data) override;
|
||||
//------------------------------------------------------------------------
|
||||
protected:
|
||||
void acquireNewExchangeBlock ();
|
||||
|
||||
std::unique_ptr<Vst::DataExchangeHandler> dataExchange;
|
||||
Vst::DataExchangeBlock currentExchangeBlock {InvalidDataExchangeBlock};
|
||||
uint16_t numChannels {0};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // namespace Steinberg::Tutorial
|
||||
@@ -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 "dataexchange-tutorial.vst3"
|
||||
#if SMTG_PLATFORM_64
|
||||
#define stringFileDescription "dataexchange-tutorial VST3 (64Bit)"
|
||||
#else
|
||||
#define stringFileDescription "dataexchange-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