# Backend Audio Fundamentals

**URL:** <https://forum.juce.com/t/backend-audio-fundamentals/64003>\
**Category:** Getting Started\
**Created:** [October 30, 2024, 4:12am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003 "2024-10-30T04:12:48Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [October 30, 2024, 4:12am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/1 "2024-10-30T04:12:48Z")

</div>

Hi… standard disclaimer I’m a beginner to software dev as a whole (~3 months). I am trying to understand juce fundamentally, the ‘core anatomy’ of juce’s audio structure and what the most minimal ‘audio system’ setup would be. Not accounting for gui. I want to use juce as the audio-only ‘sector’ for a standalone application that will use QML for gui. I’ve had my head buried (learning CMake, build process, cpp, ect… before I even reached this point) and my thoughts aren’t completely consolidated, but I will try and make this coherent. I will denote questions _like this_ as I go.

In the attached repo, there is the most simple juce audio program. About this program :

```
- There is no gui.
- It plays noise.
- no JUCEApplicationBase is created.
- no JUCE_START_APPLICATION macro is used, but its own main().
- it uses C++20 modules, and builds/runs without any assertions.

```

After some study, it seems the most basic audio structure in a nutshell is :  
1. AudioDeviceManager to find/open/start your hardware audio unit. _Is AudioDeviceManager the link from your program to your systems audio driver that is running on your OS, outside the program?_  
2. AudioSourcePlayer that is input to the AudioDeviceManager.addAudioCallback(), added to the AudioDeviceManager internal `juce_AudioDeviceManager.h - 511: Array<AudioIODeviceCallback*> callbacks;`.  
3. AudioSource contains the actual signals, it is input to the AudioSourcePlayer.setSource().

If you set this up and sleep your main thread so it doesn’t exit, the noise will play. But, juce assertions happen. There are two ‘sets’ :

1. JUCE Assertion failure in juce\_AsyncUpdater.cpp:78  
JUCE Assertion failure in juce\_AsyncUpdater.cpp:78  
JUCE Assertion failure in juce\_MidiDeviceListConnectionBroadcaster.cpp:48  
JUCE Assertion failure in juce\_AsyncUpdater.cpp:78

These are triggered by the AudioDeviceManager, when you create a instance of it - so they are triggered somewhere in the chain of events starting from it’s constructor.  
These assertions test if a MessageManager exists. So, one must exist before AudioDeviceManager is created. In AudioDeviceManager.ixx, you see ‘Messenger’ is created - and these assertions went away.

1. \*\*\* Leaked objects detected: 1 instance(s) of class ALSADevice  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 1 instance(s) of class ALSAThread  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 1 instance(s) of class Thread  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 2 instance(s) of class WaitableEvent  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 1 instance(s) of class ALSAAudioIODeviceType  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 6 instance(s) of class StringArray  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104  
\*\*\* Leaked objects detected: 1 instance(s) of class MessageManager  
JUCE Assertion failure in juce\_LeakedObjectDetector.h:104

These happen between the sleep timer on the main thread expiring, and on the programs way to exit. _A ‘leak’ is a object you created on the heap and is allocated in memory, but your program has lost all track of it. It cannot use it nor know it exists, and will forever ‘float in memory’ uselessly until the program exits, right?_

On a tip from jules here [https://forum.juce.com/t/initialize-juce-gui-and-startup-event-loop/24028](https://forum.juce.com/t/initialize-juce-gui-and-startup-event-loop/24028), I found the main() that is run from JUCE\_START\_APPLICATION macro. You can find it in `juce_ApplicationBase.cpp - line 263`.  
In it you find this : `MessageManager::getInstance()->runDispatchLoop();`. This is the ‘main/ui event loop’ for out-of-the-box juce applications, that runs forever until you call MessageManager.stopDispatchLoop().

So, instead of sleeping the main thread, call Messenger-\>runDispatchLoop(). And, the leak assertions go away - but because I’m terminating in my IDE, and stopDispatchLoop is never called… _Is the MessageManager responsible for managing the life of the objects listed above, created by the AudioDeviceManager? If you changed your audio playback device like you would in a DAW, those objects created by the AudioDeviceManager wouldn’t be destroyed?_

Now we are at the state of the example repo. From here, you can run the program and play noise, no assertions along the way. You have to kill your program manually in your IDE.

But, if you want to use QML for your ‘main/ui thread’… obviously you can’t run two infinite loops in the same thread…so uhh…I’m just going to rattle off a bunch of questions if thats alright…

```
1. *What exactly do the MessageManager and AudioDeviceManager communicate? What is there relationship?. I know it's possible to play audio without the MessageManager.*
2. *Is the MessageManager like the bridge between your GUI and the 'audio sector'?.*
3. *In a normal juce application, does the AudioDeviceManager run on the same thread as MessageManager?*
4. *What exactly runs on this 'dedicated high priority audio thread' I hear about - just the processBlock()s of AudioSources?*
5. *Could you run MessageManager on it's own thread, and QML event loop on its own thread?*
6. *Could you communicate to your 'audio sector' (AudioDeviceManager, ect..) from QML, through the 'Messenger Thread'?*
7. *Is the MessageManager even critial for audio-only juce subsystem? Those assertions only pertain to a normal juce application setup?*
8. *If I use the MessageManager, I could re-implement whats needed in QML- essentially integrate it? Which would solve double event loop problem*

```

I appreciate any input you have - whether to the questions or any thoughts in general, any related info is good…

[Most Minimal Backend Audio Setup](https://github.com/jaxrowe/juce-qt-practice/tree/main/Tests/Audio/ConsoleNoise)

---

<div class="post-metadata">

**Author:** ![silentwind](https://avatars.discourse-cdn.com/v4/letter/s/ecae2f/32.png) [@silentwind](https://forum.juce.com/u/silentwind)\
**Post date:** [October 30, 2024, 11:15am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/2 "2024-10-30T11:15:14Z")

</div>

too busy to help now, in mean time we suggest & encourage you use GTK+ GUI SDK in addition to JUCE, learn & become familiar with both to broaden your development scope & help improve by reporting bugs etc to teams worldwide involved developing GTK & JUCE etc

---

<div class="post-metadata">

**Author:** ![silentwind](https://avatars.discourse-cdn.com/v4/letter/s/ecae2f/32.png) [@silentwind](https://forum.juce.com/u/silentwind)\
**Post date:** [October 30, 2024, 11:17am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/3 "2024-10-30T11:17:10Z")

</div>

[https://www.gtk.org/](https://www.gtk.org/)

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [October 30, 2024, 12:19pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/4 "2024-10-30T12:19:39Z")

</div>

thanks, taking a look

---

<div class="post-metadata">

**Author:** ![xenakios](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/xenakios/32/4047_2.png) [@xenakios](https://forum.juce.com/u/xenakios)\
**Post date:** [October 30, 2024, 2:17pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/5 "2024-10-30T14:17:03Z")

</div>

I am not sure how the suggestion to look into GTK would be helpful here for the original poster’s problem? The original poster already mentioned the intention is to use Qt/Qml for the GUI.

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [October 30, 2024, 3:08pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/6 "2024-10-30T15:08:29Z")

</div>

lol your right but I did say ‘any related info is good’ so thats enough to make it valid I suppose x). Surprised I haven’t heard of GTK actually, but QML is too pretty to give up, and I know people have gotten it to work. I noticed he was the one in the forum link from 7 years ago asking about using your own event loop, looks like he’s been down this road so your welcome to the party 🙂

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [October 30, 2024, 4:19pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/7 "2024-10-30T16:19:05Z")

</div>

When you get assert failures, the first thing to check is, what actually failed. Look the AsyncUpdater:

> <https://github.com/juce-framework/JUCE/blob/master/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp#L78>

Since you didn’t spin up a juce application, this message manager is missing.

There is a simple object that manages all initialisations for you, called [ScopedJuceInitialiser\_\_GUI](https://docs.juce.com/master/classScopedJuceInitialiser__GUI.html#details)

Just create one in yout QApplication or where it fits the QML (it’s been a while that I used QML). It just needs to exist somewhere so it is deleted at the end of the program. At the start of your `int main()` is a good place too.

If you are lucky, the existence of the initialiser might solve your leaks too, because without some automatic cleanup will also not happen.  
But they could still be genuine leaks too which need separate addressing.

---

<div class="post-metadata">

**Author:** ![xenakios](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/xenakios/32/4047_2.png) [@xenakios](https://forum.juce.com/u/xenakios)\
**Post date:** [October 30, 2024, 4:40pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/8 "2024-10-30T16:40:07Z")

</div>

> [@jaxrowe](#):
>
> `it uses C++20 modules`

Why that requirement? C++ modules are new and unproven technology and you will likely encounter all kinds of extraneous issues that few people will be able to help you with. (I for example didn’t completely understand what was going on in your source code repo you linked to.)

---

<div class="post-metadata">

**Author:** ![xenakios](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/xenakios/32/4047_2.png) [@xenakios](https://forum.juce.com/u/xenakios)\
**Post date:** [October 30, 2024, 6:41pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/9 "2024-10-30T18:41:39Z")

</div>

I didn’t want to start messing around with Qt/Qml or C++ modules, but here’s a simple example I wrote that uses Juce for the audio and the Choc library for the event loop/GUI :

> **[GitHub - Xenakios/juceaudio\_chocgui](https://github.com/Xenakios/juceaudio_chocgui)**
>
> Contribute to Xenakios/juceaudio\_chocgui development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![ibisum](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/ibisum/32/21288_2.png) [@ibisum](https://forum.juce.com/u/ibisum)\
**Post date:** [October 31, 2024, 10:25am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/10 "2024-10-31T10:25:27Z")

</div>

IMHO, literally every one of these questions would best be answered by doing the JUCE tutorials, which educate the new JUCE developer on its architecture and the reasoning behind design decisions, both as an application and a plugin framework. You can write a JUCE application, but JUCE plugins are often the primary product, so it’s valuable for newcomers to understand the `JUCEApplication` class in addition to plugin heuristics.

[https://juce.com/learn/tutorials/](https://juce.com/learn/tutorials/)

* * *

_1. What exactly do the MessageManager and AudioDeviceManager communicate? What is their relationship? I know it’s possible to play audio without the MessageManager._

The `MessageManager` primarily manages JUCE’s GUI thread and message dispatching, while `AudioDeviceManager` handles audio device selection and callbacks. They don’t communicate directly but operate independently on separate threads, ensuring real-time performance and avoiding conflicts.

See the notes at:  
JUCE/modules/juce\_audio\_processors/processors/Juce\_AudioProcessor.h

* * *

_2. Is the MessageManager like the bridge between your GUI and the ‘audio sector’?_

Instead of thinking in terms of “sectors,” consider the core component of each module as its own thread. The GUI thread, managed by `MessageManager`, and the high-priority audio thread are distinct and should remain separate to avoid performance issues. When interaction is needed, JUCE provides mechanisms like `AsyncUpdater` to safely communicate between these threads without compromising real-time audio.

* * *

_3. In a normal JUCE application, does the AudioDeviceManager run on the same thread as MessageManager?_

No, `AudioDeviceManager` coordinates with `AudioIODevice` to manage audio processing on the audio thread, separate from the GUI thread, ensuring device management doesn’t interfere with GUI performance.

* * *

_4. What exactly runs on this ‘dedicated high-priority audio thread’ I hear about - just the processBlock()s of AudioSources?_

Yes, the high-priority audio thread runs `processBlock()`, handling the audio resources of your application or plugin as efficiently as possible. In plugin contexts, it also manages other essential real-time tasks like `AudioProcessor`callbacks.

[https://docs.juce.com/master/tutorial\_playing\_sound\_files.html](https://docs.juce.com/master/tutorial_playing_sound_files.html)

* * *

_5. Could you run MessageManager on its own thread, and QML event loop on its own thread?_

Direct modification of `MessageManager` for custom event processing isn’t typical in JUCE. For QML integration, it’s better to create a bridge that aligns JUCE and QML event loops without altering `MessageManager`.

* * *

_6. Could you communicate with your ‘audio sector’ (AudioDeviceManager, etc.) from QML through the ‘Messenger Thread’?_

In an audio-only context, `MessageManager` isn’t critical as it primarily manages the GUI thread, not the audio subsystem. JUCE’s audio engine can operate without `MessageManager` if there’s no GUI.

* * *

_7. Is the MessageManager even critical for the audio-only JUCE subsystem? Does this apply only to normal JUCE application setups?_

Correct, `MessageManager` isn’t essential for audio-only contexts since it primarily handles GUI threads. The audio subsystem in JUCE can operate independently.

* * *

_8. If I use the MessageManager, could I re-implement what’s needed in QML and essentially integrate it to solve the double event loop problem?_

Integrating QML with JUCE’s threading and messaging system typically requires a separate thread or synchronization method rather than direct integration via `MessageManager`. Generally, QML’s event loop operates independently with defined synchronization points for necessary communication.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [October 31, 2024, 10:38am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/11 "2024-10-31T10:38:03Z")

</div>

First of all, the MessageManager is not a thread (with the exception of linux). Instead it hooks into the OS messaging system, e.g. on windows it receives and sends the WM\_XXX messages.  
QT does the same, so there is no synchronisation necessary. The message queue is the synchronisation.

In addition there is the audio thread, which is the audio driver abstracted away behind an juce::AudioIODevice. In a plugin it is the host calling processBlock of the juce::AudioProcessor. The audio thread calls ONLY the processBlock or in an app the AudioIODeviceCallback. From there it can call all kinds of things, it could be an AudioSourcePlayer, an AudioProcessorPlayer or a bespoke AudioIODeviceCallback.

---

<div class="post-metadata">

**Author:** ![ibisum](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/ibisum/32/21288_2.png) [@ibisum](https://forum.juce.com/u/ibisum)\
**Post date:** [October 31, 2024, 10:42am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/12 "2024-10-31T10:42:12Z")

</div>

> [@daniel](#):
>
> First of all, the MessageManager is not a thread

Partially ‘true’, except it runs on the “main thread”, as all applications have at least one thread.

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [October 31, 2024, 10:52pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/13 "2024-10-31T22:52:43Z")

</div>

just the kind of help I was looking for, thanks everyone! Alot to chew on, let me go through in order here…_hours later_ ok this is going to take some time to digest, so I’m just posting this to say thanks, and I will follow up when the dust has settled a bit.

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [November 2, 2024, 7:36am UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/14 "2024-11-02T07:36:00Z")

</div>

Okay! I had a think about things. In order of the replys…

> **When you get assert failures, the first thing to check is, what actually failed. Look the AsyncUpdater:**

I did find this when I was debugging, which led me to the MessageManager for the first time. At first glance, it just forwarded to’MessageManager::getInstance();', which I just directly called in my first project.

After taking another look after you brought it up I see it’s doing more. Especially the call to `shutdownJuce_GUI()`, which is in the `ScopedJuceInitialiser_GUI` destructor. I learned when main() reaches the end of execuction, objects created in main() (that are created with ‘automatic storage duration’) will have there destructor called before the program completely terminates.

So `ScopedJuceInitialiser_GUI` in your main would call `shutdownJUCE_GUI` when main() ends. As you said ‘If you are lucky, the existence of the initialiser might solve your leaks too’. Perhaps `shutdownJUCE_GUI()` deallocates juce objects (like `Audio*` related objects, the ones that were leaking) gracefully? Will expand on `shutdownJuce_GUI()` in the codebase later.

Meanwhile I mapped out `initialiseJuce_GUI()` for the record/any curious lurkers:

 ![ScopedJuceInitialiser_GUI](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/b/a/bafb11b5e03f5b32e7ab142381c9c290ead2470d.png)

> **Why that requirement? C++ modules are new and unproven technology and you will likely encounter all kinds of extraneous issues that few people will be able to help you with. (I for example didn’t completely understand what was going on in your source code repo you linked to.)**

I just heard it was the new way forward. That new codebases should adopt it, and old ones should consider migrating (its not going well [https://arewemodulesyet.org/](https://arewemodulesyet.org/)). Not a requirement here, cpp modules/qml is only a side quest, this is about juce architecture!

I don’t know how familiar you are with modules and I don’t want to go on a long tangent, but I will say this for anyone interested : One benefit of cpp modules is build time gains.

If you declare a class in the public fragment (like you would in a header) and your implementations in the private fragment and build your project. Then change a implementation and build again - only that module gets re-compiled, not everything that imports it.

Modules spit out a preliminary ‘interface file’ alongside the usual object file, into your build output tree (on clang its .pcm I think). They contain declarations of symbols that were marked with export (or inside a parent export{} braces) from the public fragment, that is - everything you can import elsewhere.

During compilation, anything that imports a module will find the interface file, and create ‘Stubs’ of the symbols in its object file. During linking, stubs are replaced with implementations from that modules object file. So if you change a module class method after initial build - things that import it never knew, and doesnt trigger recompilation. It only sees the public fragment via the interface file during compilation, and updates during linking. I like the design more then header/source personally. C++ trying to be more pythonic lol. Anyways!

> **here’s a simple example I wrote that uses Juce for the audio and the Choc library for the event loop/GUI :**

the MyAudioCallback is very interesting, it seems you bypassed the need for (or reimplemented) AudioSourcePlayer/AudioSource. Looks like your combining them, alongside AsyncUpdater, which I have been wondering about. Its a bit over my head at first glance, but I’m going to mark this and come back to it, I think im missing some fundamentals at the moment. And I see your using `ScopedJuceInitialiser_GUI`, not calling `MessageManager::getInstance()` directly, as dan also hinted to. Thanks!

> **literally every one of these questions would best be answered by doing the JUCE tutorials**

hehe, I have gone through a bunch of them (they got me this far), but many are left. Maybe I jumped the gun on this post a bit. But if I didn’t, we wouldn’t have this nice post from you 😛 will definetly be finishing those up tho.

> **The MessageManager primarily manages JUCE’s GUI thread and message dispatching**

Noted! thanks. When you look at the main() from `JUCEApplicationBase`, it creates the juce app (and thus the interface) and the `MessageManager` there. So just getting it locked the ‘GUI Thread’ must be the thread main() runs on, acoording to normal juce convention.

> **AudioDeviceManager handles audio device selection and callbacks**

thanks for confirming, I had dug into `AudioDeviceManager` a bit from tangets off tutorials, and came to some understanding of that.

Just for the record and if anyone wants to double check me - when you call `AudioDeviceManager.initialise()`. Basically it will find a subclass of `AudioIODevice` that matches your system, on my linux box its `class ALSAAudioIODevice final : public AudioIODevice`. cross platform juce in action!

It will create a instance of that class, and assign it to this internal pointer in `AudioDeviceManager`, `510: std::unique_ptr<AudioIODevice> currentAudioDevice;`.

Then it calls `currentAudioDevice->open()`, and then `currentAudioDevice->start()`. You see in `currentAudioDevice->start (callbackHandler.get());`, it passes the `AudioDeviceManagers` nested `546:std::unique_ptr<CallbackHandler> callbackHandler;` into the function.

The `CallBackHandler` was first created, when you created `AudioDeviceManager` - thats all it’s constructor does :

```cpp
AudioDeviceManager::AudioDeviceManager()
{
    callbackHandler.reset (new CallbackHandler (*this));
}

```

What is confusing is how `AudioDeviceManager` holds a `CallBackHandler`, and the `CallBackHandler` holds `owner`, which is the `AudioDeviceManager` LOL. Typical confusing C++ design patterns.

And when you call `currentAudioDevice->start()`, It passes in the `CallBackHandler`. Inside, is passes itself (the `AudioIODevice` subclass) into a method of the `CallBackHandler`. See what I mean? its almost like a ‘recursive double loop’, hard to grasp. A class method takes in a input, then calls a method of the input and plugs itself into that. /psyduck.gif.

Ultimately, `AudioDeviceManager.initialise()` chain of events seems (?) to end at calling `callbacks.audioDeviceAboutToStart()`. `callbacks` is a array of `AudioIODeviceCallBack` objects, nested in the `AudioDeviceManager`. You added to the array with `AudioDeviceManager.addAudioCallback()`. Note `AudioSourcePlayer` inherits from `AudioIODeviceCallback`, it is inside the `callbacks`.

I tried to map it out here. Probably missed a bunch of stuff, you may need to blow up the image on desktop :

 ![Initialise()](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/4/8/48cbfb93814adfd2c5712b4424d220f798dc59e4.png)

With all that aside, the goal of the `AudioDeviceManager` (or at least one of the primary ones), is to fetch your samples, and forward them to the audio driver on your OS, right?

Typically `AudioSource` holds the samples. with `AudioSourcePlayer.setSource(AudioSource)`, and then `AudioDeviceManager.addAudioCallback(AudioSourcePlayer)`, I see the path from your samples to the `AudioDeviceManager`.

But what method is called on `AudioDeviceManager` for it to return samples (or ‘trigger the callbacks’), and what calls it? I tried digging in the codebase and maybe found the answer to ‘what method’ : `AudioDeviceManager.audioDeviceIOCallbackInt()`. I have a diagram to explain…

 ![CallbackInt](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/8/9/89baf2a3eac129c816e2cfda2d7068916534ea23.png)

So I see the path in the code for your `AudioDeviceManager` to return the samples - leaving

**Question 1 : What calls AudioDeviceManager.audioDeviceIOCallbackInt and how does it call it?**.

man this stuff is super complicated… You will never grasp it the first time. For now I am going to leave the pieces on the ground and walk away like a coward…

> **Instead of thinking in terms of “sectors,” consider the core component of each module as its own thread.**

Ok, got it. That makes some sense because `MessageManager` is in juce\_events, and `AudioDeviceManager` is in juce\_audio\_devices. Since we know juce modules are kind of self contained (right?) You shouldn’t think there is a strict dependancy between them. As you said the audio subsystem can work without the messaging system.

> **When interaction is needed, JUCE provides mechanisms like AsyncUpdater to safely communicate between these threads without compromising real-time audio.**

Ok good to have a high level point of AsyncUpdater - it handles communication between threads. It was a mystery. I will probably learn more in one of the juce tutorials.

> **Yes, the high-priority audio thread runs processBlock(), handling the audio resources of your application or plugin as efficiently as possible. In plugin contexts, it also manages other essential real-time tasks like AudioProcessorcallbacks.**

Copy! hadn’t got to that tutorial yet my bad.

> **Direct modification of MessageManager for custom event processing isn’t typical in JUCE. For QML integration, it’s better to create a bridge that aligns JUCE and QML event loops without altering MessageManager.**

and

> **Integrating QML with JUCE’s threading and messaging system typically requires a separate thread or synchronization method rather than direct integration via MessageManager.**

Roger that… try to be as ‘hands off’ when screwing with juce, and let it do it’s thing. Try to make clean, seperate threads that link to juce as it is, instead of trying to weave crazy integrations into the existing juce classes. Actually I tried a project where I subclassed `juce::Thread` and created `MessageManager` in it, and called `runDispatchLoop()` inside the `juce::Thread.run()`. No idea what I was doing, but it become clear I totally broke `juce::Thread`, because it’s designed to check `threadShouldExit()` in a while loop, and all the other thread methods work with it. So yea, i see what your saying…

–

Okay! checkpoint. I think I got a grasp of everything above to some degree. Just the question about what calls `AudioDeviceManager.audioDeviceIOCallbackInt()`, Not important right now…

Just to clarify two things before a conclusion :

> First of all, the MessageManager is not a thread

Right, it is a object. A thread and a object are totally different concepts. And even if a object was designed to have ‘stuff’ that runs on a different thread, just creating that object doesn’t mean the ‘stuff’ will start running on that thread it was instanced on, or any other. That’s how `juce::Thread` works right. What is inside `juce::Thread.run()`, is what gets executed on a different thread. and you have to call `start()` to trigger `run()`. I think I saw the AudioSampleBuffer (Advanced) tutorial goes over `juce::Thread`. I’ll get to it…

> except it runs on the “main thread”

So I confirmed this by looking at the usual juce main(), here again :

```cpp
int JUCEApplicationBase::main()
{
    ScopedJuceInitialiser_GUI libraryInitialiser;
    jassert (createInstance != nullptr);

    const std::unique_ptr<JUCEApplicationBase> app (createInstance());
    jassert (app != nullptr);

    if (! app->initialiseApp())
        return app->shutdownApp();

    JUCE_TRY
    {
        // loop until a quit message is received..
        MessageManager::getInstance()->runDispatchLoop();
    }
    JUCE_CATCH_EXCEPTION

    return app->shutdownApp();
}

```

and when you expand `runDispatchLoop` :

````cpp
```cpp
void MessageManager::runDispatchLoop()
{
    jassert (isThisTheMessageThread()); // must only be called by the message thread

    while (quitMessageReceived.get() == 0)
    {
        JUCE_TRY
        {
            if (! detail::dispatchNextMessageOnSystemQueue (false))
                Thread::sleep (1);
        }
        JUCE_CATCH_EXCEPTION
    }
}

````

**// must only be called by the message thead** ← note this. and, in the MessageManager constructor :

```cpp
MessageManager::MessageManager() noexcept
  : messageThreadId (Thread::getCurrentThreadId())

```

sets `messageThreadId` to the current thread (we instanced it in main via `ScopedJuceInitialiser_GUI libraryInitialiser`) and :

```cpp
bool MessageManager::isThisTheMessageThread() const noexcept
{
    const std::lock_guard<std::mutex> lock { messageThreadIdMutex };

    return Thread::getCurrentThreadId() == messageThreadId;
}

```

The point is, and what I just want to have on the record for any other beginners that find this in the future : The **GUI Thread** _is_ the **Message Thread** _is_ the **Thread main() runs on**, in a normal juce application. They are all the same.

Finally,

> JUCE’s audio engine can operate without MessageManager if there’s no GUI.

Understood, but given you want a gui, even if it is a different framework (qml), that means you should have a MessageManager. Ok got it. And as you said, if your using a different gui framework, make a seperate thread instead of trying to integrate. Right, we went over this, moving on…

**Question 2 : How does MessageManager.runDispatchLoop() fit into the picture, with a application that uses a different gui framework? And, is runDispatchLoop() critial for the MessageManager to function?**

I’m still a bit vague on what the messaging system is actually sending, I know it work with the GUI tho. The confusion comes, because `runDispatchLoop` is a blocking loop. It is the native juce event loop. Usually, it runs in main(). But we can’t run it in main(). Or else it would block the QML event loop. And, it’s best to not mix them in one. This is why I did that project to `runDispatchLoop()` in a `juce::Thread.run()`, to leave main() open for QML. But this can’t be the right way. If we don’t need `runDispatchLoop` for MessageManager to function, problem solved. Maybe the answer is found traversing `runDispatchLoop` code, maybe in tutorials. I noticed in Xenokios project, he never called `runDispatchLoop()`. Is having two event loops in one application even a thing people do?

In summary, there is really only two outstanding questions. I did a bit of a brain dump, of course you can correct anything If I’m mistaken. From here, I’m going to put a pin in this train of thought and finish all the tutorials. I’m sure they will fill in the blanks somewhat.

But first I will now go explore this place they call the ‘out-side’.

---

<div class="post-metadata">

**Author:** ![xenakios](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/xenakios/32/4047_2.png) [@xenakios](https://forum.juce.com/u/xenakios)\
**Post date:** [November 2, 2024, 3:06pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/15 "2024-11-02T15:06:17Z")

</div>

> [@jaxrowe](#):
>
> in Xenokios project, he never called `runDispatchLoop()`

I don’t, because I am using the message loop from the Choc library with `choc::messageloop::run();` The Juce MessageManager “magically” incorporates itself into that. Works that way at least on Windows, I can’t easily test at the moment if it actually would work the same on Mac and Linux, but I would expect so.

By the way, I am not sure if this is completely correct :

```auto
JUCE’s audio engine can operate without MessageManager if there’s no GUI.

```

The Juce audio classes depend on being able to do async operations in the GUI/main thread and those won’t work if the Juce MessageManager hasn’t been initialised. For example, the Mac CoreAudio and Windows WASAPI and ASIO implementations in Juce use AsyncUpdater and Timer, which need a message loop running.

However, you don’t have to actually _run_ the Juce MessageManager message loop if you already have a message loop running, like I did with Choc in my example. I’d expect it to work in a Qt app something like this :

```auto
int main(int argc, char *argv[])
{
    juce::ScopedJuceInitialiser_GUI guiInit;
    // Init the Juce audio stuff
    // ...
    QApplication a(argc, argv);
    Window w;
    w.show();
    auto result = a.exec();
    // shutdown the Juce audio stuff if needed
    return result;
}
```

I can’t unfortunately test if this would actually work since I don’t have Qt set up for development and I don’t want to do it just to test this. (Qt is way too bloated and complicated to set up for my taste.)

By the way, another thing you will want to watch out is using Juce classes as global variables, some of them won’t work correctly used that way because of C++ initialization/deinitialization ordering issues.

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [November 2, 2024, 3:46pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/16 "2024-11-02T15:46:42Z")

</div>

ah okay, so choc solved that problem… and as you said maybe qt does too, but not confirmed.

> By the way, another thing you will want to watch out is using Juce classes as global variables, some of them won’t work correctly used that way because of C++ initialization/deinitialization ordering issues.

Thanks, noted.

I asked a LLM 'Is it common to run two event loops in one application?" and it said this

> " Some frameworks offer a way to “pump” or “poll” their event loops manually, allowing you to integrate two loops more smoothly. For instance, Qt allows a custom event loop to integrate with its main loop by periodically calling `processEvents()` ."

If in timestamp below, they mention a polling thread for audio to gui communication, so maybe this how you would do (given you did have to use runDispatchLoop, or whatever is it you have to do to forward from audio thread). You would have to set it up to run in a std or pthread tho, as juce::Thread wasn’t designed for that.

[![](https://us1.discourse-cdn.com/flex026/uploads/juce/original/2X/5/5ecd02b6c0fdbea9a2c8fa058babfe12a51b2b62.jpeg "Making music: Architecting realtime audio development with QML | DevDes 2021") ](https://www.youtube.com/watch?v=QlirdL4JORc&t=692)

Anyways getting a bit ahead of myself. but good to look ahead a bit to know it’s possible and add belief in your purpose. It’s gonna take at least 6 months of study before I should go much further here. Might remake my first project to update some of the things I learned here, and try a CMake build (juce and qml have there own exe targets, so that will probably be tricky) but after that its pencils down and back to the basics. Thanks again everyone

---

<div class="post-metadata">

**Author:** ![benvining](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/benvining/32/9922_2.png) [@benvining](https://forum.juce.com/u/benvining)\
**Post date:** [November 2, 2024, 8:14pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/17 "2024-11-02T20:14:35Z")

</div>

> [@jaxrowe](#):
>
> If you declare a class in the public fragment (like you would in a header) and your implementations in the private fragment and build your project. Then change a implementation and build again - only that module gets re-compiled, not everything that imports it.

This is also true of the old header/cpp file idiom. If only the cpp file changes and not the header, then other TUs that only include the header don’t get recompiled.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [November 2, 2024, 9:14pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/18 "2024-11-02T21:14:26Z")

</div>

I just wanted to point you to a short thread:

> [@Integrating Tracktion Engine into another event loop](https://forum.juce.com/t/integrating-tracktion-engine-into-another-event-loop/31641/2):
>
> You shouldn’t need to run your own message loop, the Qt message loop should handle everything as long as you call initialiseJuce\_GUI() / shutdownJuce\_GUI() before / after using the engine. Think of it kinda like a plugin, the host runs the message loop and the hidden juce window gets sent the messages it needs. I haven’t tried it however, this is probably a use case we should test.

The QT events are processed in the [QEventDispatcher](https://doc.qt.io/qt-6/qabstracteventdispatcher.html#details) which is started with the QCoreApplication::exec() and ended with QCoreApplication::quit().

You cannot have two event loops, because the whole purpose is to avoid concurrency issues e.g. when manipulating windows etc. I understand you don’t manage windows from juce, but that’s what it is.

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [November 2, 2024, 9:14pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/19 "2024-11-02T21:14:36Z")

</div>

oh really? I started learning with modules from the start so not versed in header/source… this guy makes it seem like only a modules thing : [https://www.youtube.com/watch?v=VcQXn4mNttI&t=1s&ab\_channel=LearnQtGuide](https://www.youtube.com/watch?v=VcQXn4mNttI&t=1s&ab_channel=LearnQtGuide)

---

<div class="post-metadata">

**Author:** ![jaxrowe](https://avatars.discourse-cdn.com/v4/letter/j/f9ae1b/32.png) [@jaxrowe](https://forum.juce.com/u/jaxrowe)\
**Post date:** [November 2, 2024, 9:26pm UTC](https://forum.juce.com/t/backend-audio-fundamentals/64003/20 "2024-11-02T21:26:27Z")

</div>

Oh! so we can take `runDispatchLoop` out of the equation. Yea that makes it alot easier. Nice find, thanks

[Next page](https://forum.juce.com/t/backend-audio-fundamentals/64003.md?page=2)
