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< EffectInstanceAddTrack (const Track &track, 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 Track &track, 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 slots ()
 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 Track *, 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 315 of file RealtimeEffectState.cpp.

316{
317 SetID(id);
318 BuildAll();
319}
void BuildAll()
For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it.
Definition: ClientData.h:441
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 321 of file RealtimeEffectState.cpp.

322{
323
324}

Member Function Documentation

◆ AddTrack()

std::shared_ptr< EffectInstance > RealtimeEffectState::AddTrack ( const Track track,
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 AddTrack and Process must be the same

Definition at line 457 of file RealtimeEffectState.cpp.

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

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

Referenced by RealtimeEffectManager::AddTrack().

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

379{
380 if (!mPlugin)
381 return {};
382
383 auto pInstance = mwInstance.lock();
384 if (!mInitialized) {
388
390 if (!pInstance)
391 mwInstance = pInstance = MakeInstance();
392 if (!pInstance)
393 return {};
394
395 // PRL: conserving pre-3.2.0 behavior, but I don't know why this arbitrary
396 // number was important
397 pInstance->SetBlockSize(512);
398
399 if (!pInstance->RealtimeInitialize(mMainSettings.settings, sampleRate))
400 return {};
401 mInitialized = true;
402 return pInstance;
403 }
404 return pInstance;
405}
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, and mWorkerSettings.

Referenced by AddTrack(), 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 651 of file RealtimeEffectState.cpp.

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

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

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

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

344{
345 if (!mPlugin) {
347 if (mPlugin) {
348 // Also make EffectSettings, but preserve activation
349 auto wasActive = mMainSettings.settings.extra.GetActive();
350 mMainSettings.counter = 0;
351 mMainSettings.settings = mPlugin->MakeSettings();
352 mMainSettings.settings.extra.SetActive(wasActive);
355 }
356 }
357 return mPlugin;
358}
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 338 of file RealtimeEffectState.cpp.

339{
340 return mID;
341}

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

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

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

90{ return mMainSettings.settings; }

◆ HandleXMLChild()

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

Implements XMLTagHandler.

Definition at line 737 of file RealtimeEffectState.cpp.

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

◆ HandleXMLEndTag()

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

Definition at line 726 of file RealtimeEffectState.cpp.

727{
728 if (tag == XMLTag()) {
729 if (mPlugin && !mParameters.empty()) {
731 mPlugin->LoadSettings(parms, mMainSettings.settings);
732 }
733 mParameters.clear();
734 }
735}
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 685 of file RealtimeEffectState.cpp.

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

418{
419 if (!mPlugin)
420 return {};
421
423 mGroups.clear();
424 mLatency = {};
425 return EnsureInstance(sampleRate);
426}

References EnsureInstance(), mCurrentProcessor, mGroups, mLatency, and mPlugin.

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

633{
634 return mWorkerSettings.settings.extra.GetActive();
635}

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

628{
629 return mMainSettings.settings.extra.GetActive();
630}

References mMainSettings.

◆ MakeInstance()

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

Definition at line 360 of file RealtimeEffectState.cpp.

361{
362 mMovedMessage.reset();
363 mMessage.reset();
364 auto result = mPlugin->MakeInstance();
365 if (result) {
366 // Allocate presized containers in messages, so later
367 // copies of contents might avoid free store operations
368 mMessage = result->MakeMessage();
369 mMovedMessage = result->MakeMessage();
370 if (auto state = GetAccessState())
371 state->Initialize(mMainSettings.settings,
372 mMessage.get(), mMovedOutputs.get());
373 }
374 return result;
375}
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 Track track,
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 AddTrack.

Returns
how many leading samples are discardable for latency

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

Parameters
inbufchans input buffers
outbufchans output buffers
dummybufone dummy output buffer

Definition at line 533 of file RealtimeEffectState.cpp.

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

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

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

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

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

638{
639 auto access = GetAccess();
640 access->ModifySettings([&](EffectSettings &settings) {
641 settings.extra.SetActive(active);
642 return nullptr;
643 });
644 access->Flush();
645
646 Publish(active
649}
static Settings & settings()
Definition: TrackInfo.cpp:83
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 326 of file RealtimeEffectState.cpp.

327{
328 bool empty = id.empty();
329 if (mID.empty() && !empty) {
330 mID = id;
331 GetEffect();
332 }
333 else
334 // Set mID to non-empty at most once
335 assert(empty);
336}
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 130 of file RealtimeEffectState.h.

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

Referenced by ProcessEnd(), and ProcessStart().

Here is the caller graph for this function:

◆ WriteXML()

void RealtimeEffectState::WriteXML ( XMLWriter xmlFile)

Definition at line 744 of file RealtimeEffectState.cpp.

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

672{
673 static const std::string result{"effect"};
674 return result;
675}

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

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

◆ mGroups

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

Definition at line 187 of file RealtimeEffectState.h.

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

◆ mID

PluginID RealtimeEffectState::mID
private

Definition at line 135 of file RealtimeEffectState.h.

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

◆ mInitialized

bool RealtimeEffectState::mInitialized { false }
private

Definition at line 196 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 179 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 177 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 192 of file RealtimeEffectState.h.

Referenced by GetAccess().

◆ mParameters

wxString RealtimeEffectState::mParameters
private

Definition at line 194 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 138 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 172 of file RealtimeEffectState.h.

Referenced by AddTrack(), 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: