Audacity 3.2.0
Classes | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
RealtimeEffectState Class Reference

#include <RealtimeEffectState.h>

Inheritance diagram for RealtimeEffectState:
[legend]
Collaboration diagram for RealtimeEffectState:
[legend]

Classes

struct  Access
 Main thread's interface to inter-thread communication of changes of settings. More...
 
class  AccessState
 Mediator of two-way inter-thread communication of changes of settings. More...
 
struct  EffectFactory
 
struct  Response
 
struct  SettingsAndCounter
 

Public Member Functions

 RealtimeEffectState (const PluginID &id)
 
 RealtimeEffectState (const RealtimeEffectState &other)=delete
 
RealtimeEffectStateoperator= (const RealtimeEffectState &other)=delete
 
 ~RealtimeEffectState ()
 
void SetID (const PluginID &id)
 May be called with nonempty id at most once in the lifetime of a state. More...
 
const PluginIDGetID () const noexcept
 
const EffectInstanceFactoryGetEffect ()
 Initializes the effect on demand. More...
 
const EffectInstanceFactoryGetEffect () const
 const accessor will not initialize the effect on demand More...
 
std::shared_ptr< EffectInstanceGetInstance ()
 Expose a pointer to the state's instance (making one as needed). More...
 
const EffectOutputsGetOutputs () const
 Get locations that a GUI can connect meters to. More...
 
std::shared_ptr< EffectInstanceInitialize (double rate)
 Main thread sets up for playback. More...
 
std::shared_ptr< EffectInstanceAddGroup (const ChannelGroup &group, unsigned chans, float sampleRate)
 Main thread sets up this state before adding it to lists. More...
 
bool ProcessStart (bool running)
 Worker thread begins a batch of samples. More...
 
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. More...
 
bool ProcessEnd ()
 Worker thread finishes a batch of samples. More...
 
const EffectSettingsGetSettings () const
 
bool IsEnabled () const noexcept
 Test only in the main thread. More...
 
bool IsActive () const noexcept
 Test only in the worker thread, or else when there is no processing. More...
 
void SetActive (bool active)
 Set only in the main thread. More...
 
bool Finalize () noexcept
 Main thread cleans up playback. More...
 
bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs) override
 
void HandleXMLEndTag (const std::string_view &tag) override
 
XMLTagHandlerHandleXMLChild (const std::string_view &tag) override
 
void WriteXML (XMLWriter &xmlFile)
 
std::shared_ptr< EffectSettingsAccessGetAccess ()
 
- Public Member Functions inherited from XMLTagHandler
 XMLTagHandler ()
 
virtual ~XMLTagHandler ()
 
virtual bool HandleXMLTag (const std::string_view &tag, const AttributesList &attrs)=0
 
virtual void HandleXMLEndTag (const std::string_view &WXUNUSED(tag))
 
virtual void HandleXMLContent (const std::string_view &WXUNUSED(content))
 
virtual XMLTagHandlerHandleXMLChild (const std::string_view &tag)=0
 
void ReadXMLEndTag (const char *tag)
 
void ReadXMLContent (const char *s, int len)
 
XMLTagHandlerReadXMLChild (const char *tag)
 
- Public Member Functions inherited from ClientData::Site< RealtimeEffectState >
 ~Site ()
 
 Site ()
 
 Site (const Site &other)
 
 Site (Site &&other)
 
Siteoperator= (const Site &other)
 
Siteoperator= (Site &&other)
 
size_t size () const
 How many attachment pointers are in the Site. More...
 
Subclass & Get (const RegisteredFactory &key)
 Get reference to an attachment, creating on demand if not present, down-cast it to Subclass. More...
 
auto Get (const RegisteredFactory &key) const -> std::enable_if_t< std::is_const< Subclass >::value, Subclass & >
 Get reference to an attachment, creating on demand if not present, down-cast it to Subclass. More...
 
Subclass * Find (const RegisteredFactory &key)
 Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand. More...
 
auto Find (const RegisteredFactory &key) const -> std::enable_if_t< std::is_const< Subclass >::value, Subclass * >
 Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand. More...
 
void Assign (const RegisteredFactory &key, ReplacementPointer &&replacement)
 Reassign Site's pointer to ClientData. More...
 
- Public Member Functions inherited from Observer::Publisher< RealtimeEffectStateChange >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 

Static Public Member Functions

static const std::string & XMLTag ()
 
- Static Public Member Functions inherited from SharedNonInterfering< RealtimeEffectState >
static std::shared_ptr< RealtimeEffectStatemake_shared (Args &&...args)
 
- Static Public Member Functions inherited from ClientData::Site< RealtimeEffectState >
static size_t numFactories ()
 How many static factories have been registered with this specialization of Site. More...
 

Private Member Functions

std::shared_ptr< EffectInstanceMakeInstance ()
 
std::shared_ptr< EffectInstanceEnsureInstance (double rate)
 
AccessStateGetAccessState () const
 
AccessStateTestAccessState () const
 

Private Attributes

PluginID mID
 
std::weak_ptr< EffectInstancemwInstance
 Stateful instance made by the plug-in. More...
 
const EffectInstanceFactorymPlugin {}
 Stateless effect object. More...
 
NonInterfering< SettingsAndCountermMainSettings
 Updated immediately by Access::Set in the main thread. More...
 
std::unique_ptr< EffectInstance::MessagemMessage
 
std::unique_ptr< EffectOutputsmMovedOutputs
 
Members that are changed also in the worker thread
NonInterfering< SettingsAndCountermWorkerSettings
 
std::unique_ptr< EffectInstance::MessagemMovedMessage
 
std::unique_ptr< EffectOutputsmOutputs
 
std::optional< EffectInstance::SampleCountmLatency
 How many samples must be discarded. More...
 
bool mLastActive {}
 Assigned in the worker thread at the start of each processing scope. More...
 
Members that do not change during processing
std::unordered_map< const ChannelGroup *, std::pair< size_t, double > > mGroups
 
AtomicUniquePointer< AccessStatempAccessState { nullptr }
 
wxString mParameters
 
size_t mCurrentProcessor { 0 }
 
bool mInitialized { false }
 

Additional Inherited Members

- Public Types inherited from ClientData::Site< RealtimeEffectState >
using DataType = Base
 
using DataPointer = UniquePtr< Base >
 
using DataFactory = std::function< DataPointer(RealtimeEffectState &) >
 Type of function from which RegisteredFactory is constructed; it builds attachments. More...
 
- Public Types inherited from Observer::Publisher< RealtimeEffectStateChange >
using message_type = RealtimeEffectStateChange
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const RealtimeEffectStateChange &) >
 Type of functions that can be connected to the Publisher. More...
 
- Static Public Attributes inherited from Observer::Publisher< RealtimeEffectStateChange >
static constexpr bool notifies_all
 
- Protected Member Functions inherited from ClientData::Site< RealtimeEffectState >
void ForEach (const Function &function)
 Invoke function on each ClientData object that has been created in this. More...
 
void ForEach (const Function &function) const
 Invoke function on each ClientData object that has been created in this. More...
 
void ForCorresponding (Site &other, const Function &function, bool create=true)
 
BaseFindIf (const Function &function)
 Return pointer to first attachment in this that is not null and satisfies a predicate, or nullptr. More...
 
const BaseFindIf (const Function &function) const
 Return pointer to first attachment in this that is not null and satisfies a predicate, or nullptr. More...
 
void EraseIf (const Function &function)
 Erase attached objects satisfying a predicate. More...
 
void BuildAll ()
 For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it. More...
 
- Protected Member Functions inherited from Observer::Publisher< RealtimeEffectStateChange >
CallbackReturn Publish (const RealtimeEffectStateChange &message)
 Send a message to connected callbacks. More...
 

Detailed Description

Definition at line 32 of file RealtimeEffectState.h.

Constructor & Destructor Documentation

◆ RealtimeEffectState() [1/2]

RealtimeEffectState::RealtimeEffectState ( const PluginID id)
explicit

Definition at line 316 of file RealtimeEffectState.cpp.

317{
318 SetID(id);
319 BuildAll();
320}
void BuildAll()
For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it.
Definition: ClientData.h:546
void SetID(const PluginID &id)
May be called with nonempty id at most once in the lifetime of a state.

References ClientData::Site< RealtimeEffectState >::BuildAll(), and SetID().

Here is the call graph for this function:

◆ RealtimeEffectState() [2/2]

RealtimeEffectState::RealtimeEffectState ( const RealtimeEffectState other)
delete

◆ ~RealtimeEffectState()

RealtimeEffectState::~RealtimeEffectState ( )

Definition at line 322 of file RealtimeEffectState.cpp.

323{
324
325}

Member Function Documentation

◆ AddGroup()

std::shared_ptr< EffectInstance > RealtimeEffectState::AddGroup ( const ChannelGroup group,
unsigned  chans,
float  sampleRate 
)

Main thread sets up this state before adding it to lists.

Set up processors to be visited repeatedly in Process.

The iteration over channels in AddGroup and Process must be the same

Definition at line 458 of file RealtimeEffectState.cpp.

460{
461 auto pInstance = EnsureInstance(sampleRate);
462 if (!pInstance)
463 return {};
464 if (!mPlugin)
465 return {};
466 auto first = mCurrentProcessor;
467 const auto numAudioIn = pInstance->GetAudioInCount();
468 const auto numAudioOut = pInstance->GetAudioOutCount();
469 AllocateChannelsToProcessors(chans, numAudioIn, numAudioOut,
470 [&](unsigned, unsigned){
471 // Add a NEW processor
472 if (pInstance->RealtimeAddProcessor(
473 mWorkerSettings.settings, mOutputs.get(), numAudioIn, sampleRate)
474 ) {
475 mCurrentProcessor++;
476 return true;
477 }
478 else
479 return false;
480 });
481 if (mCurrentProcessor > first) {
482 // Remember the sampleRate of the group, so latency can be computed
483 // later
484 mGroups[&group] = { first, sampleRate };
485 return pInstance;
486 }
487 return {};
488}
const EffectInstanceFactory * mPlugin
Stateless effect object.
NonInterfering< SettingsAndCounter > mWorkerSettings
std::unordered_map< const ChannelGroup *, std::pair< size_t, double > > mGroups
std::unique_ptr< EffectOutputs > mOutputs
std::shared_ptr< EffectInstance > EnsureInstance(double rate)
void AllocateChannelsToProcessors(unsigned chans, const unsigned numAudioIn, const unsigned numAudioOut, const F &f)

References anonymous_namespace{RealtimeEffectState.cpp}::AllocateChannelsToProcessors(), EnsureInstance(), mCurrentProcessor, mGroups, mOutputs, mPlugin, mWorkerSettings, and anonymous_namespace{ClipSegmentTest.cpp}::sampleRate.

Referenced by RealtimeEffectManager::AddGroup().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ EnsureInstance()

std::shared_ptr< EffectInstance > RealtimeEffectState::EnsureInstance ( double  rate)
private

copying settings in the main thread while worker isn't yet running

If there was already an instance, recycle it; else make one here

Definition at line 379 of file RealtimeEffectState.cpp.

380{
381 if (!mPlugin)
382 return {};
383
384 auto pInstance = mwInstance.lock();
385 if (!mInitialized) {
389
391 if (!pInstance)
392 mwInstance = pInstance = MakeInstance();
393 if (!pInstance)
394 return {};
395
396 // PRL: conserving pre-3.2.0 behavior, but I don't know why this arbitrary
397 // number was important
398 pInstance->SetBlockSize(512);
399
400 if (!pInstance->RealtimeInitialize(mMainSettings.settings, sampleRate))
401 return {};
402 mInitialized = true;
403 return pInstance;
404 }
405 return pInstance;
406}
NonInterfering< SettingsAndCounter > mMainSettings
Updated immediately by Access::Set in the main thread.
bool mLastActive
Assigned in the worker thread at the start of each processing scope.
bool IsActive() const noexcept
Test only in the worker thread, or else when there is no processing.
std::shared_ptr< EffectInstance > MakeInstance()
std::weak_ptr< EffectInstance > mwInstance
Stateful instance made by the plug-in.

References IsActive(), MakeInstance(), mInitialized, mLastActive, mMainSettings, mPlugin, mwInstance, mWorkerSettings, and anonymous_namespace{ClipSegmentTest.cpp}::sampleRate.

Referenced by AddGroup(), and Initialize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Finalize()

bool RealtimeEffectState::Finalize ( )
noexcept

Main thread cleans up playback.

Definition at line 654 of file RealtimeEffectState.cpp.

655{
656 mGroups.clear();
658
659 auto pInstance = mwInstance.lock();
660 if (!pInstance)
661 return false;
662
663 if (!pInstance->UsesMessages()) {
664 // This is the main thread cleaning up a state not now used in processing
666 }
667
668 auto result = pInstance->RealtimeFinalize(mMainSettings.settings);
669 mLatency = {};
670 mInitialized = false;
671 return result;
672}
std::optional< EffectInstance::SampleCount > mLatency
How many samples must be discarded.

References mCurrentProcessor, mGroups, mInitialized, mLatency, mMainSettings, mwInstance, and mWorkerSettings.

Referenced by RealtimeEffectManager::Finalize().

Here is the caller graph for this function:

◆ GetAccess()

std::shared_ptr< EffectSettingsAccess > RealtimeEffectState::GetAccess ( )

Expose access so a dialog can be connected to this state To be called by the main thread only

Postcondition
result: result != nullptr

Definition at line 784 of file RealtimeEffectState.cpp.

785{
786 if (!GetEffect())
787 // Effect not found!
788 // Return a dummy
789 return std::make_shared<Access>();
790
791 // Only the main thread assigns to the atomic pointer, here and
792 // once only in the lifetime of the state
793 if (!GetAccessState())
794 {
795 MakeInstance();
796 mpAccessState.emplace(*mPlugin, *this);
797 }
798
799 return std::make_shared<Access>(*this);
800}
AccessState * GetAccessState() const
const EffectInstanceFactory * GetEffect()
Initializes the effect on demand.
AtomicUniquePointer< AccessState > mpAccessState

References GetAccessState(), GetEffect(), MakeInstance(), mpAccessState, and mPlugin.

Referenced by SetActive(), and RealtimeEffectStateUI::Show().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetAccessState()

AccessState * RealtimeEffectState::GetAccessState ( ) const
inlineprivate

Definition at line 127 of file RealtimeEffectState.h.

128 {
129 return mpAccessState.load(std::memory_order_relaxed);
130 }

Referenced by GetAccess(), and MakeInstance().

Here is the caller graph for this function:

◆ GetEffect() [1/2]

const EffectInstanceFactory * RealtimeEffectState::GetEffect ( )

Initializes the effect on demand.

Definition at line 344 of file RealtimeEffectState.cpp.

345{
346 if (!mPlugin) {
348 if (mPlugin) {
349 // Also make EffectSettings, but preserve activation
350 auto wasActive = mMainSettings.settings.extra.GetActive();
351 mMainSettings.counter = 0;
352 mMainSettings.settings = mPlugin->MakeSettings();
353 mMainSettings.settings.extra.SetActive(wasActive);
356 }
357 }
358 return mPlugin;
359}
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.
std::unique_ptr< EffectOutputs > mMovedOutputs

References GlobalHook< EffectFactory, const EffectInstanceFactory *(const PluginID &) >::Call(), EffectSettingsManager::MakeOutputs(), EffectSettingsManager::MakeSettings(), mID, mMainSettings, mMovedOutputs, mOutputs, and mPlugin.

Referenced by GetAccess(), and SetID().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetEffect() [2/2]

const EffectInstanceFactory * RealtimeEffectState::GetEffect ( ) const
inline

const accessor will not initialize the effect on demand

Definition at line 58 of file RealtimeEffectState.h.

58{ return mPlugin; }

◆ GetID()

const PluginID & RealtimeEffectState::GetID ( ) const
noexcept

Definition at line 339 of file RealtimeEffectState.cpp.

340{
341 return mID;
342}

References mID.

Referenced by RealtimeEffectStateUI::Show(), and RealtimeEffectStateUI::UpdateTitle().

Here is the caller graph for this function:

◆ GetInstance()

std::shared_ptr< EffectInstance > RealtimeEffectState::GetInstance ( )

Expose a pointer to the state's instance (making one as needed).

Postcondition
true (no promise result is not null)

If there was already an instance, recycle it; else make one here

Definition at line 408 of file RealtimeEffectState.cpp.

409{
411 auto pInstance = mwInstance.lock();
412 if (!pInstance && mPlugin)
413 mwInstance = pInstance = MakeInstance();
414 return pInstance;
415}

References MakeInstance(), mPlugin, and mwInstance.

Here is the call graph for this function:

◆ GetOutputs()

const EffectOutputs * RealtimeEffectState::GetOutputs ( ) const
inline

Get locations that a GUI can connect meters to.

Definition at line 67 of file RealtimeEffectState.h.

67{ return mMovedOutputs.get(); }

◆ GetSettings()

const EffectSettings & RealtimeEffectState::GetSettings ( ) const
inline

Definition at line 91 of file RealtimeEffectState.h.

91{ return mMainSettings.settings; }

◆ HandleXMLChild()

XMLTagHandler * RealtimeEffectState::HandleXMLChild ( const std::string_view &  tag)
overridevirtual

Implements XMLTagHandler.

Definition at line 740 of file RealtimeEffectState.cpp.

741{
742 // Tag may be for the state, or the list of parameters, or for one parameter.
743 // See the writing method below. All are handled by this
744 return this;
745}

◆ HandleXMLEndTag()

void RealtimeEffectState::HandleXMLEndTag ( const std::string_view &  tag)
override

Definition at line 729 of file RealtimeEffectState.cpp.

730{
731 if (tag == XMLTag()) {
732 if (mPlugin && !mParameters.empty()) {
734 mPlugin->LoadSettings(parms, mMainSettings.settings);
735 }
736 mParameters.clear();
737 }
738}
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
virtual bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const =0
Restore settings from keys and values.
static const std::string & XMLTag()

References EffectSettingsManager::LoadSettings(), mMainSettings, mParameters, mPlugin, and XMLTag().

Here is the call graph for this function:

◆ HandleXMLTag()

bool RealtimeEffectState::HandleXMLTag ( const std::string_view &  tag,
const AttributesList attrs 
)
overridevirtual

Implements XMLTagHandler.

Definition at line 688 of file RealtimeEffectState.cpp.

690{
691 if (tag == XMLTag()) {
692 mParameters.clear();
693 mPlugin = nullptr;
694 mID.clear();
695 for (auto &[attr, value] : attrs) {
696 if (attr == idAttribute) {
697 SetID(value.ToWString());
698 if (!mPlugin) {
699 // TODO - complain!!!!
700 }
701 }
702 else if (attr == versionAttribute) {
703 }
704 else if (attr == activeAttribute)
705 // Updating the EffectSettingsExtra although we haven't yet built
706 // the settings
707 mMainSettings.settings.extra.SetActive(value.Get<bool>());
708 }
709 return true;
710 }
711 else if (tag == parametersAttribute)
712 return true;
713 else if (tag == parameterAttribute) {
714 wxString n;
715 wxString v;
716 for (auto &[attr, value] : attrs) {
717 if (attr == nameAttribute)
718 n = value.ToWString();
719 else if (attr == valueAttribute)
720 v = value.ToWString();
721 }
722 mParameters += wxString::Format(wxT("\"%s=%s\" "), n, v);
723 return true;
724 }
725 else
726 return false;
727}
wxT("CloseDown"))
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

References activeAttribute, idAttribute, mID, mMainSettings, mParameters, mPlugin, nameAttribute, parameterAttribute, parametersAttribute, SetID(), valueAttribute, versionAttribute, wxT(), and XMLTag().

Here is the call graph for this function:

◆ Initialize()

std::shared_ptr< EffectInstance > RealtimeEffectState::Initialize ( double  rate)

Main thread sets up for playback.

Definition at line 418 of file RealtimeEffectState.cpp.

419{
420 if (!mPlugin)
421 return {};
422
424 mGroups.clear();
425 mLatency = {};
427}

References EnsureInstance(), mCurrentProcessor, mGroups, mLatency, mPlugin, and anonymous_namespace{ClipSegmentTest.cpp}::sampleRate.

Referenced by RealtimeEffectManager::Initialize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsActive()

bool RealtimeEffectState::IsActive ( ) const
noexcept

Test only in the worker thread, or else when there is no processing.

Definition at line 635 of file RealtimeEffectState.cpp.

636{
637 return mWorkerSettings.settings.extra.GetActive();
638}

References mWorkerSettings.

Referenced by EnsureInstance(), ProcessEnd(), and ProcessStart().

Here is the caller graph for this function:

◆ IsEnabled()

bool RealtimeEffectState::IsEnabled ( ) const
noexcept

Test only in the main thread.

Definition at line 630 of file RealtimeEffectState.cpp.

631{
632 return mMainSettings.settings.extra.GetActive();
633}

References mMainSettings.

◆ MakeInstance()

std::shared_ptr< EffectInstance > RealtimeEffectState::MakeInstance ( )
private

Definition at line 361 of file RealtimeEffectState.cpp.

362{
363 mMovedMessage.reset();
364 mMessage.reset();
365 auto result = mPlugin->MakeInstance();
366 if (result) {
367 // Allocate presized containers in messages, so later
368 // copies of contents might avoid free store operations
369 mMessage = result->MakeMessage();
370 mMovedMessage = result->MakeMessage();
371 if (auto state = GetAccessState())
372 state->Initialize(mMainSettings.settings,
373 mMessage.get(), mMovedOutputs.get());
374 }
375 return result;
376}
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
std::unique_ptr< EffectInstance::Message > mMessage
std::unique_ptr< EffectInstance::Message > mMovedMessage

References GetAccessState(), EffectInstanceFactory::MakeInstance(), mMainSettings, mMessage, mMovedMessage, mMovedOutputs, and mPlugin.

Referenced by EnsureInstance(), GetAccess(), and GetInstance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=()

RealtimeEffectState & RealtimeEffectState::operator= ( const RealtimeEffectState other)
delete

◆ Process()

size_t RealtimeEffectState::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.

Visit the effect processors that were added in AddGroup.

Returns
how many leading samples are discardable for latency

The iteration over channels in AddGroup and Process must be the same

Parameters
inbufchans input buffers
outbufchans output buffers
dummybufone dummy output buffer

Definition at line 535 of file RealtimeEffectState.cpp.

539{
540 auto pInstance = mwInstance.lock();
541 if (!mPlugin || !pInstance || !mLastActive) {
542 // Process trivially
543 for (size_t ii = 0; ii < chans; ++ii)
544 memcpy(outbuf[ii], inbuf[ii], numSamples * sizeof(float));
545 return 0;
546 }
547 const auto numAudioIn = pInstance->GetAudioInCount();
548 const auto numAudioOut = pInstance->GetAudioOutCount();
549 const auto clientIn = stackAllocate(const float *, numAudioIn);
550 const auto clientOut = stackAllocate(float *, numAudioOut);
551 size_t len = 0;
552 const auto &pair = mGroups[&group];
553 auto processor = pair.first;
554 // Outer loop over processors
555 AllocateChannelsToProcessors(chans, numAudioIn, numAudioOut,
556 [&](unsigned indx, unsigned ondx){
557 // Point at the correct input buffers
558 unsigned copied = std::min(chans - indx, numAudioIn);
559 std::copy(inbuf + indx, inbuf + indx + copied, clientIn);
560 // If there are too few input channels for what the processor requires,
561 // re-use input channels from the beginning
562 while (auto need = numAudioIn - copied) {
563 auto moreCopied = std::min(chans, need);
564 std::copy(inbuf, inbuf + moreCopied, clientIn + copied);
565 copied += moreCopied;
566 }
567
568 // Point at the correct output buffers
569 copied = std::min(chans - ondx, numAudioOut);
570 std::copy(outbuf + ondx, outbuf + ondx + copied, clientOut);
571 if (copied < numAudioOut) {
572 // Make determinate pointers
573 std::fill(clientOut + copied, clientOut + numAudioOut, dummybuf);
574 }
575
576 // Inner loop over blocks
577 const auto blockSize = pInstance->GetBlockSize();
578 for (size_t block = 0; block < numSamples; block += blockSize) {
579 auto cnt = std::min(numSamples - block, blockSize);
580 // Assuming we are in a processing scope, use the worker settings
581 auto processed = pInstance->RealtimeProcess(processor,
582 mWorkerSettings.settings, clientIn, clientOut, cnt);
583 if (!mLatency)
584 // Find latency once only per initialization scope,
585 // after processing one block
586 mLatency.emplace(
587 pInstance->GetLatency(mWorkerSettings.settings, pair.second));
588 for (size_t i = 0 ; i < numAudioIn; i++)
589 if (clientIn[i])
590 clientIn[i] += cnt;
591 for (size_t i = 0 ; i < numAudioOut; i++)
592 if (clientOut[i])
593 clientOut[i] += cnt;
594 if (ondx == 0) {
595 // For the first processor only
596 len += processed;
597 auto discard = limitSampleBufferSize(len, *mLatency);
598 len -= discard;
599 *mLatency -= discard;
600 }
601 }
602 ++processor;
603 return true;
604 });
605 // Report the number discardable during the processing scope
606 // We are assuming len as calculated above is the same in case of multiple
607 // processors
608 return numSamples - len;
609}
int min(int a, int b)
#define stackAllocate(T, count)
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40

References anonymous_namespace{RealtimeEffectState.cpp}::AllocateChannelsToProcessors(), staffpad::vo::copy(), limitSampleBufferSize(), mGroups, min(), mLastActive, mLatency, mPlugin, mwInstance, mWorkerSettings, and stackAllocate.

Referenced by RealtimeEffectManager::Process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessEnd()

bool RealtimeEffectState::ProcessEnd ( )

Worker thread finishes a batch of samples.

Definition at line 611 of file RealtimeEffectState.cpp.

612{
613 auto pInstance = mwInstance.lock();
614 bool result = pInstance &&
615 // Assuming we are in a processing scope, use the worker settings
616 pInstance->RealtimeProcessEnd(mWorkerSettings.settings) &&
618
619 if (auto pAccessState = TestAccessState())
620 // Always done, regardless of activity
621 // Some dialogs require communication back from the processor so that
622 // they can update their appearance in idle time, and some plug-in
623 // libraries (like lv2) require the host program to mediate the
624 // communication
625 pAccessState->WorkerWrite();
626
627 return result;
628}
AccessState * TestAccessState() const

References IsActive(), mLastActive, mwInstance, mWorkerSettings, and TestAccessState().

Referenced by RealtimeEffectManager::ProcessEnd().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessStart()

bool RealtimeEffectState::ProcessStart ( bool  running)

Worker thread begins a batch of samples.

Parameters
runningmeans no pause or deactivation of containing list

Definition at line 490 of file RealtimeEffectState.cpp.

491{
492 // Get state changes from the main thread
493 // Note that it is only here that the answer of IsActive() may be changed,
494 // and it is important that for each state the answer is unchanging in one
495 // processing scope.
496 if (auto pAccessState = TestAccessState())
497 pAccessState->WorkerRead();
498
499 // Detect transitions of activity state
500 auto pInstance = mwInstance.lock();
501 bool active = IsActive() && running;
502 if (active != mLastActive) {
503 if (pInstance) {
504 bool success = active
505 ? pInstance->RealtimeResume()
506 : pInstance->RealtimeSuspend();
507 if (!success)
508 return false;
509 }
510 mLastActive = active;
511 }
512
513 bool result = false;
514 if (pInstance) {
515 // Consume messages even if not processing
516 // (issue #3855: plain UI for VST 2 effects)
517
518 // Assuming we are in a processing scope, use the worker settings
520 mWorkerSettings.settings, mMovedMessage.get()
521 };
522 result = pInstance->RealtimeProcessStart(package);
523 }
524
525 if (!pInstance || !active)
526 return false;
527 else
528 return result;
529}

References IsActive(), mLastActive, mMovedMessage, mwInstance, mWorkerSettings, and TestAccessState().

Referenced by RealtimeEffectManager::ProcessStart().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetActive()

void RealtimeEffectState::SetActive ( bool  active)

Set only in the main thread.

Definition at line 640 of file RealtimeEffectState.cpp.

641{
642 auto access = GetAccess();
643 access->ModifySettings([&](EffectSettings &settings) {
644 settings.extra.SetActive(active);
645 return nullptr;
646 });
647 access->Flush();
648
649 Publish(active
652}
static Settings & settings()
Definition: TrackInfo.cpp:47
CallbackReturn Publish(const RealtimeEffectStateChange &message)
Send a message to connected callbacks.
Definition: Observer.h:207
std::shared_ptr< EffectSettingsAccess > GetAccess()
Externalized state of a plug-in.

References EffectOff, EffectOn, GetAccess(), Observer::Publisher< RealtimeEffectStateChange >::Publish(), and settings().

Here is the call graph for this function:

◆ SetID()

void RealtimeEffectState::SetID ( const PluginID id)

May be called with nonempty id at most once in the lifetime of a state.

Call with empty id is ignored. Called by the constructor that takes an id

Definition at line 327 of file RealtimeEffectState.cpp.

328{
329 bool empty = id.empty();
330 if (mID.empty() && !empty) {
331 mID = id;
332 GetEffect();
333 }
334 else
335 // Set mID to non-empty at most once
336 assert(empty);
337}
int id

References GetEffect(), id, and mID.

Referenced by HandleXMLTag(), and RealtimeEffectState().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TestAccessState()

AccessState * RealtimeEffectState::TestAccessState ( ) const
inlineprivate

Definition at line 131 of file RealtimeEffectState.h.

132 {
133 return mpAccessState.load(std::memory_order_acquire);
134 }

Referenced by ProcessEnd(), and ProcessStart().

Here is the caller graph for this function:

◆ WriteXML()

void RealtimeEffectState::WriteXML ( XMLWriter xmlFile)

Definition at line 747 of file RealtimeEffectState.cpp.

748{
749 if (!mPlugin)
750 return;
751
752 xmlFile.StartTag(XMLTag());
753 const auto active = mMainSettings.settings.extra.GetActive();
754 xmlFile.WriteAttr(activeAttribute, active);
757
758 CommandParameters cmdParms;
759 if (mPlugin->SaveSettings(mMainSettings.settings, cmdParms)) {
761
762 wxString entryName;
763 long entryIndex;
764 bool entryKeepGoing;
765
766 entryKeepGoing = cmdParms.GetFirstEntry(entryName, entryIndex);
767 while (entryKeepGoing) {
768 wxString entryValue = cmdParms.Read(entryName, "");
769
771 xmlFile.WriteAttr(nameAttribute, entryName);
772 xmlFile.WriteAttr(valueAttribute, entryValue);
773 xmlFile.EndTag(parameterAttribute);
774
775 entryKeepGoing = cmdParms.GetNextEntry(entryName, entryIndex);
776 }
777
779 }
780
781 xmlFile.EndTag(XMLTag());
782}
virtual wxString GetVersion() const =0
virtual bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const =0
Store settings as keys and values.
static PluginID GetID(PluginProvider *provider)
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:79
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:102

References activeAttribute, XMLWriter::EndTag(), PluginManager::GetID(), ComponentInterface::GetVersion(), idAttribute, mMainSettings, mPlugin, nameAttribute, parameterAttribute, parametersAttribute, EffectSettingsManager::SaveSettings(), XMLWriter::StartTag(), valueAttribute, versionAttribute, XMLWriter::WriteAttr(), and XMLTag().

Here is the call graph for this function:

◆ XMLTag()

const std::string & RealtimeEffectState::XMLTag ( )
static

Definition at line 674 of file RealtimeEffectState.cpp.

675{
676 static const std::string result{"effect"};
677 return result;
678}

Referenced by RealtimeEffectList::HandleXMLChild(), HandleXMLEndTag(), HandleXMLTag(), and WriteXML().

Here is the caller graph for this function:

Member Data Documentation

◆ mCurrentProcessor

size_t RealtimeEffectState::mCurrentProcessor { 0 }
private

Definition at line 197 of file RealtimeEffectState.h.

Referenced by AddGroup(), Finalize(), and Initialize().

◆ mGroups

std::unordered_map<const ChannelGroup *, std::pair<size_t, double> > RealtimeEffectState::mGroups
private

Definition at line 189 of file RealtimeEffectState.h.

Referenced by AddGroup(), Finalize(), Initialize(), and Process().

◆ mID

PluginID RealtimeEffectState::mID
private

Definition at line 136 of file RealtimeEffectState.h.

Referenced by GetEffect(), GetID(), HandleXMLTag(), and SetID().

◆ mInitialized

bool RealtimeEffectState::mInitialized { false }
private

Definition at line 198 of file RealtimeEffectState.h.

Referenced by EnsureInstance(), and Finalize().

◆ mLastActive

bool RealtimeEffectState::mLastActive {}
private

Assigned in the worker thread at the start of each processing scope.

Definition at line 180 of file RealtimeEffectState.h.

Referenced by EnsureInstance(), Process(), ProcessEnd(), and ProcessStart().

◆ mLatency

std::optional<EffectInstance::SampleCount> RealtimeEffectState::mLatency
private

How many samples must be discarded.

Definition at line 178 of file RealtimeEffectState.h.

Referenced by Finalize(), Initialize(), and Process().

◆ mMainSettings

NonInterfering<SettingsAndCounter> RealtimeEffectState::mMainSettings
private

◆ mMessage

std::unique_ptr<EffectInstance::Message> RealtimeEffectState::mMessage
private

◆ mMovedMessage

std::unique_ptr<EffectInstance::Message> RealtimeEffectState::mMovedMessage
private

◆ mMovedOutputs

std::unique_ptr<EffectOutputs> RealtimeEffectState::mMovedOutputs
private

◆ mOutputs

std::unique_ptr<EffectOutputs> RealtimeEffectState::mOutputs
private

◆ mpAccessState

AtomicUniquePointer<AccessState> RealtimeEffectState::mpAccessState { nullptr }
private

Definition at line 194 of file RealtimeEffectState.h.

Referenced by GetAccess().

◆ mParameters

wxString RealtimeEffectState::mParameters
private

Definition at line 196 of file RealtimeEffectState.h.

Referenced by HandleXMLEndTag(), and HandleXMLTag().

◆ mPlugin

const EffectInstanceFactory* RealtimeEffectState::mPlugin {}
private

◆ mwInstance

std::weak_ptr<EffectInstance> RealtimeEffectState::mwInstance
private

Stateful instance made by the plug-in.

Definition at line 139 of file RealtimeEffectState.h.

Referenced by EnsureInstance(), Finalize(), GetInstance(), Process(), ProcessEnd(), and ProcessStart().

◆ mWorkerSettings

NonInterfering<SettingsAndCounter> RealtimeEffectState::mWorkerSettings
private

Updated with delay, but atomically, in the worker thread; skipped by the copy constructor so that there isn't a race when pushing an Undo state

Definition at line 173 of file RealtimeEffectState.h.

Referenced by AddGroup(), EnsureInstance(), Finalize(), IsActive(), Process(), ProcessEnd(), ProcessStart(), RealtimeEffectState::AccessState::FromMainSlot::Reader::Reader(), and RealtimeEffectState::AccessState::WorkerWrite().


The documentation for this class was generated from the following files: