Serialization


#1

i searched but found nothing usable.

I need to store some settings (set up in a GUI class) within the BASE filter class, for when a user opens/closes a window. This is a normal VST operation. Is there a realtivly “easy” way of serializing a Component in Juce.

Different approach, is it possible to keep the pointer to a editors component (a knob/slider) within the Filter Base class ? i mean to keep it there and just when the editor creation is requested make it visible (invisible when editor deleted).

What i’m writing is a plugin that will have multiple (dynamic) tabs, each with a set of sliders/knobs/buttons (also dynamic). I need to store them for the time Editor is closed.

Also on the subject, can VST store data in different formats (other than float) in it’s presetes/banks ? Like strings, binary etc ?


#2

You can store anything you want in the filter’s state - it’s all done in getStateInformation() and setStateInformation(), and there’s even helper methods like copyXmlToBinary() to save XML state.

There’s no automatic serialisation of components in juce, mainly because I’ve never seen any situation where it’d be particularly useful or the best way to do the job. In fact I’m not sure what sort of values you’d want it to store?

You can keep a pointer to a component in your filter class if you want to, but it’s bad UI design for a data model to know anything about the view. Maybe ask yourself why you want to store them? Usually there’s no good reason not to create them each time they’re needed, and it’s polite to free up as much memory as you can when your editor’s not there, because there may be a lot of other filters running that need the resources.


#3

The Ui pointers in the filter are a bad idea, i’m just looking for a solution that would be practical.

Anyway i have a problem cause all theese parameters, values are dynamic, based on XML files parsed by tthe plugin after it’s loaded. This brings a problem with giving information to the host

  1. when the plugin is initialy loaded it has no controllers, the controllers are created after the user has chosen a XML file

  2. this brings problems when getParameter and others are called, cause at any time the controller assignment can changed, the user can load a new file at any moment into any panel (existing/new one)

  3. preset saving (like when you do a SAVE AS in FLStudio or in any DAW), i would have to store a plugin STATE (filenames for each panel, each controller state for each modifier in each panel).


#4

That is tricky, particularly because hosts will all be different in the way they handle parameters - attempting to have dynamic parameter lists sounds like asking for trouble!


#5

yeah i know :slight_smile: but i dont see it any other way unforutnatly.

anyway, is serialazizng a Component (by a special dedicated method for each component) to a in-memory XML form and stroing that in the filter clas for later use, will be a good idea ? (this is for a situation when the GUI with all those dynamic controllers gets closed/reopened).

As for the SAVE the while plugin state on exit, this is a problem i’m gonna be facing. However someone mentioned me that some samplers like Directwave can stroe SAMPLE data in presets, if that’s possible that is see no problem in stroing XML in them. Will invastigate on that.


#6

In terms of dynamic controllers i wnet around that problem

on plugin init i tell the host that i have 512 controllers, and thean I assign new ones as they appear in the plugin from XML files. I send a parameterChanged to host, and as far as Live! goes it even refreshes this parameter’s name. I didn’t test this with others though.


#7

i think you’re looking at the whole thing backwards.

you shouldn’t have to serialise the components and their layouts/structure, because then you’re relying on the UI for your stuff. you do not need to do this, but you seem convinced that you do.

you’ll read in these files into your filter, and need to have somewhere to store the structure of whatever the data is. When you open the editor, it should create the components based on the structure you hold in the filter for the loaded XML file. This is how it should be done. When the display is closed, you don’t want to copy the layout of the components in a serialised form (especially not XML - that is going to take up a pointless amount of memory). You should have a structure in your filter (as read from the XML originally) which holds this information anyway, and have specially designed components that create whatever is necessary to display that structure. When you reopen the GUI, these components are created from your data - the user is to expect opening the GUI to take a moment’s processing, just as they are to expect that closing the GUI will release the load somewhat.

For example, say your structure had something like this…

[data]

  • knob1
  • knob2
  • [panel1]
    – thingA
    – thingB

dataComponent (data)
{
step thru data contents…
add knobs for each knob
add a panel (panel1) - panel will add any contained things to itself
etc…
}

if the elements in your structure can be repositioned, they can hold position information too so the component knows where to put them.


#8

that’s how i’ve written it up to this point (the filter holds a structure)

struct controllers
{
     int x,y,width,height,value,index,max,min;
     String name;
     String data;
}

struct controllers allControllers[512]; /* plugins limit of controllers */

and when the panel get’s created it reads through this structure, also the Filter parses the file. When something in the GUI changed it updates the filter structure also through a getFilter() function. I just though there might be a btter way too do this, but if that’s ok than i’ll keep this code.

The serialization is needed for PATCH storage i mean for holding a state in a preset/bank when a projcect with the VST is saved. Whether this should be serialization or something else i dont know, perhaps there is a better way to do this. The problem is that the controllers properties can vary and are not only floats. Also this is very complex there will be many different type of coontrollers, so i was wondering is there is a simple way to serialize this kind of data, and let the VST HOST save it with a project.


#9

sure, you should adjust your structures to have serialisation in them.

for example, give your structure a createXml() function, and use that to put all the stored values into an XML tag. You don’t need to get information from the editor - that’s just used to edit the data in your structure. The structure should be responsible for its serialisation.

The fact that the structures can hold different types of data is not really a problem; because it needs to hold different things, it obviously needs to be designed to create these things based on the user-loaded XML file

[e.g. this user file has a controller with five int values and a float value … it should therefore have a way of adding a the int values to an array for int values, and adding the float value to the array for float values… then your UI component will step thru all the arrays and create whatever’s necessary for each item. Your structure can serialise this in the same way too - create a tag to represent the structure, then step thru all the contained elements and add a child XML tag for each one - this XML structure is then returned to the host in the JAP state storing function as a binary blob]

You could even make things slightly easier (in a long-way-round way of course) by linking elements in your structure directly to the UI components. e.g. say you have some kind of data value, and it’s directly represented as a slider, when the value changes, it broadcasts a change message which only your slider picks up [because your UI classes are designed to automatically register the widgets as listeners to your data elements] - when the widget changes of course, you’ll want it to call the setParameterNotifyingHost with the parameterID of the data, if you’re planning on allowing automation recording.


#10

I think i found what i was looking for

virtual VstInt32 	getChunk (void **data, bool isPreset=false)
 	Host stores plug-in state. Returns the size in bytes of the chunk (plug-in allocates the data array).

virtual VstInt32 	setChunk (void *data, VstInt32 byteSize, bool isPreset=false)
 	Host restores plug-in state. 

this enables the plugin to store it’s presets as memory chunks, so i’ll fill those chunks with my serialized as XML data for each data structure present in the plugin. And than parse the XML state back when loading.


#11

perhaps my data classes may be of use to you.

http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=781

basically you can use it as a framework for all your data elements. By subclassing from FileDataElement, and defining it according to its rules, you can easily serialise your structure.

It may be a bit complex (definitely at first) but i use it all the time and it makes things a lot easier. For example, in the constructor of a FileDataElement, you specify a tag name, which is used for input/output of xml. the create/restore xml functions are implemented already, (Restore: checking the provided tag’s name against the specified one, Create: creating a tag for you with the correct name already so you only need to add child elements/attributes) - you just implement readDataFrom and addDataTo XmlElement functions. If your structure contains nested elements, they should know what they contain, and can simply add those elements tags during serialisation…

e.g.

class box : public FileDataElement
{
private:
   int size;
   ...
public:

   Box ()
   : FileDataElement (T("box"))
   {
   }
   ... 

   void addDataToXmlElement (XmlElement* tag)
   {
      tag->setAttribute (T("size"), size);
   }

   void readDataFromXmlElement (XmlElement* tag)
   {
      size = tag->getIntAttribute (T("size"));
   }

};

class Room : public FileDataElement
{
private:
   OwnedArray<Box> boxes;
   ...

public:

   Room ()
   :  FileDataElement (T("room"))
   {
   }

   void addDataToXmlElement (XmlElement* tag)
   {
      for (int i=0; i<boxes.size(); i++)
      {
         tag->addChildElement (boxes.getUnchecked(i)->createXml());
      }
   }

   void readDataFromXmlElement (XmlElement* tag)
   {
      XmlElement* subTag = tag->getFirstChildElement ();
      while (subTag)
      {
         if (subTag->hasTagName (T("box")))
         {
            Box* box = new Box;
            box->restoreFromXml (subTag);
            boxes.add (box);
         }
         subTag = subTag->getNextElement ();
      }
   }

};

You just define how each element can serialise itself, and then they can work together to result in a final big XML structure for you to export.

Have you looked at the example juce plugin? It shows how you can store xml in a patch. It’s right there, you don’t need to use the getChunk/setChunk functions if you’re using the juce audio plugin framework.


#12

You have those wrapped in JAP too:

[quote]void JuceFilter::getStateInformation (MemoryBlock& destData){

}

void JuceFilter::setStateInformation (const void* data, int sizeInBytes){

}[/quote]


#13

i thought that those functions were to store data in a FILE (i still think btw)
and i need to use those two methods (theyre from the VST SDK) to store this serialized data IN the host, or in it’s native whatever file format.

Cause a host has two options to save a plugins state, either to itrate thrgoug all it’s paramteters (witch is no use to me), or by reading memory chunk that the pplugin is serving it. So i guess i need to add those methods from the VST SDK, or are those two utility functions from the JuceAudioPlugin example, wrappers fro those VST SDK calls? (after a quick look at the code i don’t think so)


#14

they are wrappers. they will only write to a file if you code them to specifically write it to a file.

The memory block returned from /provided by those functions goes to / comes from the host, and is directly related to the setChunk/getChunk functions. They do exactly what you need.


#15

Yes, like haydxn says, (and like I said in my first post), those functions are there to do exactly what you’re trying to do. The JAP wrapper wouldn’t be much use if it didn’t even have a way of saving the filter state!


#16

well i misunderstood i’m sorry

back to the code, hope i finish this plug, it would make my life much easier.

thank you for all your help.


#17