81 arg.effect.CopySettingsContents(
119 settings.extra = slot.mSettings.extra;
139 :
mwState{ state.weak_from_this() }
147 if (!lastSettings.has_value() ||
148 pResult->extra.GetCounter() ==
149 lastSettings.extra.GetCounter()
162 if (
auto pState =
mwState.lock()) {
163 if (
auto pAccessState = pState->GetAccessState()) {
165 auto &lastSettings = pAccessState->mLastSettings;
166 return lastSettings.has_value()
170 : pAccessState->MainThreadCache();
178 if (
auto pState =
mwState.lock())
179 if (
auto pAccessState = pState->GetAccessState()) {
180 auto &lastSettings = pAccessState->mLastSettings;
181 auto lastCounter = lastSettings.extra.GetCounter();
182 settings.extra.SetCounter(++lastCounter);
190 if (
auto pState =
mwState.lock()) {
191 if (
auto pAccessState = pState->GetAccessState()) {
195 using namespace std::chrono;
196 std::this_thread::sleep_for(50ms);
198 pState->mMainSettings.Set(*pResult);
199 pAccessState->mLastSettings = *pResult;
204 if (
auto pOther =
dynamic_cast<const Access*
>(&other)) {
206 auto &theirs = pOther->mwState;
207 auto less = std::owner_less{};
208 return !(less(mine, theirs) || less(theirs, mine));
223 , mPlugin{ other.mPlugin }
224 , mMainSettings{ other.mMainSettings }
233 bool empty =
id.empty();
234 if (
mID.empty() && !empty) {
263std::shared_ptr<EffectInstance>
285 pInstance->SetBlockSize(512);
287 if (!pInstance->RealtimeInitialize(
mMainSettings, sampleRate))
303std::shared_ptr<EffectInstance>
316std::shared_ptr<EffectInstance>
336 while (ichans > 0 && ochans > 0)
341 if (ichans < numAudioIn)
349 else if (ichans >= numAudioIn)
358 if (ochans < numAudioOut)
366 else if (ochans >= numAudioOut)
368 ochans -= numAudioOut;
374 if (pInstance->RealtimeAddProcessor(
mWorkerSettings, gchans, sampleRate))
394 pAccessState->WorkerRead();
398 bool active =
IsActive() && running;
401 bool success = active
402 ? pInstance->RealtimeResume()
403 : pInstance->RealtimeSuspend();
410 if (!pInstance || !active)
420 const float *
const *inbuf,
float *
const *outbuf,
size_t numSamples)
425 for (
size_t ii = 0; ii < chans; ++ii)
426 memcpy(outbuf[ii], inbuf[ii], numSamples *
sizeof(
float));
441 const auto clientIn =
442 static_cast<const float **
>(alloca(numAudioIn *
sizeof(
float *)));
443 const auto clientOut =
444 static_cast<float **
>(alloca(numAudioOut *
sizeof(
float *)));
445 decltype(numSamples) len = 0;
452 auto processor =
mGroups[&track];
455 while (ichans > 0 && ochans > 0)
459 if (ichans < numAudioIn)
461 for (
size_t i = 0; i < numAudioIn; i++)
462 clientIn[i] = inbuf[indx++];
470 else if (ichans >= numAudioIn)
473 for (
size_t i = 0; i < numAudioIn; i++, ichans--, gchans++)
475 clientIn[i] = inbuf[indx++];
482 if (ochans < numAudioOut)
484 for (
size_t i = 0; i < numAudioOut; i++)
485 clientOut[i] = outbuf[i];
493 else if (ochans >= numAudioOut)
495 for (
size_t i = 0; i < numAudioOut; i++, ochans--)
497 clientOut[i] = outbuf[ondx++];
503 const auto blockSize = pInstance->GetBlockSize();
504 for (
decltype(numSamples) block = 0; block < numSamples; block += blockSize)
506 auto cnt =
std::min(numSamples - block, blockSize);
508 len += pInstance->RealtimeProcess(processor,
511 for (
size_t i = 0 ; i < numAudioIn; i++)
516 for (
size_t i = 0 ; i < numAudioOut; i++)
538 pAccessState->WorkerWrite();
572 static const std::string result{
"effect"};
591 for (
auto &[attr, value] : attrs) {
593 SetID(value.ToWString());
612 for (
auto &[attr, value] : attrs) {
614 n = value.ToWString();
616 v = value.ToWString();
618 mParameters += wxString::Format(wxT(
"\"%s=%s\" "), n, v);
662 entryKeepGoing = cmdParms.GetFirstEntry(entryName, entryIndex);
663 while (entryKeepGoing) {
664 wxString entryValue = cmdParms.Read(entryName,
"");
671 entryKeepGoing = cmdParms.GetNextEntry(entryName, entryIndex);
684 return std::make_shared<Access>();
690 return std::make_shared<Access>(*
this);
@ WorkerToMain
Worker thread settings replicated to main thread.
@ MainToWorker
Main thread settings replicated to the worker thread.
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
static Settings & settings()
std::vector< Attribute > AttributesList
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
virtual wxString GetVersion() const =0
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
virtual unsigned GetAudioOutCount() const =0
How many output buffers to allocate at once.
virtual unsigned GetAudioInCount() const =0
How many input buffers to allocate at once.
EffectSettingsManager is an EffectDefinitionInterface that adds a factory function for EffectSettings...
virtual bool CopySettingsContents(const EffectSettings &src, EffectSettings &dst, SettingsCopyDirection copyDirection) const
Update one settings object from another.
virtual bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const =0
Restore settings from keys and values.
virtual bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const =0
Store settings as keys and values.
virtual EffectSettings MakeSettings() const
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
Communicate data atomically from one writer thread to one reader.
static PluginID GetID(PluginProvider *provider)
Mediator of two-way inter-thread communication of changes of settings.
const EffectSettings & MainThreadCache() const
MessageBuffer< ToMainSlot > mChannelToMain
const EffectSettingsManager & mEffect
RealtimeEffectState & mState
EffectSettings mMainThreadCache
const EffectSettings & MainWriteThrough(const EffectSettings &settings)
AccessState(const EffectSettingsManager &effect, RealtimeEffectState &state)
MessageBuffer< FromMainSlot > mChannelFromMain
void MainWrite(EffectSettings &&settings)
EffectSettings mLastSettings
const EffectSettings & MainRead()
NonInterfering< EffectSettings > mMainSettings
Updated immediately by Access::Set in the main thread.
const EffectInstanceFactory * mPlugin
Stateless effect object.
void HandleXMLEndTag(const std::string_view &tag) override
std::shared_ptr< EffectInstance > GetInstance()
Expose a pointer to the state's instance (making one as needed).
std::shared_ptr< EffectSettingsAccess > GetAccess()
bool ProcessEnd()
Worker thread finishes a batch of samples.
AccessState * GetAccessState() const
AccessState * TestAccessState() const
static const std::string & XMLTag()
bool Finalize() noexcept
Main thread cleans up playback.
NonInterfering< EffectSettings > mWorkerSettings
std::shared_ptr< EffectInstance > EnsureInstance(double rate)
bool ProcessStart(bool running)
Worker thread begins a batch of samples.
bool IsEnabled() const noexcept
Test only in the main thread.
const PluginID & GetID() const noexcept
bool mLastActive
Assigned in the worker thread at the start of each processing scope.
std::shared_ptr< EffectInstance > AddTrack(Track &track, unsigned chans, float sampleRate)
Main thread sets up this state before adding it to lists.
void WriteXML(XMLWriter &xmlFile)
RealtimeEffectState(const PluginID &id)
bool IsActive() const noexcept
Test only in the worker thread, or else when there is no processing.
std::shared_ptr< EffectInstance > Initialize(double rate)
Main thread sets up for playback.
std::unordered_map< Track *, size_t > mGroups
const EffectInstanceFactory * GetEffect()
Initializes the effect on demand.
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
void SetID(const PluginID &id)
May be called with nonempty id at most once in the lifetime of a state.
std::weak_ptr< EffectInstance > mwInstance
Stateful instance made by the plug-in.
AtomicUniquePointer< AccessState > mpAccessState
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
void Process(Track &track, unsigned chans, const float *const *inbuf, float *const *outbuf, size_t numSamples)
Worker thread processes part of a batch of samples.
Abstract base class for an object holding data associated with points on a time axis.
This class is an interface which should be implemented by classes which wish to be able to load and s...
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
virtual void StartTag(const wxString &name)
void WriteAttr(const wxString &name, const Identifier &value)
virtual void EndTag(const wxString &name)
Externalized state of a plug-in.
EffectSettingsExtra extra
void swap(EffectSettings &other)
void Set(const T &other)
Allow assignment from default-aligned base type.
Main thread's interface to inter-thread communication of changes of settings.
void Set(EffectSettings &&settings) override
const EffectSettings & Get() override
static const EffectSettings * FlushAttempt(AccessState &state)
Access(RealtimeEffectState &state)
bool IsSameAs(const EffectSettingsAccess &other) const override
void Flush() override
Make the last Set changes "persistent" in underlying storage.
~Access() override=default
std::weak_ptr< RealtimeEffectState > mwState
Store no state here but this weak pointer, so IsSameAs isn't lying.
const EffectSettings & settings
const EffectSettingsManager & effect
Reader(FromMainSlot &&slot, const EffectSettingsManager &effect, EffectSettings &settings)
FromMainSlot & operator=(FromMainSlot &&)=default
FromMainSlot(const EffectSettings &settings)
FromMainSlot & operator=(EffectSettings &&settings)
Reader(ToMainSlot &&slot, EffectSettings &settings)
ToMainSlot(const EffectSettings &settings)
ToMainSlot & operator=(ToMainSlot &&)=default
ToMainSlot & operator=(EffectAndSettings &&arg)