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...
 
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 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:449
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.

Precondition
group.IsLeader()

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

Definition at line 458 of file RealtimeEffectState.cpp.

460{
461 assert(group.IsLeader());
462 auto pInstance = EnsureInstance(sampleRate);
463 if (!pInstance)
464 return {};
465 if (!mPlugin)
466 return {};
467 auto first = mCurrentProcessor;
468 const auto numAudioIn = pInstance->GetAudioInCount();
469 const auto numAudioOut = pInstance->GetAudioOutCount();
470 AllocateChannelsToProcessors(chans, numAudioIn, numAudioOut,
471 [&](unsigned, unsigned){
472 // Add a NEW processor
473 if (pInstance->RealtimeAddProcessor(
474 mWorkerSettings.settings, mOutputs.get(), numAudioIn, sampleRate)
475 ) {
476 mCurrentProcessor++;
477 return true;
478 }
479 else
480 return false;
481 });
482 if (mCurrentProcessor > first) {
483 // Remember the sampleRate of the group, so latency can be computed
484 // later
485 mGroups[&group] = { first, sampleRate };
486 return pInstance;
487 }
488 return {};
489}
virtual bool IsLeader() const =0
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(), ChannelGroup::IsLeader(), 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 655 of file RealtimeEffectState.cpp.

656{
657 mGroups.clear();
659
660 auto pInstance = mwInstance.lock();
661 if (!pInstance)
662 return false;
663
664 if (!pInstance->UsesMessages()) {
665 // This is the main thread cleaning up a state not now used in processing
667 }
668
669 auto result = pInstance->RealtimeFinalize(mMainSettings.settings);
670 mLatency = {};
671 mInitialized = false;
672 return result;
673}
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 785 of file RealtimeEffectState.cpp.

786{
787 if (!GetEffect())
788 // Effect not found!
789 // Return a dummy
790 return std::make_shared<Access>();
791
792 // Only the main thread assigns to the atomic pointer, here and
793 // once only in the lifetime of the state
794 if (!GetAccessState())
795 {
796 MakeInstance();
797 mpAccessState.emplace(*mPlugin, *this);
798 }
799
800 return std::make_shared<Access>(*this);
801}
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 130 of file RealtimeEffectState.h.

131 {
132 return mpAccessState.load(std::memory_order_relaxed);
133 }

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 94 of file RealtimeEffectState.h.

94{ return mMainSettings.settings; }

◆ HandleXMLChild()

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

Implements XMLTagHandler.

Definition at line 741 of file RealtimeEffectState.cpp.

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

◆ HandleXMLEndTag()

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

Definition at line 730 of file RealtimeEffectState.cpp.

731{
732 if (tag == XMLTag()) {
733 if (mPlugin && !mParameters.empty()) {
735 mPlugin->LoadSettings(parms, mMainSettings.settings);
736 }
737 mParameters.clear();
738 }
739}
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 689 of file RealtimeEffectState.cpp.

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

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

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 631 of file RealtimeEffectState.cpp.

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

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 536 of file RealtimeEffectState.cpp.

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

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

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

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 641 of file RealtimeEffectState.cpp.

642{
643 auto access = GetAccess();
644 access->ModifySettings([&](EffectSettings &settings) {
645 settings.extra.SetActive(active);
646 return nullptr;
647 });
648 access->Flush();
649
650 Publish(active
653}
static Settings & settings()
Definition: TrackInfo.cpp:69
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 134 of file RealtimeEffectState.h.

135 {
136 return mpAccessState.load(std::memory_order_acquire);
137 }

Referenced by ProcessEnd(), and ProcessStart().

Here is the caller graph for this function:

◆ WriteXML()

void RealtimeEffectState::WriteXML ( XMLWriter xmlFile)

Definition at line 748 of file RealtimeEffectState.cpp.

749{
750 if (!mPlugin)
751 return;
752
753 xmlFile.StartTag(XMLTag());
754 const auto active = mMainSettings.settings.extra.GetActive();
755 xmlFile.WriteAttr(activeAttribute, active);
758
759 CommandParameters cmdParms;
760 if (mPlugin->SaveSettings(mMainSettings.settings, cmdParms)) {
762
763 wxString entryName;
764 long entryIndex;
765 bool entryKeepGoing;
766
767 entryKeepGoing = cmdParms.GetFirstEntry(entryName, entryIndex);
768 while (entryKeepGoing) {
769 wxString entryValue = cmdParms.Read(entryName, "");
770
772 xmlFile.WriteAttr(nameAttribute, entryName);
773 xmlFile.WriteAttr(valueAttribute, entryValue);
774 xmlFile.EndTag(parameterAttribute);
775
776 entryKeepGoing = cmdParms.GetNextEntry(entryName, entryIndex);
777 }
778
780 }
781
782 xmlFile.EndTag(XMLTag());
783}
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 675 of file RealtimeEffectState.cpp.

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

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 200 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 192 of file RealtimeEffectState.h.

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

◆ mID

PluginID RealtimeEffectState::mID
private

Definition at line 139 of file RealtimeEffectState.h.

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

◆ mInitialized

bool RealtimeEffectState::mInitialized { false }
private

Definition at line 201 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 183 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 181 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 197 of file RealtimeEffectState.h.

Referenced by GetAccess().

◆ mParameters

wxString RealtimeEffectState::mParameters
private

Definition at line 199 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 142 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 176 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: