// 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 #include #include #include #include #include using namespace Steinberg; class SfizzVstProcessor : public Vst::AudioEffect, public OrderedEventProcessor { 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 _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 _queuedMessages; IPtr _playStateUpdate; IPtr _sfzUpdate; IPtr _sfzDescriptionUpdate; IPtr _scalaUpdate; IPtr _automationUpdate; bool processUpdate(FUnknown* changedUnknown, int32 message); // client sfz::ClientPtr _client; std::unique_ptr _oscTemp; void receiveOSC(int delay, const char* path, const char* sig, const sfizz_arg_t* args); // misc void loadSfzFileOrDefault(const std::string& filePath); // note event tracking std::array _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 const T* payload() const; }; struct RTMessageDelete { void operator()(RTMessage* x) const noexcept { std::free(x); } }; typedef std::unique_ptr 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 const T* SfizzVstProcessor::RTMessage::payload() const { return reinterpret_cast( reinterpret_cast(this) + sizeof(*this)); }