Initial VST3 Support (disabled)

Disabled until Steinberg licensing compliance  can be sorted out.
This commit is contained in:
Robin Davies
2022-08-15 18:14:49 -04:00
parent 351d1542e1
commit 553ae2a3f7
56 changed files with 4840 additions and 637 deletions
+83
View File
@@ -0,0 +1,83 @@
/*
* MIT License
*
* Copyright (c) 2022 Robin E. R. Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "PiPedalHost.hpp"
#include <functional>
#include "json.hpp"
namespace pipedal {
struct Vst3PluginInfo {
public:
std::string filePath_;
std::string version_;
std::string uid_;
Lv2PluginUiInfo pluginInfo_;
DECLARE_JSON_MAP(Vst3PluginInfo);
};
struct Vst3ProgramListEntry {
int32_t id;
std::string name;
};
struct Vst3ProgramList {
std::string name;
std::vector<Vst3ProgramListEntry> programs;
};
class Vst3Effect: public IEffect {
public:
using Ptr = std::unique_ptr<Vst3Effect>;
virtual void Prepare(int32_t sampleRate, size_t maxBufferSize,int inputChannels, int outputChannels) = 0;
virtual void Activate() = 0;
virtual void Deactivate() = 0;
virtual void Unprepare() = 0;
virtual void CheckSync() = 0; // throw if audioProcessor and controller are not sync (test only)
virtual bool SupportsState() const = 0;
virtual bool GetState(std::vector<uint8_t> *state) = 0;
virtual void SetState(const std::vector<uint8_t> state) = 0;
using ControlChangedHandler = std::function<void(int control,float value)>;
virtual void SetControlChangedHandler(const ControlChangedHandler& handler) = 0;
virtual void RemoveControlChangedHandler() = 0;
virtual std::vector<Vst3ProgramList> GetProgramList(int32_t programListId) = 0;
public:
static std::unique_ptr<Vst3Effect> CreateInstance(uint64_t instanceId,const Vst3PluginInfo& info, IHost *pHost);
};
}
+286
View File
@@ -0,0 +1,286 @@
/*
* MIT License
*
* Copyright (c) 2022 Robin E. R. Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "Vst3Effect.hpp"
#include <vector>
#include "RtInversionGuard.hpp"
#include "Vst3RtStream.hpp"
#pragma once
namespace pipedal
{
using namespace std;
using namespace pipedal;
using namespace VST3::Hosting;
using namespace Steinberg;
using namespace Steinberg::Vst;
enum
{
kMaxMidiMappingBusses = 4,
kMaxMidiChannels = 16
};
using Controllers = std::vector<int32>;
using Channels = std::array<Controllers, kMaxMidiChannels>;
using Busses = std::array<Channels, kMaxMidiMappingBusses>;
using MidiCCMapping = Busses;
class Vst3EffectImpl : public Vst3Effect,
public IAudioClient,
public IMidiClient
{
public:
//--------------------------------------------------------------------
using Name = std::string;
Vst3EffectImpl();
virtual ~Vst3EffectImpl();
void Load(uint64_t instanceId, const Vst3PluginInfo &info, IHost *pHost);
// IEffect
virtual bool IsVst3() const { return true; }
virtual uint64_t GetInstanceId() const { return instanceId; }
virtual int GetControlIndex(const std::string &symbol) const
{
for (size_t i = 0; i < info.pluginInfo_.controls().size(); ++i)
{
if (info.pluginInfo_.controls()[i].symbol() == symbol)
{
return (int)i;
}
}
return -1;
}
bool SupportsState() const { return supportsState; }
bool GetState(std::vector<uint8_t> *state);
void SetState(const std::vector<uint8_t> state);
virtual void CheckSync();
//- PiPedalHost Interfaces.
virtual void SetControl(int index, float value);
virtual float GetControlValue(int index) const
{
return this->parameterValues[index];
}
virtual std::vector<Vst3ProgramList> GetProgramList(int32_t programListId);
int bypassControl = -1;
bool bypassEnable = false;
virtual void SetBypass(bool enable)
{
if (bypassControl != -1)
{
SetControl(bypassControl, enable ? 1 : 0);
}
else
{
bypassEnable = enable;
}
}
virtual void Activate();
virtual void Deactivate();
virtual float GetOutputControlValue(int controlIndex) const
{
return this->parameterValues[controlIndex];
}
virtual int GetNumberOfInputAudioPorts() const
{
return info.pluginInfo_.audio_inputs();
}
virtual int GetNumberOfOutputAudioPorts() const
{
return info.pluginInfo_.audio_outputs();
}
virtual float *GetAudioInputBuffer(int index) const { return buffers.inputs[index]; }
virtual float *GetAudioOutputBuffer(int index) const { return buffers.outputs[index]; }
virtual void ResetAtomBuffers() {}
virtual void RequestParameter(LV2_URID uridUri) {} // no vst equivalent.
virtual void GatherParameter(RealtimeParameterRequest *pRequest) {} // no vst equivalent.
virtual void SetAudioInputBuffer(int index, float *buffer)
{
buffers.inputs[index] = buffer;
}
virtual void SetAudioOutputBuffer(int index, float *buffer)
{
buffers.outputs[index] = buffer;
}
virtual void Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBufferWriter)
{
process(buffers, samples);
SendControlChanges(realtimeRingBufferWriter);
}
// Vst3Effect interfaces.
virtual void Prepare(int32_t sampleRate, size_t maxBufferSize, int inputChannels, int outputChannels);
virtual void Unprepare();
// IAudioClient
bool process(Buffers &buffers, int64_t continousFrames) override;
bool setSamplerate(SampleRate value) override;
bool setBlockSize(int32 value) override;
IAudioClient::IOSetup getIOSetup() const override;
// IMidiClient
bool onEvent(const Event &event, int32_t port) override;
IMidiClient::IOSetup getMidiIOSetup() const override;
// IParameterClient
//--------------------------------------------------------------------
private:
bool supportsState = false;
IHost *pHost;
Module::Ptr module;
IPtr<IMidiMapping> midiMapping;
IPtr<PlugProvider> plugProvider;
RtStreamPool streamPool;
void SendControlChanges(RealtimeRingBufferWriter *realtimeRingBufferWriter);
//--------------------------------------------------------------------
private:
std::mutex parameterMutex;
Buffers buffers;
std::vector<ParamID> lv2ToVstParam;
std::vector<float> parameterValues;
// void createLocalMediaServer(const Name &name);
uint64_t instanceId;
Vst3PluginInfo info;
void terminate();
void initProcessData();
void updateBusBuffers(Buffers &buffers, HostProcessData &processData);
void preprocess(Buffers &buffers, int64_t continousFrames);
void postprocess(Buffers &buffers);
bool isPortInRange(int32 port, int32 channel) const;
bool processVstEvent(const IMidiClient::Event &event, int32 port);
bool processParamChange(const IMidiClient::Event &event, int32 port);
SampleRate sampleRate = 0;
int32 blockSize = 0;
HostProcessData processData;
ProcessContext processContext;
EventList eventList;
ParameterChanges inputParameterChanges;
ParameterChanges outputParameterChanges;
IComponent *component = nullptr;
IEditController *controller = nullptr;
FUnknownPtr<IAudioProcessor> processor;
ParameterChangeTransfer paramTransferrer;
MidiCCMapping midiCCMapping;
// IMediaServerPtr mediaServer;
bool isProcessing = false;
Name name;
private:
ssize_t ParamIdToLv2Id(ParamID id) const;
class ComponentHandler : public IComponentHandler
{
private:
Vst3EffectImpl *pEffect = nullptr;
public:
ComponentHandler() { }
void setEffect(Vst3EffectImpl*effect)
{
pEffect = effect;
}
tresult PLUGIN_API beginEdit(ParamID id) override
{
return pEffect->beginEdit(id);
}
tresult PLUGIN_API performEdit(ParamID id, ParamValue valueNormalized) override
{
return pEffect->performEdit(id, valueNormalized);
}
tresult PLUGIN_API endEdit(ParamID id) override
{
return pEffect->endEdit(id);
}
tresult PLUGIN_API restartComponent(int32 flags) override
{
return pEffect->restartComponent(flags);
}
private:
tresult PLUGIN_API queryInterface(const TUID _iid, void ** obj) override
{
if (_iid == IComponentHandler_iid)
{
addRef();
*((FUnknown**)obj) = this;
return kResultOk;
}
return kNoInterface;
}
uint32 PLUGIN_API addRef() override { return 1000; }
uint32 PLUGIN_API release() override { return 1000; }
};
ComponentHandler componentHandler;
void transferControllerStateToComponent();
void refreshControlValues();
virtual tresult beginEdit(ParamID id);
virtual tresult performEdit(ParamID id, ParamValue valueNormalized);
virtual tresult endEdit(ParamID id);
virtual tresult restartComponent(int32 flags);
private:
ControlChangedHandler controlChangedHandler = [] (int control,float value) {};
void fireControlChanged(int control, float normalizedValue);
public:
virtual void SetControlChangedHandler(const ControlChangedHandler& handler)
{
controlChangedHandler = handler;
}
virtual void RemoveControlChangedHandler() {
controlChangedHandler = [] (int,float){};
}
};
}
+70
View File
@@ -0,0 +1,70 @@
/*
/* MIT License
*
* Copyright (c) 2022 Robin E. R. Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <vector>
#include <stdint.h>
#include <string>
#include <exception>
#include <stdexcept>
#include "public.sdk/source/vst/utility/uid.h"
#include "vst3/Vst3Effect.hpp"
#include "PedalBoard.hpp"
namespace pipedal {
class Vst3Exception: public std::logic_error {
public:
Vst3Exception(const std::string&error)
:logic_error(error)
{
}
};
class Vst3Host {
public:
using Ptr = std::unique_ptr<Vst3Host>;
using PluginList = std::vector<std::unique_ptr<Vst3PluginInfo>>;
virtual ~Vst3Host() {}
virtual const PluginList &RescanPlugins() = 0;
virtual const PluginList &RefreshPlugins() = 0;
virtual const PluginList &getPluginList() = 0;
virtual std::unique_ptr<Vst3Effect> CreatePlugin(long instanceId,const std::string&url, IHost*pHost) = 0;
virtual std::unique_ptr<Vst3Effect> CreatePlugin(PedalBoardItem&pedalBoardItem, IHost*pHost) = 0;
static Ptr CreateInstance(const std::string &cacheFilePath = "");
};
};
+53
View File
@@ -0,0 +1,53 @@
/*
* MIT License
*
* Copyright (c) 2022 Robin E. R. Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <cstddef>
#include <string>
#include <vector>
#include <memory>
namespace pipedal {
struct Vst3PresetInfo {
uint32_t index;
std::string name;
};
class Vst3PresetFile {
protected:
Vst3PresetFile() { }
public:
virtual ~Vst3PresetFile() { }
virtual void Load(const std::string&path) = 0;
virtual std::vector<Vst3PresetInfo> GetPresets() = 0;
virtual std::vector<uint8_t> GetPresetChunk(uint32_t index) = 0;
std::unique_ptr<Vst3PresetFile> CreateInstance();
};
}
+109
View File
@@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) 2022 Robin E. R. Davies
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "public.sdk/source/common/memorystream.h"
#include <mutex>
#include "Vst3RtStream.hpp"
namespace pipedal
{
using namespace Steinberg;
class IRtStream : public IBStream
{
public:
virtual void QueueForRelease() = 0;
};
class RtStreamPool;
class RtStream : public IRtStream
{
friend class RtStreamPool;
virtual void PLUGIN_API QueueForRelease();
RtStream(RtStreamPool *pool);
public:
virtual ~RtStream();
//---IBStream---------------------------------------
tresult PLUGIN_API read(void *buffer, int32 numBytes, int32 *numBytesRead) SMTG_OVERRIDE;
tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten) SMTG_OVERRIDE;
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result) SMTG_OVERRIDE;
tresult PLUGIN_API tell(int64 *pos) SMTG_OVERRIDE;
TSize getSize() const; ///< returns the current memory size
void setSize(TSize size); ///< set the memory size, a realloc will occur if memory already used
char *getData() const; ///< returns the memory pointer
char *detachData(); ///< returns the memory pointer and give up ownership
bool truncate(); ///< realloc to the current use memory size if needed
bool truncateToCursor(); ///< truncate memory at current cursor position
//------------------------------------------------------------------------
DECLARE_FUNKNOWN_METHODS
protected:
RtStreamPool *pool = nullptr;
RtStream *next = nullptr;
char *memory; // memory block
TSize memorySize; // size of the memory block
TSize size; // size of the stream
int64 cursor; // stream pointer
bool ownMemory; // stream has allocated memory itself
bool allocationError; // stream invalid
};
class RtStreamPool
{
public:
~RtStreamPool()
{
ReleaseStreams();
}
IRtStream *AllocateBStream()
{
ReleaseStreams();
return new RtStream(this);
}
void ReleaseStreams();
private:
friend class RtStream;
RtStream *freeStreamList = nullptr;
void QueueForRelease(RtStream *pStream)
{
pStream->next = freeStreamList;
freeStreamList = pStream;
}
};
inline void RtStream::QueueForRelease()
{
pool->QueueForRelease(this);
}
};