How to use getXmlFromBinary


#1

Hey,
i try to build a custom preset gui page in my plugin.
My only problem is:
I don’t know how to use getXmlFromBinary corectly.

I have my Preset (which is normaly created from the getStateInformation() function in an juce::File but whats now?
i cant just parse it to xml because it’s a binary…

I tryed a little bit arround with getXmlFromBinary but i don’t know how to give him my data’s from a normal file Object.

Thank you :slight_smile:


#2

The copyXmlToBinary function takes some XML and writes it to a supplied MemoryBlock, and the getXmlFromBinary takes a void* pointer to some binary data and creates some XML. It’s not completely clear, but the best way to read the same information from a File is to first get the contents in a MemoryBlock - something along the lines of:

File f ("path/to/file");
MemoryBlock content;
f.loadFileAsData (content);
ScopedPointer<XmlElement> xml (getXmlFromBinary (content.getData(), content.getSize()));

I’ve not tested this code, so there may be an error somewhere, but the general approach will work.


#3

The main purpose of those functions was to make it easy to save XML in your plugin’s state block.

You could also use them to save/load files, but it’d be a bad way to do it IMHO. If you’re dealing with files then just read/write the XML to a file as text.

And if you really want a binary file that contains XML, then using a ValueTree would be a much better way to store your data.


#4

I didn’t want to use it, but i want that you can safe a preset over the normal DAW way and load it over my Custom PresetGUI. And i didn’t see another way to read the xml which was saved from the DAW. Or did i missed something?


#5

great, thank you i will have a look :slight_smile:


#6

I tryed this.
Still the same Problem, the xml is null after using the function.
I checked the content object, it looks perfect from the size (shows me 355kb thats exactly the same like windows says).
But i didn’t get a xml, it’s null all the time.

I tryed to load the same preset via the DAW and had a look to the size, in the setStateInformation(const void* data, int sizeInBytes) is sizeinBytes much smaller (180).

So it looks like i missing something :S any Idea?


#7

Do as Jules suggests - try saving your XML to a file as text. That way you can be absolutely sure that you actually saved what you were intending to save by looking at the file in a text editor.


#8

t0ms loader looks ok to me. I am using the same code and it works fine.
Probably an issue with the saving?


#9

I can’t, the Plugin is already out and the old presets from the users must be compatible with the new GUI…


#10

I didn’t think so but maybe you can have a look :slight_smile:

Safe:

void Processor::getStateInformation(MemoryBlock& destData)
    {	
    	XmlElement root("Root");
    	XmlElement *el;
    	int knobCount = globalSettings->GetKnobCount();
    	for (int i = 0; i < knobCount; i++)
    	{
    		std::string safeName = "Knob" + IntInString(i);
    		el = root.createNewChildElement(safeName.c_str());
    		el->addTextElement(FloatInString(poti[i]->getValue()));
    	}
    	int autoGain = 0;
    	if (globalDatabase->GetAutoGainValue())
    		autoGain = 1;
    	el = root.createNewChildElement("AutoGain");
    	el->addTextElement(IntInString(autoGain));
    	copyXmlToBinary(root, destData);
    }

Load:

void Processor::setStateInformation(const void* data, int sizeInBytes)
{	    
	withPresetLoaded = true;
	int correctPreset = 0;
	XmlElement* pRoot = getXmlFromBinary(data, sizeInBytes);
	if (pRoot != NULL)
	{
        CreateTheKnobs();
		int knobCount = globalSettings->GetKnobCount();
		std::string knobName = "";
		String value = "";
		forEachXmlChildElement((*pRoot), pChild)
		{
			if (pChild->hasTagName("AutoGain"))
			{
				String val = pChild->getAllSubText();
				if (val == "1")
					globalDatabase->SetAutoGainValue(true);
				else
					globalDatabase->SetAutoGainValue(false);
			}

			for (int i = 0; i < knobCount; i++)
			{
				knobName = "Knob" + IntInString(i); 
				if (pChild->hasTagName(knobName.c_str()))
				{
                    String valString = pChild->getAllSubText();
                    if(valString != "")
                    {
                        float val = StringInFloat(valString.toStdString());
						if (val < 0 || val > 12){
							correctPreset++;
						}
                        if(i == 2)
                        {
                            setParameter(i, val);
                        }
                        else
                        {
                            setParameter(i, val);
                        }
                        poti[i]->setValue(val);
                  
                    }
                    else
                    {
                        withPresetLoaded = false;
                    }
					break;
				}
			}
		}

		delete pRoot;
	}
	if (correctPreset != 0){
		withPresetLoaded = false;
	}
}

Load from Custom Preset GU (this is in my timerCallback):

if (globalDatabase->IsCustomPresetTriggered()) {
	File f(globalDatabase->GetCustomPreset());
	MemoryBlock content;
	f.loadFileAsData(content);
	XmlElement* pRoot = getXmlFromBinary(content.getData(), content.getSize());


	withPresetLoaded = true;
	int correctPreset = 0;
	if (pRoot != NULL)
	{
		CreateTheKnobs();
		int knobCount = globalSettings->GetKnobCount();
		std::string knobName = "";
		String value = "";
		forEachXmlChildElement((*pRoot), pChild)
		{
			if (pChild->hasTagName("AutoGain"))
			{
				String val = pChild->getAllSubText();
				if (val == "1")
					globalDatabase->SetAutoGainValue(true);
				else
					globalDatabase->SetAutoGainValue(false);
			}

			for (int i = 0; i < knobCount; i++)
			{
				knobName = "Knob" + IntInString(i);
				if (pChild->hasTagName(knobName.c_str()))
				{
					//if(EditorThere)
					//    const MessageManagerLock mloCk;
					String valString = pChild->getAllSubText();
					if (valString != "")
					{
						float val = StringInFloat(valString.toStdString());
						if (val < 0 || val > 12) {
							correctPreset++;
						}
						if (i == 2)
						{
							setParameter(i, val);
						}
						else
						{
							setParameter(i, val);
						}
						poti[i]->setValue(val);
				}
				else
					{
						withPresetLoaded = false;
					}
					break;
				}
			}
		}
		delete pRoot;
	}
	if (correctPreset != 0) {
		withPresetLoaded = false;
	}
}

#11

Without having read the entire code yet just one question: why don’t you just call setStateInformation from the timer callback once the settings file has been read into the MemoryBlock?


#12

My first idea was like jules: just load and safe an xml… and in the beginning i had no idea how to get a memoryblock… I can change the code but i didn’t think that it would be change anything. Because the code after if(pRoot != null) is exactly the same


#13

The save bit does not include the creation of the file.
Can you show that one too?


#14

Do you mean a file creation in getStateInformation ?
I didn’t do anything like that in the Preset creation. Anything else get handled by juce and the daw


#15

Then I don’t think you should make any assumptions on the contents of the file.
If you let juce and the daw handle the saving of the file then you should also let it load the file again. If that is not an option you have two choices:

  • save the file from the plugin or
  • study the host specific preset file formats and load these (which is probably a ton of work to implement)

#16

To me there is one good reason to go that route: Keeping the data format consistent allows for a leaner design. The File loader/saver routines can then be built upon the existing set/getStateInformation functions (+ normally you do not want your users to edit the settings file by hand anyway - that’s two good reasons then.)