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

693{
694 mGroups.clear();
696
697 auto pInstance = mwInstance.lock();
698 if (!pInstance)
699 return false;
700
701 if (!pInstance->UsesMessages()) {
702 // This is the main thread cleaning up a state not now used in processing
704 }
705
706 auto result = pInstance->RealtimeFinalize(mMainSettings.settings);
707 mLatency = {};
708 mInitialized = false;
709 return result;
710}
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 822 of file RealtimeEffectState.cpp.

823{
824 if (!GetEffect())
825 // Effect not found!
826 // Return a dummy
827 return std::make_shared<Access>();
828
829 // Only the main thread assigns to the atomic pointer, here and
830 // once only in the lifetime of the state
831 if (!GetAccessState())
832 {
833 MakeInstance();
834 mpAccessState.emplace(*mPlugin, *this);
835 }
836
837 return std::make_shared<Access>(*this);
838}
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 778 of file RealtimeEffectState.cpp.

779{
780 // Tag may be for the state, or the list of parameters, or for one parameter.
781 // See the writing method below. All are handled by this
782 return this;
783}

◆ HandleXMLEndTag()

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

Definition at line 767 of file RealtimeEffectState.cpp.

768{
769 if (tag == XMLTag()) {
770 if (mPlugin && !mParameters.empty()) {
772 mPlugin->LoadSettings(parms, mMainSettings.settings);
773 }
774 mParameters.clear();
775 }
776}
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 726 of file RealtimeEffectState.cpp.

728{
729 if (tag == XMLTag()) {
730 mParameters.clear();
731 mPlugin = nullptr;
732 mID.clear();
733 for (auto &[attr, value] : attrs) {
734 if (attr == idAttribute) {
735 SetID(value.ToWString());
736 if (!mPlugin) {
737 // TODO - complain!!!!
738 }
739 }
740 else if (attr == versionAttribute) {
741 }
742 else if (attr == activeAttribute)
743 // Updating the EffectSettingsExtra although we haven't yet built
744 // the settings
745 mMainSettings.settings.extra.SetActive(value.Get<bool>());
746 }
747 return true;
748 }
749 else if (tag == parametersAttribute)
750 return true;
751 else if (tag == parameterAttribute) {
752 wxString n;
753 wxString v;
754 for (auto &[attr, value] : attrs) {
755 if (attr == nameAttribute)
756 n = value.ToWString();
757 else if (attr == valueAttribute)
758 v = value.ToWString();
759 }
760 mParameters += wxString::Format(wxT("\"%s=%s\" "), n, v);
761 return true;
762 }
763 else
764 return false;
765}
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 673 of file RealtimeEffectState.cpp.

674{
675 return mWorkerSettings.settings.extra.GetActive();
676}

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

669{
670 return mMainSettings.settings.extra.GetActive();
671}

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

650{
651 auto pInstance = mwInstance.lock();
652 bool result = pInstance &&
653 // Assuming we are in a processing scope, use the worker settings
654 pInstance->RealtimeProcessEnd(mWorkerSettings.settings) &&
656
657 if (auto pAccessState = TestAccessState())
658 // Always done, regardless of activity
659 // Some dialogs require communication back from the processor so that
660 // they can update their appearance in idle time, and some plug-in
661 // libraries (like lv2) require the host program to mediate the
662 // communication
663 pAccessState->WorkerWrite();
664
665 return result;
666}
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 678 of file RealtimeEffectState.cpp.

679{
680 auto access = GetAccess();
681 access->ModifySettings([&](EffectSettings &settings) {
682 settings.extra.SetActive(active);
683 return nullptr;
684 });
685 access->Flush();
686
687 Publish(active
690}
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 785 of file RealtimeEffectState.cpp.

786{
787 if (!mPlugin)
788 return;
789
790 xmlFile.StartTag(XMLTag());
791 const auto active = mMainSettings.settings.extra.GetActive();
792 xmlFile.WriteAttr(activeAttribute, active);
795
796 CommandParameters cmdParms;
797 if (mPlugin->SaveSettings(mMainSettings.settings, cmdParms)) {
799
800 wxString entryName;
801 long entryIndex;
802 bool entryKeepGoing;
803
804 entryKeepGoing = cmdParms.GetFirstEntry(entryName, entryIndex);
805 while (entryKeepGoing) {
806 wxString entryValue = cmdParms.Read(entryName, "");
807
809 xmlFile.WriteAttr(nameAttribute, entryName);
810 xmlFile.WriteAttr(valueAttribute, entryValue);
811 xmlFile.EndTag(parameterAttribute);
812
813 entryKeepGoing = cmdParms.GetNextEntry(entryName, entryIndex);
814 }
815
817 }
818
819 xmlFile.EndTag(XMLTag());
820}
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 712 of file RealtimeEffectState.cpp.

713{
714 static const std::string result{"effect"};
715 return result;
716}

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: