Yes, thank you. I was afraid that I have just been “lucky” until now. I always strive to make things better, however, so this is a great opportunity to refactor the code into something more robust!
The lock-free fifo idea sounds like it may very well be the way to go. I’ll be looking at that as my new approach.
In the mean time, I’ve been analyzing my code, out of curiosity, to try to determine why it works as well as it does? I mean, as I’ve mentioned three or four times, it works great in Pro Tools. You’d think it would fail there, if it was going to fail anywhere. And, it also works great in Tacktion/Waveform (you may have some insight here).
I make a point of making all my code in the processBlock() as tight as possible. And, for example, I bypass code that is not changing, which includes the setValueNotifyingHost() calls. In fact, in a steady signal, dozens, if not hundreds, of blocks can go by without setValueNotifyingHost() being called. So maybe this has something to do with my “getting away with it”.
So, I’ve got work to do. And, the lock-free fifo idea is not too different from the way I feed data to my meters (although, they are on a much more relaxed schedule!). We are always learning. I think that is one of the reasons we code!
Maybe it is even only a problem in a combination, like having a certain amount of plugins, you can’t know… still a good idea to improve it.
It doesn’t sound, like it’s ever going to be sample accurate, so why not simply use callAsync with the setValueNotifyingHost()? Sounds easier to implement…
@t0m maybe while you’re working on the audioprocessor stuff, we should throw in some assertions to make sure people don’t call unsafe stuff from the audio thread? We could have a thread-local flag set during the process method, and have assertions that check for it, kind of like we do in some places for the message thread.
I don’t think this will work reliably, because there are hosts that call initialization methods from realtime threads before calling any process callback with them.
And therefore, all the methods called in those initialization phases will have a wrong indication because said hypotetical isRealtimeThread() method will return false at that point, but it will start returning true later on after the first processing callback has been called.
To be fair, on the other hand this may be a tolerated behavior, if we accept that “blocking” behavior can happen on a soon-to-be realtime thread, as long as it has not yet actually entered the processing loop
Playing the “devil’s advocate” now: what happens if the DAW decides to stop using a certain thread of its pool for realtime jobs, and assigns it to background stuff that still call into the plug-in?
That thread would still be marked as realtime while not really being anymore.
Maybe while designing this, allow for another method to query whether the current DAW is to be trusted or not. I suppose most DAWs will be implemented in a sensible way and the answer will be “yes”, but you may never know.
I think you misunderstood what I meant: I was suggesting having a thread-local variable “isAudioThread”, which is set to true at the start of process() and set to false at the end. That way it doesn’t matter if the thread changes.
Ah yes, I misunderstood your proposal, I figured you wanted to set the flag to “true” upon first processBlock to “tag” the thread from then on, which is something that I considered myself for exactly this purpose.
Regarding your idea, it is equivalent to having a method that informs whether the AudioProcessor::getCallbackLock() is taken by the current thread.
On one hand, that’s a facility that is already available for the special case of the MessageManagerLock, so I don’t see why not adding it also for the callback lock.
But on the other hand, I remember that when I suggested implementing something like that several years ago for CriticalSection, you dismissed the idea with valid arguments (can’t remember now), probably linked to the fact that one could write code that waited for the lock without actually locking, which seemed a bad idea.
EDIT: found it, 8 years have passed, maybe something has changed in the mean time:
FinalCut and WaveLab would probably be the two DAWs for which the isRealtimeFlagReliable() should return false, and hence all the assertions regarding isRealtimeThread() should take that into account, probably passing without being triggered.
@jules, are there news about this?
I’m in a situation where it would be really nice to have the possibility to scatter around some assertions, to find where non-realtime-safe methods are being called from the realtime thread.
No, hadn’t got around to this yet. If you need a quick solution for adding your own asserts, it’s actually something you could easily do yourself in a couple of lines of code with a thread-local variable.
As a follow up on my original issue—my user who had an issue with Logic is now resolved. The fix I used (outlined above) did the trick. The work-around involved a HighResolutionTimer and its callback. The key being that the automation communication is handled on the timer thread.
In hindsight, it is a better way to do it. As usual, I learned something from this forum!
And, going forward, it would have been nice to have the asserts to warn of issues on the audio thread. That is a win for everybody.