I selected JUCE for my application because it includes both the gui framework and the audio framework. I’m new to JUCE and relatively new to C++, but I have extensive background in other frameworks.
I’m currently stuck on synchronizing data model changes with the gui components. My model is generic C++ (No JUCE because other applications will be using it). But I would like to be able to propagate changes in the model data to all of the relevant components.
I’m thinking of a solution where I would wrap (by inheritance) each of my model classes in a JUCE-capable class that would handle broadcasters that my gui components could listen to.
Question 1: What JUCE class would be appropriate to use as my wrapper? This would not be a displayed component, but would be a container that would add broadcaster capabilities to my vanilla model classes.
Question 2: Does anyone know of a better way to achieve this? I’m sure I’m not the first person using this kind of a scenario.
If I am understanding your question correctly, take a look at JUCE ValueTrees ( and examples). And, also, drow_ValueTreeObjectList class available on github (created by one of Tracktion/Waveform developers). The TracktionEngine SDK has a built-in version of it which you can use for inspiration. And, also, I’m sure other examples can be googled.
Thanks for your reply. Maybe I don’t have a complete grasp of the power of the value trees. It seems to me that the value tree is used to define a data model that is integrated into the Juce framework. My data model is already mature as a grouping of generic C++ classes that are not tied to JUCE. I need it to be this way so that other external applications can use it.
Can I wrap my existing data model with a value tree somehow?
This is a topic that can go very wide and very deep. You can choose to have a strict separation between model and view objects, where neither knows anything about the other, or you can mix them together and have no separation at all. What works best depends on what sort of software you’re trying to write. JUCE doesn’t really have anything like this, unless you use the ValueTree as the model object (but that doesn’t really suit all applications).
Personally, I like to start with a really dumb updateUI() function that redraws everything based on the latest model values. Usually this is sufficient. If you find this is too slow, then you can update smaller pieces of the UI at a time rather than the whole thing.
It depends, of course, on your data model. But a refactor might be worth considering, because ValueTrees have built-in benefits such as Undo/Redo for free! And if you couple that with ValueTreeObjectList your underlying data vectors are automatically managed along with their associated UI components. Or, you can simply use all of this as inspiration for additional functionality in your existing code.
I need to have a strict separation between model and view, because the model will be used for other applications. I don’t mind that much doing a mass update, except for the performance hit it will take. The final home for this app will be a raspberry pi, so efficiency is important.
You’ve persuaded me to take another look at the value tree. If I can implement it without impacting the ability to isolate the data model, I can possibly use it. How steep is the learning curve for a JUCE newbie?
Keeping things simple there is juce::ChangeBroadcaster and juce::ChangeListener. Or you can also use a juce::ListenerList to store a collection of listeners of any type you like. That may get you enough to start passing notifications around of what has changed and when?
If you want to keep a strict separation, it’s useful to know who drives the UI updates.
If the changes to the model are caused by a UI update, then the model doesn’t need to send out any notifications, since you know that once you’re done updating the model you’ll also need to redraw the UI.
If changes to the model are caused by other sources, such as the audio processing code updating metering values, then an easy solution is to run the UI updates on a timer and periodically check in to see what the model values are.
If timer-based polling isn’t a good solution for your use case, then the model can publish changes that the UI can subscribe to. There are many different approaches for this such as listeners, a FIFO, etc.
I like the ChangeBroadcaster and ChangeListener idea. That’s why I have been considering creating a class that inherits from a juce class (component?) and also from my model class. That way I can use it as is for a model, and also a broadcaster. I know a component is capable of being a broadcaster, but I don’t know if it’s overkill and there might be a lighter weight solution.
I hadn’t thought of changes coming in asynchronously from one of the external apps, but there might be a possibility of that in the future, so I need to keep that in mind to avoid a major refactor.
If you’re going for broadcasters and listeners, I would recommend that you bypass ChangeBroadcaster and ChangeListener and go straight for custom listeners and ListenerList. Custom listeners require a small amount of setup, but end up being much more flexible.ChangeBroadcaster only gives you one callback, without any arguments. I can give you a quick example of this if you like.
Regarding ValueTree, the key thing to understand is that it’s like a live XML data structure, where you can add named properties (ints, doubles, strings, bools) and also add indexed children, and then get listener callbacks when anything changes. If your existing model can trivially be modelled by XML, then refactoring your code to use ValueTree shouldn’t be too difficult, and would make your GUI integration very tidy. On the other hand, if your model is tightly coupled, or if you have complex interactions between different layers, the refactor probably wouldn’t be easy. It might still be worth it in the long run though. One of the hidden benefits of ValueTree is that, by giving you a very limited API, it forces you to keep things nice and simple.
I have managed to attach JUCE components to a non-JUCE model via a custom ‘attachment’ class.
Your attachment class doesn’t need to inherit from any JUCE class or do anything particularly complex or heavyweight.
For example, the juce::Slider has onValueChange, onDragStart, and onDragEnd, which are std::function based customisation points that you can attach your own generic lambda to. You just attach three lambdas who’s job is to update your model, and JUCE needs to know nothing about your model.
In the other direction, your model can hold a pointer to the juce::Slider and call juce::Slider::setvalue() to update the GUI.
my attachments are only about half a page of code, so don’t overcomplicate it.
At this point I am leaning toward using a ValueTree. I was skeptical about it a first but it checks all of my requirement’s boxes except one. I am doing a rewrite of my app in order to take advantage of the audio and midi capabilities of juce. My model was implemented with standard C++ classes so I could use external tools. Before I bite the bullet and refactor, I am checking all of my existing code to see how well it can integrate juce and the ValueTree. This will mean refactoring my external programs in addition to what I have done so far in my new app.
Wow. I’m impressed with this forum. Thanks to everyone who pitched in with your suggestions. I’m a solo programmer, retired, with no one to rub technical shoulders with. Since I am just learning juce, I will probably need occasional help with stuff that baffles me. Most forums I have used in the past fall far short of what I have seen just today in this one. Maybe this project is not going to be as difficult as I thought.
Note that ChangeBroadcaster does a bit more than just calling a bunch of listeners. As far as I know it doesn’t immediately call the listeners, but enqueues the call in the message queue. So if an object is modified multiple times in response to for example some UI action, you only get one callback after everything is done, instead of multiple callbacks while stuff is still worked on. That can be quite relevant for anything where multiple interdependent values are changed and you only want to really update something once all changes are made.
I think ValueTree is the right tool for the job here. The real problem begins, if different parts of that tree structure depend semantically on one another.
There is no option to summarise multiple actions into one atomic operation, aside from creating a whole sub-tree outside of the model and then adding it with all properties and children configured. That is a serious limitation that needs to be thought of in advance, when writing the UI. Since you are refactoring what is already there, I’d expect a few tuff nuts here.
There is also very little type safety and absolutely zero const correctness. Two things I love dearly about C++, that you’ll likely not be able to benefit from. There are ways to “re-add” these features at compile time, by writing wrappers around ValueTree, but it’s cumbersome IMO.
If you are interested, I’m happy to share some software architectural insights, on how I deal with these problems. There are many way to do it though.
I think you should also consider how frequent are the model updates. If they are very frequent, you can also sample the changes with a timer (e.g. realtime plot).