Add a fast path to effect busses Get the number of outputs in the Synth Duplicate effect buses and process outputs separately Update the API wrappers to handle multichannel processing Accomodate multiple outputs in the VST plugin Publish a 8 stereo version of the LV2 plugin Publish a 8 stereo version of the VST3 plugin WIP Remove the duplication of effects Cleanups Debugs Tweaks Windows free error Port numbers change between plugin versions Fix warning Proper meter backgrounds
146 lines
4.7 KiB
C++
146 lines
4.7 KiB
C++
// SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
|
// license. You should have receive a LICENSE.md file along with the code.
|
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
|
|
|
#pragma once
|
|
#include "SfizzVstState.h"
|
|
#include "SfizzVstUpdates.h"
|
|
#include "OrderedEventProcessor.h"
|
|
#include "plugin/RMSFollower.h"
|
|
#include "sfizz/RTSemaphore.h"
|
|
#include "ring_buffer/ring_buffer.h"
|
|
#include "public.sdk/source/vst/vstaudioeffect.h"
|
|
#include <sfizz.hpp>
|
|
#include <SpinMutex.h>
|
|
#include <array>
|
|
#include <thread>
|
|
#include <memory>
|
|
#include <cstdlib>
|
|
|
|
using namespace Steinberg;
|
|
|
|
class SfizzVstProcessor : public Vst::AudioEffect,
|
|
public OrderedEventProcessor<SfizzVstProcessor> {
|
|
public:
|
|
SfizzVstProcessor();
|
|
~SfizzVstProcessor();
|
|
|
|
tresult PLUGIN_API initialize(FUnknown* context) override;
|
|
tresult PLUGIN_API terminate() override;
|
|
tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) override;
|
|
|
|
tresult PLUGIN_API connect(IConnectionPoint* other) override;
|
|
|
|
tresult PLUGIN_API setState(IBStream* stream) override;
|
|
tresult PLUGIN_API getState(IBStream* stream) override;
|
|
void syncStateToSynth();
|
|
|
|
tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override;
|
|
tresult PLUGIN_API setActive(TBool state) override;
|
|
tresult PLUGIN_API process(Vst::ProcessData& data) override;
|
|
|
|
// OrderedEventProcessor
|
|
void playOrderedParameter(int32 sampleOffset, Vst::ParamID id, Vst::ParamValue value);
|
|
void playOrderedEvent(const Vst::Event& event);
|
|
|
|
void processMessagesFromUi();
|
|
|
|
tresult PLUGIN_API notify(Vst::IMessage* message) override;
|
|
void PLUGIN_API update(FUnknown* changedUnknown, int32 message) override;
|
|
|
|
static FUnknown* createInstance(void*);
|
|
|
|
static FUID cid;
|
|
|
|
// --- Sfizz stuff here below ---
|
|
protected:
|
|
RMSFollower _rmsFollower {};
|
|
bool _multi { false };
|
|
private:
|
|
// synth state. acquire processMutex before accessing
|
|
std::unique_ptr<sfz::Sfizz> _synth;
|
|
bool _isActive = false;
|
|
SfizzVstState _state;
|
|
float _currentStretchedTuning = 0;
|
|
|
|
// whether allowed to perform events (owns the processing lock)
|
|
bool _canPerformEventsAndParameters {};
|
|
|
|
// level meters
|
|
bool _editorIsOpen = false;
|
|
|
|
// updates
|
|
IPtr<QueuedUpdates> _queuedMessages;
|
|
IPtr<PlayStateUpdate> _playStateUpdate;
|
|
IPtr<SfzUpdate> _sfzUpdate;
|
|
IPtr<SfzDescriptionUpdate> _sfzDescriptionUpdate;
|
|
IPtr<ScalaUpdate> _scalaUpdate;
|
|
IPtr<AutomationUpdate> _automationUpdate;
|
|
bool processUpdate(FUnknown* changedUnknown, int32 message);
|
|
|
|
// client
|
|
sfz::ClientPtr _client;
|
|
std::unique_ptr<uint8_t[]> _oscTemp;
|
|
void receiveOSC(int delay, const char* path, const char* sig, const sfizz_arg_t* args);
|
|
|
|
// misc
|
|
void loadSfzFileOrDefault(const std::string& filePath, bool initParametersFromState);
|
|
|
|
// note event tracking
|
|
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
|
|
|
// worker and thread sync
|
|
std::thread _worker;
|
|
volatile bool _workRunning = false;
|
|
Ring_Buffer _fifoToWorker;
|
|
RTSemaphore _semaToWorker;
|
|
Ring_Buffer _fifoMessageFromUi;
|
|
SpinMutex _processMutex;
|
|
|
|
// time info
|
|
int _timeSigNumerator = 0;
|
|
int _timeSigDenominator = 0;
|
|
void updateTimeInfo(const Vst::ProcessContext& context);
|
|
|
|
// messaging
|
|
struct RTMessage {
|
|
const char* type;
|
|
uintptr_t size;
|
|
// 32-bit aligned data after header
|
|
template <class T> const T* payload() const;
|
|
};
|
|
struct RTMessageDelete {
|
|
void operator()(RTMessage* x) const noexcept { std::free(x); }
|
|
};
|
|
typedef std::unique_ptr<RTMessage, RTMessageDelete> RTMessagePtr;
|
|
|
|
// worker
|
|
void doBackgroundWork();
|
|
void doBackgroundIdle(size_t idleCounter);
|
|
void startBackgroundWork();
|
|
void stopBackgroundWork();
|
|
// writer
|
|
bool writeWorkerMessage(const char* type, const void* data, uintptr_t size);
|
|
// reader
|
|
RTMessagePtr readWorkerMessage();
|
|
bool discardWorkerMessage();
|
|
|
|
// generic
|
|
static bool writeMessage(Ring_Buffer& fifo, const char* type, const void* data, uintptr_t size);
|
|
};
|
|
|
|
class SfizzVstProcessorMulti : public SfizzVstProcessor {
|
|
public:
|
|
tresult PLUGIN_API initialize(FUnknown* context) override;
|
|
static FUnknown* createInstance(void*);
|
|
static FUID cid;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <class T> const T* SfizzVstProcessor::RTMessage::payload() const
|
|
{
|
|
return reinterpret_cast<const T*>(
|
|
reinterpret_cast<const uint8*>(this) + sizeof(*this));
|
|
}
|