I'm working on the realtime part now. It's all working ok, except for one little problem:
In the class that manages the realtime processing tasks (executing the process function in every box in the project) there's this code (yes, right now I'm doing per-sample processing here):
- Code: Select all
int blockManager::process(void* output, void* input, unsigned int frames, int outs, int ins)
float* inBuffer = (float*)input;
float* outBuffer = (float*)output;
// Por ahora solo nos ocupamos del buffer de salida.
for (unsigned int i = 0; i<frames && !skipProcess; i++)
for(unsigned int t=0; t<tree.size() && !skipProcess; t++)
for(int o=0; o<outs && audioOutBlock; o++)
*(outBuffer + (frames * o) ) = (float) (audioOutBlock->getInputValue(o) );
"tree" is a vector that holds pointers to every box in the project. This vector is modified every time a box is created, deleted, connected or disconnected to another box. Obviously, right now the vector can be modified (via the GUI thread, for example by deleting a box) in the middle of the process(...) function, leading to disaster.
I was thinking about using a Fast Mutex (using the ZThread lib) to protect access to the "tree" vector. My idea is to have 2 swappable vectors, say treeA and treeB, and a pointer, say pTree. Initially pTree would point to treeA, and when the GUI tries to update the tree, it would do all of its work using the treeB vector. Then , once the tree is built, a lock is acquired and the pTree pointer is set to point to treeB. Next time the GUI wants to rebuild the tree, it works on treeA, and at the end of the operation, the lock is acquired and pTree is set to point to treeA... you get the idea.
In the process(...) function (which would now be using pTree to access the current valid vector), the lock would be acquired just at the beginning of the function, so if the GUI wants to update the tree, it has to wait (worst-case-scenario) for the block to be processed before it can set the pointer. So the process(...) functon is always working using a valid vector.
If the process(...) function tries to acquire the lock while the other function (the one that updates the tree)has it, then the maximum it would have to wait would be the time it takes to set a pointer, so I guess the possibility of having dropouts would be very very low, right?
Would having a lock aquired per buffer mean much overhead?
I'd like to know your opinions and/or ideas on this subject.