Sorry for the late response.
On 27.11.2024 02:51, ichthyo wrote:
...
Anyway, when investigating what is done with that SynthEngine pointer,
it turns out that access falls into various categories:
- many accesses actually need to know some runtime parameters,
like the sample rate or (very common!) the buffer size
- there is a (a smaller number) which need similar, config-like stuff.
- then there are a lot of accesses, which reach through the SynthEngine
into the InterChange, actually to communicate via the ringbuffers.
- a lot of further accesses (especially from the GUI) actually go
from the SynthEngine to the MasterUI and navigate to some sub component
of the UI. So in fact we'd need some kind of internal wiring / DI; so
this seems like something that can be sorted out without any major
changes
to the overall structure of the UI. (IMHO this structure is fine)
- and then there are the evil ones, those accesses which drill down
into internal stuff, like parts, effects, filters.
These observations brought me to the idea of introducing a "root-anchor"
DTO.
Because: assuming that we manage to get rid of the "evil" accesses,
all the other ones do not actually need the SynthEngine.
- most notably, the InterChange is accessed. But this is benign.
It is a communication service, and thus it is made to be accessed
from all threads. At some point, this could be an interface, not
the implementation. And it could be one communication service,
instead of having one for each Synth-Instance. Because in fact
the InterChange is stateless to a large degree; internally it
only talks to the appropriate set of ringbuffers.
Possibly, but keep in mind that LV2 hosts may choose to run different
instances in different threads, and may even destroy one while another
one is running. They are meant to be fully isolated instances. Some
hosts provide compatibility options to avoid doing this, but we should
not rely on this. So sharing them between instances may be a risky route
to take.
...
After thinking it over for a while, I also tend more and more to see this
initial connection as somewhat special. On the other hand, having it fully
integrated with GuiDataExchange has the benefit that it would allow
push-updates, e.g. when some config parameter changes.
But possibly both can be combined.
Because all those push-updates are processed in two steps
1) the core plants the data in the slot and sends a notification message
through the toGUI ringbuffer
2) later, asynchronously, the GUI processes this message, picks up the
data and dispatches it to the listener in the GUI, which was connected
using the appropriate routing-tag
Thus, we could indeed send the /initial/ rootAnchor DTO over a different
channel, as long as this ensures the data (which belongs to the
synth-thread)
is properly synched and visible for the UI-thread. In the GUI, the data
could then be dispatched with the existing publisher-subscriber setup.
Actually, this kind of handover looks like a promise/future pattern.
But there is the twist with the LV2 plugin. If I recall correct, a
promise can not be re-initialised. So this kind of usage only works
well when the promise is created before the other thread is started.
Because then both sides see the promise. From the promise object,
a future can then be created later, and used to get the data.
But if the other thread is already running, we're again on slippery ground.
The C++ standard does not specify how the promise works internally and
if it is safe to just grab it from another thread.
Hmm. But does it need to be this complicated? We are talking about a
pointer to either SynthEngine or, if we isolate it, the rootAnchor. And
my point is that this will not change during one plugin instance. Will
it? So grabbing it from another thread should be perfectly safe, because
within one instance, it can essentially be considered a constant.
The LV2 plugin depends on the LV2_INSTANCE_ACCESS feature, which
guarantees that a pointer to the core plugin is available, IOW
SynthEngine (directly or indirectly).
So basically we're in the situation that the code that wants to initiate
a new UI-bootstrap runs in the (prospective) UI thread. But we can not
be sure at that point that we can see data from the Synth-thread.
I believe we can, due to the LV2_INSTANCE_ACCESS feature. The assignment
of this pointer happens before anything else. Unless I'm missing something?
--
Kristian
_______________________________________________
Yoshimi-devel mailing list
Yoshimi-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/yoshimi-devel