Juce and file saving


I’m a novice programmer, trying to build a piece of sequencing software and learning C++ and Juce as I go. Right now, I am trying to build a rudimentary system which will read and write the variables within a custom class to a file (hopefully one day this will become the saving and loading system for the program). I have a sense of how to do this using data streams in the STL library. On the other hand, I’m almost certainly going to do a bad job of it, and this is a problem that must have been solved thousands of times before.

Does Juce contain any tools which automate the file saving process? How is the problem usually solved? I’m not so much asking how exactly to do it, and more asking where I should invest time: into learning Juce modules or C++ and STL basics.

Sorry if this topic turns out to be less about Juce and more about C++.


That is a really broad question with no yes/no answer. It really depends, what you want to save or load, and what structure you read it into (this process is called serialisation, btw.). So if you want to read something and construct a JUCE object from it, it makes sense to use the juce::File and juce::FileInputStream.
For Audio there are the AudioFormat classes available, and same for ImageFileFormat.
For hierarchical data that you produce yourself, the ValueTree is a good pick, since it allows also callbacks when it is manipulated.

If however the constructed object is completely independent from juce, and there is no ready reader/parser available, it would be considered good practice to avoid additional dependencies.

But another angle to look at this is, what technology you feel most comfortable with…


Since C++ does not have reflection (the capability to know at runtime how the classes are structured, what data members they have etc), no automated solution as such is possible for arbitrary data. Raw streams are not a great solution because it becomes difficult to future proof that for extensibility. JUCE has the ValueTree class that can be helpful but still requires you to manually do the saving and loading code for your data, unless you structure your whole application to use the ValueTrees.


…which is a good idea if you want undo/redo functionality for your data model… it is very tedious and error prone to do that by hand, the UndoManager is a great extension to the ValueTree


Thanks for your responses. I am aware that my questions are broad, but the answers have already been very helpful. I’ve read up on ValueTree and it seems like it is exactly the right thing for me to be using, as it will help with file saving and so much more.

I have read through the tutorial on ValueTrees, but there are still some gaps in my understanding which are preventing me from being able to implement what I’ve learned. Am I right in saying that to utilize ValueTrees, I would start by creating my own custom class and then inheriting from the ValueTree class?


No, inheriting ValueTrees is not useful. It’s in fact marked as “final” so you couldn’t inherit anyway.

There are many ways the ValueTrees can be used, but you will probably want some “master” ValueTree instance in some suitable class that always has all the state you need.


So the ValueTree is a member of a custom class?


Well, all your classes are “custom” classes, otherwise your code wouldn’t really be doing much. And yes, the ValueTree should be a member in some suitable class. What is “suitable” depends on your code structure.



My 2 cents, especially if you’re a novice: the setup/boilerplate code to get this working seems rather complex/large. You’re maybe not having the same problems you need to solve. If you’re just writing a simple plugin that e.g. represents a simple EQ, you might not need all this and can simply store your 10-20 parameters as an array of floats and be done with it.

If you have a complex data-model, with a deeply nested hierarchy etc. then it’s definitely a good way to go.

Learn to walk before you learn how to run.


But even if the main data model is just plain variables and arrays, the ValueTrees can be used for profit during the serialization and deserialization steps…They are a very handy way to deal with data where future expansion may be needed.


Horses for courses. If we’re talking, just as an example, about four EQ bands and an input/output gain, there is little that could be extended.

I would start out with a simple float array, don’t do anything special for serialization (just store them as is) and be done with it.

Then, when creating more complex plugins, add the ValueTree stuff to it. It’s a complex beast and can overwhelm any novice (and pro) easily. Especially when adding constrainers etc. it becomes complex quick.


There’s not really anything complex about using the ValueTrees only during the serialization and deserialization steps. (Literally just using them as local variables when saving and loading the data.) However, if the whole application or plugin is designed around them, sure, it’s complete overkill for anything simple.


I should have paid more attention to the OP needs. He mentioned a sequencer (so DAW?). That is a monumental undertaking and requires complex solutions. ValueTree seems perfect for that.


@reFX and @Xenakios, your discussion reads like the one playing in my head right now. On the one hand, trying to run before you can walk is foolish. On the other hand, I’m determined to do things properly and make the most out of the existing tools and techniques (which is why I’m researching Juce).

I’m new to C++ but not to software design. I spent five years building this sequencer in PD, during which time I learned a lot of lessons about the importance of structure and long term thinking. But being a beginner, I had to scrap everything and start over on the project several times.

C++ is a lot harder than PD, but I’m still trying to make the most of the experience I have. My hope is that by investing my time into tools such as ValueTrees, it will help me write code that will hold its weight, so that I won’t have to scrap the whole thing and start again when it gets to a certain level of complexity. But maybe it’s necessary to write bad code and reinvent a thousand wheels before you can do something like this properly?

My questions are getting very broad again, but I’m writing them because your feedback has been genuinely helpful so far (and this place is a lot friendlier than stack exchange!)


OT: take that, @juce team always saying that this forum is unwelcoming for new users :grin: