21#include <condition_variable> 
   43         pOutputs ? pOutputs->
Clone() : 
nullptr } });
 
   45         pOutputs ? pOutputs->
Clone() : 
nullptr } });
 
   57      std::unique_ptr<EffectInstance::Message> pMessage) {
 
   63      std::unique_ptr<EffectInstance::Message> pMessage) {
 
   65         counter, std::move(pMessage) });
 
  112         if (pOutputs && slot.mResponse.pOutputs)
 
  113            pOutputs->
Assign(std::move(*slot.mResponse.pOutputs));
 
  114         counter = slot.mResponse.counter;
 
  140         mMessage.SettingsAndCounter::swap(message);
 
  160         if(slot.mMessage.counter == 
settings.counter)
 
  162         settings.counter = slot.mMessage.counter;
 
  166            slot.mMessage.settings, 
settings.settings);
 
  167         settings.settings.extra = slot.mMessage.settings.extra;
 
  170            state.
mMovedMessage->Assign(std::move(*slot.mMessage.pMessage));
 
  186   std::condition_variable 
mCV;
 
  195      : 
mwState{ state.weak_from_this() }
 
  202      if (
auto pState = 
mwState.lock()) {
 
  203         if (
auto pAccessState = pState->GetAccessState()) {
 
  204            if (pAccessState->mState.mInitialized)
 
  207               assert(pAccessState->mState.mInitialized);
 
  208               auto& lastSettings = pAccessState->mLastSettings;
 
  210               pAccessState->MainRead();
 
  216            return pAccessState->mLastSettings.settings;
 
  225      if (
auto pState = 
mwState.lock()) {
 
  226         if (
auto pAccessState = pState->GetAccessState()) {
 
  227            if (pMessage && !pAccessState->mState.mInitialized) {
 
  230               if (
auto pInstance = pState->mwInstance.lock()) {
 
  231                  auto &stateSettings = pState->mMainSettings.settings;
 
  232                  stateSettings = std::move(
settings);
 
  234                     stateSettings, pMessage.get()
 
  236                  pInstance->RealtimeProcessStart(package);
 
  237                  pInstance->RealtimeProcessEnd(stateSettings);
 
  238                  pAccessState->mLastSettings.
settings = stateSettings;
 
  242            auto &lastSettings = pAccessState->mLastSettings;
 
  244            lastSettings.settings = std::move(
settings);
 
  245            ++lastSettings.counter;
 
  247            pAccessState->MainWrite(
 
  252   void Set(std::unique_ptr<Message> pMessage)
 
  254      if (
auto pState = 
mwState.lock()) {
 
  255         if (
auto pAccessState = pState->GetAccessState()) {
 
  256            if (pMessage && !pAccessState->mState.mInitialized) {
 
  259               if (
auto pInstance = pState->mwInstance.lock()) {
 
  260                  auto &stateSettings = pState->mMainSettings.settings;
 
  262                     stateSettings, pMessage.get()
 
  264                  pInstance->RealtimeProcessStart(package);
 
  265                  pInstance->RealtimeProcessEnd(stateSettings);
 
  270            auto &lastSettings = pAccessState->mLastSettings;
 
  272            ++lastSettings.counter;
 
  273            pAccessState->MainWrite(
 
  274               lastSettings.counter, std::move(pMessage));
 
  279      if (
auto pState = 
mwState.lock()) {
 
  280         if (
auto pAccessState = pState->GetAccessState()) {
 
  281            assert(pAccessState->mMainThreadId == std::this_thread::get_id());
 
  283            if (pAccessState->mState.mInitialized)
 
  285               std::unique_lock lk(pAccessState->mLockForCV);
 
  286               pAccessState->mCV.wait(lk,
 
  288                        auto& lastSettings = pAccessState->mLastSettings;
 
  289                        pAccessState->MainRead();
 
  290                        return pAccessState->mCounter == lastSettings.counter;
 
  299            pState->mMainSettings.Set(pAccessState->mLastSettings);
 
  304      if (
auto pOther = 
dynamic_cast<const Access*
>(&other)) {
 
  306         auto &theirs = pOther->mwState;
 
  307         auto less = std::owner_less{};
 
  308         return !(less(mine, theirs) || less(theirs, mine));
 
  329   bool empty = 
id.empty();
 
  330   if (
mID.empty() && !empty) {
 
  378std::shared_ptr<EffectInstance>
 
  398      pInstance->SetBlockSize(512);
 
  417std::shared_ptr<EffectInstance>
 
  441   unsigned chans, 
const unsigned numAudioIn, 
const unsigned numAudioOut,
 
  445   for (
unsigned ondx = 0; ondx < chans; ondx += numAudioOut) {
 
  457std::shared_ptr<EffectInstance>
 
  467   const auto numAudioIn = pInstance->GetAudioInCount();
 
  468   const auto numAudioOut = pInstance->GetAudioOutCount();
 
  470   [&](
unsigned, 
unsigned){
 
  472      if (pInstance->RealtimeAddProcessor(
 
  497      pAccessState->WorkerRead();
 
  501   bool active = 
IsActive() && running;
 
  504         bool success = active
 
  505            ? pInstance->RealtimeResume()
 
  506            : pInstance->RealtimeSuspend();
 
  522      result = pInstance->RealtimeProcessStart(package);
 
  525   if (!pInstance || !active)
 
  531#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T))) 
  537   const float *
const *inbuf, 
float *
const *outbuf, 
float *
const dummybuf,
 
  542   const auto& pair = 
mGroups[group];
 
  543   const float** 
const clientIn =
 
  544      pInstance ? 
stackAllocate(
const float*, pInstance->GetAudioInCount()) :
 
  547   const auto PointAtCorrectInputBuffers =
 
  548      [&](
unsigned numAudioIn, 
unsigned indx) {
 
  550         unsigned copied = 
std::min(chans - indx, numAudioIn);
 
  551         std::copy(inbuf + indx, inbuf + indx + copied, clientIn);
 
  554         while (
auto need = numAudioIn - copied)
 
  556            auto moreCopied = 
std::min(chans, need);
 
  557            std::copy(inbuf, inbuf + moreCopied, clientIn + copied);
 
  558            copied += moreCopied;
 
  565      for (
size_t ii = 0; ii < chans; ++ii)
 
  566         memcpy(outbuf[ii], inbuf[ii], numSamples * 
sizeof(
float));
 
  569         auto processor = pair.first;
 
  570         const auto numAudioIn = pInstance->GetAudioInCount();
 
  571         const auto numAudioOut = pInstance->GetAudioOutCount();
 
  573            chans, numAudioIn, numAudioOut, [&](
unsigned indx, 
unsigned ondx) {
 
  575               PointAtCorrectInputBuffers(numAudioIn, indx);
 
  578               const auto blockSize = pInstance->GetBlockSize();
 
  579               for (
size_t block = 0; block < numSamples; block += blockSize)
 
  581                  auto cnt = 
std::min(numSamples - block, blockSize);
 
  582                  pInstance->RealtimePassThrough(
 
  584                  for (
size_t i = 0; i < numAudioIn; i++)
 
  594   const auto numAudioIn = pInstance->GetAudioInCount();
 
  595   const auto numAudioOut = pInstance->GetAudioOutCount();
 
  598   auto processor = pair.first;
 
  601      chans, numAudioIn, numAudioOut, [&](
unsigned indx, 
unsigned ondx) {
 
  603         PointAtCorrectInputBuffers(numAudioIn, indx);
 
  606         unsigned copied = 
std::min(chans - ondx, numAudioOut);
 
  607         std::copy(outbuf + ondx, outbuf + ondx + copied, clientOut);
 
  608         if (copied < numAudioOut)
 
  610            std::fill(clientOut + copied, clientOut + numAudioOut, dummybuf);
 
  613         const auto blockSize = pInstance->GetBlockSize();
 
  614         for (
size_t block = 0; block < numSamples; block += blockSize)
 
  616            auto cnt = 
std::min(numSamples - block, blockSize);
 
  618            auto processed = pInstance->RealtimeProcess(
 
  625            for (
size_t i = 0; i < numAudioIn; i++)
 
  628            for (
size_t i = 0; i < numAudioOut; i++)
 
  646   return numSamples - len;
 
  652   bool result = pInstance &&
 
  663      pAccessState->WorkerWrite();
 
  701   if (!pInstance->UsesMessages()) {
 
  706   auto result = pInstance->RealtimeFinalize(
mMainSettings.settings);
 
  714   static const std::string result{
"effect"};
 
  733      for (
auto &[attr, value] : attrs) {
 
  735            SetID(value.ToWString());
 
  754      for (
auto &[attr, value] : attrs) {
 
  756            n = value.ToWString();
 
  758            v = value.ToWString();
 
  791   const auto active = 
mMainSettings.settings.extra.GetActive();
 
  804      entryKeepGoing = cmdParms.GetFirstEntry(entryName, entryIndex);
 
  805      while (entryKeepGoing) {
 
  806         wxString entryValue = cmdParms.Read(entryName, 
"");
 
  813         entryKeepGoing = cmdParms.GetNextEntry(entryName, entryIndex);
 
  827      return std::make_shared<Access>();
 
  837   return std::make_shared<Access>(*
this);
 
Abstract class ChannelGroup with two discrete iterable dimensions, channels and intervals; subclasses...
static const auto parametersAttribute
static const auto versionAttribute
static const auto parameterAttribute
static const auto nameAttribute
static const auto idAttribute
static const auto valueAttribute
static constexpr auto activeAttribute
#define stackAllocate(T, count)
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
static Settings & settings()
std::vector< Attribute > AttributesList
void BuildAll()
For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it.
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
virtual wxString GetVersion() const =0
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
Hold values to send to effect output meters.
virtual std::unique_ptr< EffectOutputs > Clone() const =0
virtual void Assign(EffectOutputs &&src)=0
Update one Outputs object from another.
Type of messages to send from main thread to processing.
EffectSettingsManager is an EffectDefinitionInterface that adds a factory function for EffectSettings...
virtual bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const =0
Restore settings from keys and values.
virtual bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const =0
Store settings as keys and values.
virtual bool CopySettingsContents(const EffectSettings &src, EffectSettings &dst) const
Update one settings object from another.
virtual std::unique_ptr< EffectOutputs > MakeOutputs() const
Produce an object to hold values to send to effect output meters.
virtual EffectSettings MakeSettings() const
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
Communicate data atomically from one writer thread to one reader.
CallbackReturn Publish(const RealtimeEffectStateChange &message)
Send a message to connected callbacks.
static PluginID GetID(const PluginProvider *provider)
Mediator of two-way inter-thread communication of changes of settings.
void Initialize(const EffectSettings &settings, const EffectInstance::Message *pMessage, const EffectOutputs *pOutputs)
MessageBuffer< ToMainSlot > mChannelToMain
const EffectSettingsManager & mEffect
Response::Counter mCounter
void MainWrite(SettingsAndCounter::Counter counter, std::unique_ptr< EffectInstance::Message > pMessage)
RealtimeEffectState & mState
SettingsAndCounter mLastSettings
std::condition_variable mCV
AccessState(const EffectSettingsManager &effect, RealtimeEffectState &state)
MessageBuffer< FromMainSlot > mChannelFromMain
void MainWrite(SettingsAndCounter &&settings, std::unique_ptr< EffectInstance::Message > pMessage)
std::thread::id mMainThreadId
void SetActive(bool active)
Set only in the main thread.
const EffectInstanceFactory * mPlugin
Stateless effect object.
std::shared_ptr< EffectInstance > AddGroup(const ChannelGroup *group, unsigned chans, float sampleRate)
Main thread sets up this state before adding it to lists.
NonInterfering< SettingsAndCounter > mWorkerSettings
NonInterfering< SettingsAndCounter > mMainSettings
Updated immediately by Access::Set in the main thread.
size_t Process(const ChannelGroup *group, unsigned chans, const float *const *inbuf, float *const *outbuf, float *dummybuf, size_t numSamples)
Worker thread processes part of a batch of samples.
std::optional< EffectInstance::SampleCount > mLatency
How many samples must be discarded.
void HandleXMLEndTag(const std::string_view &tag) override
std::shared_ptr< EffectInstance > GetInstance()
Expose a pointer to the state's instance (making one as needed).
std::unordered_map< const ChannelGroup *, std::pair< size_t, double > > mGroups
std::shared_ptr< EffectSettingsAccess > GetAccess()
std::unique_ptr< EffectOutputs > mOutputs
bool ProcessEnd()
Worker thread finishes a batch of samples.
AccessState * GetAccessState() const
AccessState * TestAccessState() const
static const std::string & XMLTag()
bool Finalize() noexcept
Main thread cleans up playback.
std::shared_ptr< EffectInstance > EnsureInstance(double rate)
bool ProcessStart(bool running)
Worker thread begins a batch of samples.
bool IsEnabled() const noexcept
Test only in the main thread.
const PluginID & GetID() const noexcept
bool mLastActive
Assigned in the worker thread at the start of each processing scope.
void WriteXML(XMLWriter &xmlFile)
RealtimeEffectState(const PluginID &id)
bool IsActive() const noexcept
Test only in the worker thread, or else when there is no processing.
std::shared_ptr< EffectInstance > Initialize(double rate)
Main thread sets up for playback.
std::shared_ptr< EffectInstance > MakeInstance()
std::unique_ptr< EffectInstance::Message > mMessage
const EffectInstanceFactory * GetEffect()
Initializes the effect on demand.
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
void SetID(const PluginID &id)
May be called with nonempty id at most once in the lifetime of a state.
std::unique_ptr< EffectInstance::Message > mMovedMessage
std::weak_ptr< EffectInstance > mwInstance
Stateful instance made by the plug-in.
AtomicUniquePointer< AccessState > mpAccessState
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
std::unique_ptr< EffectOutputs > mMovedOutputs
This class is an interface which should be implemented by classes which wish to be able to load and s...
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
virtual void StartTag(const wxString &name)
void WriteAttr(const wxString &name, const Identifier &value)
virtual void EndTag(const wxString &name)
constexpr auto sampleRate
void AllocateChannelsToProcessors(unsigned chans, const unsigned numAudioIn, const unsigned numAudioOut, const F &f)
void copy(const T *src, T *dst, int32_t n)
EffectSettings & settings
Externalized state of a plug-in.
Main thread's interface to inter-thread communication of changes of settings.
const EffectSettings & Get() override
void Set(std::unique_ptr< Message > pMessage) override
Message-only overload of Set(). In future, this should be the only one.
Access(RealtimeEffectState &state)
bool IsSameAs(const EffectSettingsAccess &other) const override
void Flush() override
Make the last Set changes "persistent" in underlying storage.
void Set(EffectSettings &&settings, std::unique_ptr< Message > pMessage) override
~Access() override=default
std::weak_ptr< RealtimeEffectState > mwState
Store no state here but this weak pointer, so IsSameAs isn't lying.
Response::Counter counter
std::unique_ptr< EffectInstance::Message > pMessage
Reader(FromMainSlot &&slot, const EffectSettingsManager &effect, RealtimeEffectState &state)
std::unique_ptr< EffectInstance::Message > pMessage
SettingsAndCounter::Counter counter
FromMainSlot & operator=(FromMainSlot &&)=default
FromMainSlot(const EffectSettings &settings, const EffectInstance::Message *pMessage)
FromMainSlot & operator=(Message &&message)
FromMainSlot & operator=(ShortMessage &&message)
Reader(ToMainSlot &&slot, EffectOutputs *pOutputs, Response::Counter &counter)
ToMainSlot(Response response)
ToMainSlot & operator=(ToMainSlot &&)=default
ToMainSlot & operator=(CounterAndOutputs &&arg)
std::unique_ptr< EffectOutputs > pOutputs