COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 10-26-2017, 07:56 AM   #1
Andi!
Human being with feelings
 
Andi!'s Avatar
 
Join Date: Nov 2015
Location: Germany
Posts: 82
Default Worker threads in audio process

At the moment when parameters change I do new calculations in the audio thread. This includes preparing FIR filters and so on. So far so good, but when the CPU is very busy or the calculation gets to complex and takes too long (e.g. longer than the frame count), the audio glitches and I get drop outs.

The trace looks like this. When no parameter changes there is no problem, but when calculating the FIR (which is already optimized), it takes 15ms which is much too long.

3;16:44:47.052802100;ProcessDoubleReplacing;346;nF rames:512
3;16:44:47.053882200;calcFIR;297;Begin
3;16:44:47.068597800;calcFIR;468;End
3;16:44:47.069520900;ProcessDoubleReplacing;522;nF rames:512 End
3;16:44:47.069662900;ProcessDoubleReplacing;346;nF rames:512

I think I need some kind of asynchronous worker threads here (it's not important before which call of Replacing the calcFIR finishes). I'm succesfully doing some stuff in the GUI with worker threads but I wonder if this is a good idea in the audio thread. Could calls to std::thread lead to problems, glitches and drop outs ? And how to know that it has some new calculation ready ? I assume an atomic variable would do the job.

BTW by rising the audio buffer of the driver to 1024, the glitches disappear, but of course this can't be the solution.

Last edited by Andi!; 10-26-2017 at 08:20 AM.
Andi! is offline   Reply With Quote
Old 10-26-2017, 08:50 AM   #2
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Andi! View Post
Could calls to std::thread lead to problems, glitches and drop outs ?
You definitely don't want to be creating std::thread (or any other thread wrappers that just use the underlying operating system implementation) instances in the audio thread. The runtime library or operating system might use a quick thread pool for that, but there are no guarantees at all. (Especially cross platform.)

So, you need to have your thread previously created and then continuously running and waiting for work to be passed into it. Or you could look into the platform specific concurrent/parallel task execution libraries like Apple's Grand Central Dispatch (GCD) or Microsoft's PPL. I would recommend just doing the latter, rolling even the simplest threaded task queue on your own is going to be complicated. Using Apple GCD is a bit annoying in C++ because it's a C API but with some template and other trickery it can be made easy to use in C++.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 10-26-2017 at 08:59 AM.
Xenakios is offline   Reply With Quote
Old 10-26-2017, 09:11 AM   #3
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

Or just use CreateThread() on Windows, and pthread on macOS; that is what I do for the worker thread in my version of the WDL convolution engine. But yeah, that does get complicated, because you will also need to think about events/signals, locks, thread priorities, etc.
Tale is offline   Reply With Quote
Old 10-26-2017, 09:14 AM   #4
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Tale View Post
Or just use CreateThread() on Windows, and pthread on macOS
Which is again potentially horrible, if it is done in the audio thread. (std::thread and similar are just relatively light wrappers around those low level calls.)

edit : What I gathered from the original poster was that he intended to do something like :

Code:
void processReplacing(...blah...)
{
  if (filterparameterschanged)
  {
    std::thread coeffsthread(...blahblah...);
    coeffsthread.detach();
  }
  ...audio processing...
}
No matter if std::thread or the OS thread creation functions would be used for that, not a good idea.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 10-26-2017 at 09:21 AM.
Xenakios is offline   Reply With Quote
Old 10-26-2017, 09:33 AM   #5
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

Yeah, I meant doing what you said i.e. create a thread once, and then signal it when you need it to do some work.
Tale is offline   Reply With Quote
Old 10-26-2017, 09:37 AM   #6
Andi!
Human being with feelings
 
Andi!'s Avatar
 
Join Date: Nov 2015
Location: Germany
Posts: 82
Default

Thank you! You're right, I shouldn't do that in the audio thread. A continous running (but not busy) std::thread would be great. What about a c11 condition variable? Seems to be the right thing to signal the worker thread that there is something to do. I hope that I don't need a queue. The worker thread could have the atomic state idle, calculating or finished calculation. I would test in the audio thread e.g. every x samples if I have to start a new calculation (parameters changed & state=idle) or I have to pull the results from the finished calculation. When the worker thread is calculating, nothing would happen in the audio thread and the previous calculation is still valid.
Andi! is offline   Reply With Quote
Old 10-27-2017, 08:57 AM   #7
Andi!
Human being with feelings
 
Andi!'s Avatar
 
Join Date: Nov 2015
Location: Germany
Posts: 82
Default

I got an easy worker thread working now. Well, it doesn't really work at the moment (just waits). But it syncs to the audio thread and gets a signal with the mentioned condition variable. I just use platform independent standard c11 stuff like std::thread, mutex, condition_variable, atomic & unique_lock and the trace shows me that I'm on the right way. When the plug-in is deconstructed the thread will be signaled and ended correctly. I have tested it with Reaper,Cubase,Ableton,Logic,AUVal,ProTools & Studio One and it seems to work great on Win & Mac even with multiple instances.
Now I'm thinking about what the safest method is, to access data of the audio thread (some arrays) in the worker thread. Locking the IPlug mutex for a very short time or using shared pointers/atomic data come to mind...
Andi! is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:19 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.