# Multithreaded audio processor graph

**URL:** <https://forum.juce.com/t/multithreaded-audio-processor-graph/13154>\
**Category:** General JUCE discussion\
**Created:** [July 10, 2014, 1:13pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154 "2014-07-10T13:13:07Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![dinaiz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dinaiz/32/182_2.png) [@dinaiz](https://forum.juce.com/u/dinaiz)\
**Post date:** [July 10, 2014, 1:13pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/1 "2014-07-10T13:13:07Z")

</div>

A multithreaded audio processor graph : do we have a chance to see that one day ? :)

&nbsp;

---

<div class="post-metadata">

**Author:** ![nikolaiaudios](https://avatars.discourse-cdn.com/v4/letter/n/77aa72/32.png) [@nikolaiaudios](https://forum.juce.com/u/nikolaiaudios)\
**Post date:** [July 10, 2014, 2:45pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/2 "2014-07-10T14:45:04Z")

</div>

I have used this:

https://github.com/jchkn/ckjucetools/tree/master/AudioProcessorGraphMultiThreaded

And modified it a bit to support midi and my specific needs.

There are other post on the forum on the same topic

---

<div class="post-metadata">

**Author:** ![dinaiz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dinaiz/32/182_2.png) [@dinaiz](https://forum.juce.com/u/dinaiz)\
**Post date:** [July 10, 2014, 2:47pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/3 "2014-07-10T14:47:14Z")

</div>

Is it just a matter of replacing Juce's AudioProcessorGraph by your version ? In that case I'd be interested ...

---

<div class="post-metadata">

**Author:** ![nikolaiaudios](https://avatars.discourse-cdn.com/v4/letter/n/77aa72/32.png) [@nikolaiaudios](https://forum.juce.com/u/nikolaiaudios)\
**Post date:** [July 10, 2014, 7:35pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/4 "2014-07-10T19:35:44Z")

</div>

&nbsp;

The link is not to my code, but yes, it can replace the standard graph 1-1

---

<div class="post-metadata">

**Author:** ![railjonrogut](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/railjonrogut/32/505_2.png) [@railjonrogut](https://forum.juce.com/u/railjonrogut)\
**Post date:** [July 11, 2014, 12:09am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/5 "2014-07-11T00:09:59Z")

</div>

Can you share what you did to support MIDI?

Perhaps we can combine this with Graeme’s changes which are working great (see thread: [http://www.juce.com/forum/topic/optimisations-renderingopssequencecalculator](http://www.juce.com/forum/topic/optimisations-renderingopssequencecalculator))

Cheers,

Rail

---

<div class="post-metadata">

**Author:** ![chkn](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/chkn/32/3862_2.png) [@chkn](https://forum.juce.com/u/chkn)\
**Post date:** [July 11, 2014, 8:54am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/6 "2014-07-11T08:54:43Z")

</div>

well my modified version of the audioprocessorgraph was a proof-of-concept, and i'm happy to see that someone did a full working version of it. Would happy to see the code ;)

I'm came to the conclusion the current preordering algorithm makes no sense in a multithread context ( i wrote something as explanation &nbsp;here&nbsp;http://www.juce.com/forum/topic/multithreaded-audioprocessorgraph-source-code , which does not mean that any pre-sorting is needless or can be used to optimize the algorithm&nbsp;&nbsp;)

&nbsp;

---

<div class="post-metadata">

**Author:** ![nikolaiaudios](https://avatars.discourse-cdn.com/v4/letter/n/77aa72/32.png) [@nikolaiaudios](https://forum.juce.com/u/nikolaiaudios)\
**Post date:** [July 11, 2014, 11:40am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/7 "2014-07-11T11:40:15Z")

</div>

I´ll share my version when I get my head above water here.

As I recall the midi part was pretty easy to do.

I also modded it a bit so that it does processes nodes that are not patched to output. (For example a node that only has an input)

---

<div class="post-metadata">

**Author:** ![dinaiz](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dinaiz/32/182_2.png) [@dinaiz](https://forum.juce.com/u/dinaiz)\
**Post date:** [July 13, 2014, 5:14pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/8 "2014-07-13T17:14:27Z")

</div>

Great job here guys ! :D&nbsp;Can't wait to see the code !!&nbsp;I hope Jules will consider integrating&nbsp;it to Juce !

---

<div class="post-metadata">

**Author:** ![mxf](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@mxf](https://forum.juce.com/u/mxf)\
**Post date:** [December 19, 2014, 5:41pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/9 "2014-12-19T17:41:00Z")

</div>

​Hi chkn,

​i read your code and found it really smart, for 2 reasons :

1. it manages&nbsp;obviously the multithreading, as the title said, (and that is nice !)

​  
and 2. the repetitive way the graph is traversed with your waiting flags system enables (with a little work) to update connections or nodes without recalculating the all graph with buildRenderingSequence(), simply locally, parents to children, without even stoping threads or locking anything... which is a more dynamic AudioProcessorGraph than the orginal... !

​i'll have to work a little bit on it but at the moment it looks to work well, and the midi is a simple corollary of the audio buffer, it works the same...

Well thanks! i'll share this​ soon.

​

​

​

---

<div class="post-metadata">

**Author:** ![tayholliday](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/tayholliday/32/589_2.png) [@tayholliday](https://forum.juce.com/u/tayholliday)\
**Post date:** [December 20, 2014, 4:12am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/10 "2014-12-20T04:12:22Z")

</div>

Interesting stuff. I see the use of ScopedTryLock within&nbsp;AudioProcessorGraphMultiThreaded::Node::process. Isn't using mutexes in a real time thread a no-no?

See&nbsp;http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing

---

<div class="post-metadata">

**Author:** ![tayholliday](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/tayholliday/32/589_2.png) [@tayholliday](https://forum.juce.com/u/tayholliday)\
**Post date:** [December 20, 2014, 4:55am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/11 "2014-12-20T04:55:00Z")

</div>

An approach that avoids the locks might be:

- the audio callback thread iterates over the nodes looking for ones ready for processing (using&nbsp;numberOfProcessedInputs)
- when it finds one it schedules it on a worker thread via that&nbsp;thread's lock-free queue

If you can find a lock-free wait-free queue that supports multiple consumers (I don't know of one) you could use a single FIFO, which would be better.

I suppose the disadvantage of this is that the worker threads would spin (busy-wait). I don't know&nbsp;of a way around that in the lock-free world.

---

<div class="post-metadata">

**Author:** ![chkn](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/chkn/32/3862_2.png) [@chkn](https://forum.juce.com/u/chkn)\
**Post date:** [December 20, 2014, 5:37pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/12 "2014-12-20T17:37:49Z")

</div>

cool!

---

<div class="post-metadata">

**Author:** ![chkn](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/chkn/32/3862_2.png) [@chkn](https://forum.juce.com/u/chkn)\
**Post date:** [December 20, 2014, 5:56pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/13 "2014-12-20T17:56:51Z")

</div>

\>\>I suppose the disadvantage of this is that the worker threads would spin (busy-wait).

Yes, thats the point, and if&nbsp;all cpu-kernels would spin (i think with some kind of compare-set-bit operation) it would be&nbsp;unbelievable&nbsp;inefficient.

And modern CPUs may throtteling the clock&nbsp;for energy/temperature then.

If somebody implements something cool i would be happy, but at some point there needs to be&nbsp;some-kind of&nbsp;synchronization.

&nbsp;

But from a practical point of view: All my attempts to measure problems through performance&nbsp;intrusion failed, why? Modern CPUs are just to fast.

Also it seems the &nbsp;thread- scedulers&nbsp;of modern&nbsp;OSs are highly optimized.&nbsp;

The real bottleneck were always, ram-read/write-access&nbsp;(or ram allocation, especially on windows)

&nbsp;

&nbsp;

---

<div class="post-metadata">

**Author:** ![mxf](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@mxf](https://forum.juce.com/u/mxf)\
**Post date:** [September 9, 2015, 1:16pm UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/14 "2015-09-09T13:16:00Z")

</div>

EDIT: I removed the code because I must admit that it was not fully operational at this point... (And nobody gave any advice about it!) For the Midi management in Chkn's code: 1. add the midiBuffer member in the Node class

```
ScopedPointer<MidiBuffer> midiBuffer;
```

2. Init. in the Node::prepare method:

```
midiBuffer=new MidiBuffer();
midiBuffer->clear();
```

3. add this in the Node::process method (before "processor-\>processBlock(\*buffer, \*midiBuffer);")

```
bool unwritten=true;
    int o =AudioProcessorGraphMultiThreaded::midiChannelIndex;
    for (int i=0; iinputConnection->destChannelIndex==o)
        {
            if (ri->inputConnection->sourceChannelIndex==o)
            {
                if (unwritten)
                {
                    midiBuffer->clear();
                    midiBuffer->addEvents(*ri->node->midiBuffer,0,buffer->getNumSamples(),0);
                    
                    unwritten=false;
                } else
                {
                    midiBuffer->addEvents(*ri->node->midiBuffer,0,buffer->getNumSamples(),0);
                };
            } else
            {
                DBG("Impossible Connection: Source Channel "+String(ri->inputConnection->sourceChannelIndex)+" is higher than available channels "+String(buffer->getNumChannels()));
            }
        };
    }

    if (unwritten)
    {
        midiBuffer->clear();
    };
```

---

<div class="post-metadata">

**Author:** ![rudenaggar](https://avatars.discourse-cdn.com/v4/letter/r/edb3f5/32.png) [@rudenaggar](https://forum.juce.com/u/rudenaggar)\
**Post date:** [May 27, 2016, 4:47am UTC](https://forum.juce.com/t/multithreaded-audio-processor-graph/13154/15 "2016-05-27T04:47:46Z")

</div>

More about…[Thread Locking](http://net-informations.com/faq/qk/lock.htm)

Naggar
