When to use getStateInformation / setStateInformation

Awesome works great, thanks a bunch!

That was a nice birthday present! I was worried I was going to spent the entire day, plus the past few days, trying to figure this out. So close now to finishing my synth! Last thing this is to save and load presets!

Ok done adding all my synth parameters, along with some gui settings in the set/getStateInformation, using your above example.

Final thing is I need to store my 8 tone generator’s wavetables each of 4096 floats, as these tables in many cases would have been edited (changed) by the user. What would be the easiest way to do that, working off your above example, and yes I figure that I do not want to store these tables as XML.

You don’t have to use XML. You can always just stream the values out in order after your XML is written to the stream. That’s not as flexible as using XML, but saves a lot of overhead you don’t need. Maybe stream the size of the arrays (count, 4096 in your case) first, just in case it changes?

Thanks a lot. So simply add the following to the end of getStateInformation?

...
copyXmlToBinary (*xml, destData);

MemoryOutputStream (destData, true).writeInt (wavetableSize);

for (int module = 0; module < 8; module++)
{
    for (int i = 0; i < wavetableSize; i++)
        MemoryOutputStream (destData, true).writeFloat (wavetable[module][i]);
}

and at end of setStateInformation;

wavetableSize = MemoryInputStream (data, sizeof(int), false).
                                                              readInt ();

for (int module = 0; module < 8; module++)
{
	for (int i = 0; i < wavetableSize; i++)
		wavetable[module][i] = MemoryInputStream (data, sizeof(float), false).readFloat ();
}

Well the above ain’t it, because wavetables aren’t restored when I reopen DAW file.

In the Windows operating system, does anyone know where Reaper is storing the synth state, so I can check the file?

Don’t create the stream for every item you read/write. Create it as a local variable first, then just read from or write to the stream as needed.

I would rather use base64 encoding of the wavetable and embed it in the XML.
Only drawback is, that base64 is int8, and your wavetable is probably in floats. But that is also solvable.

1 Like

It seems unnecessary to store all 4,000-some values of each wavetable. How were these wavetables originally generated? If it’s based on some kind of deterministic equation, then you can just save the equation and the size of the table with your state info, and to restore just recalculate values based on the equation and table size.

If the user can edit the wavetables, then you can use a technique such as B-splines to reverse engineer an equation that fits whatever arbitrary curve the user has created. The other advantage of this approach is it would allow you to change the table size while preserving the original shape of the curve.

@Mrugalla knows a lot about B-splines if you want more info on that!

2 Likes

I would rather use base64 encoding of the wavetable and embed it in the XML.

That’s actually what we did for some data like that.

You obviously have not seem my YouTube video demo in earlier posts. My synth has ways to create literally millions of weird waveform via an advanced waveform creator, plus a manual fine tune editor, so no I have to save them.

Unless it’s literally 4,000 random points generated by white noise, I’d be willing to bet that no matter how weird the shape is, there exists a mathematical equation that can model it accurately and reproducably.

You’re on, how much? But keep in mind that via a manual editor, user can select whole or part of the table, and then move, flip, bit reduce, jagging, smooth, distort, or take that particular part and go to my waveform creator and for that selected edit part create one of millions of waveforms. Sure I could record the user’s steps, but missa thinks it will be a lot easier to just save the waveforms.

That’s not very nice. If you don’t think my idea is suitable for your use case, you can just say that, instead of being rude.

Sorry for trying to help you.

You misunderstood my joke. No rude intention whatsoever.

I’ll post another demo soon so you can see what I am talking about.

i think you mixed up b-splines with cubic bezier curves. i didn’t finish the b-spline-thing. anyway. my ideas for this wavetable problem are:

a) save them as wav-files in some folder, just like it is done in serum. that also makes them exchangable with other synths, something users enjoy a lot.
b) actually find the polynom that describes the curve whenever it has to be saved and use the polynom to construct it when loaded. maybe that functionality would even open up new other feature possibilities

1 Like

if it helps

surge ships wavetables as standalone files for browsing and can browse both factory and user wavetables in this way. Even our wavetables which are formula specified are saved as binaries (right now).

but if you use them in a patch it streams the binary into the patch, so patches are transportable across machines with different wavetable libraries.

we actually save it as a binary blob (we don’t use the JUCE parameter mechanism to save) but storing the binary wavetable in our patch file, although it leads to bigger patches, results in well working sharable patch documents.

(We also allow export to wav of a wavetable and try to support the various RIFF tagging mechanisms that the various wt synths use and have a format for files which isn’t wav which matches the bigwig wt oscillator and stuff).

1 Like

Here is the Youtube video link, as promised, demonstrating a bit of my synth, and in particular preset selection, creation, and importing wavetable waveforms, and then manipulate part or all of the waveform.

By the way, a free download of this synth, in a sandbox (no saving or loading) version will be available very soon!

I’m guessing even if you were able to define a polynomial that would express the waveforms perfectly, it would be a lot of work up front, and would trading some time to recompute them versus some added space in the data. For a really large amount of data, we sometimes write it to an external file so as not to bloat the data too much (but that requires the user to migrate that file if they migrate the session, and not all hosts provide a way to know where the session is so you can write the file there). Otherwise, we stream to a buffer/buffers, and use 64-bit-encoding to put that/them into the XML.

Even the simplest attempt to manually use MemoryOutputStream to write and MemoryInputStream to read fails, so I am missing something, doing something wrong.

End of my getStateInformation

void MutineerAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
...
   // Above all my audio parameters and xml converted gui settings.

    copyXmlToBinary (*xml, destData);

    MemoryOutputStream (destData, true).writeInt (wavetableSize);

I checked the Reaper stored the “rpp” file, and I can see that something is added in the section that stores my synth state, however when I attempt to read it back in setStateInformation, it is garbage.

void MutineerAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    // Retrieving audio parameters and xml converted gui settings up here
    ....
    parameters.replaceState (ValueTree::fromXml (*xmlState));

    // Reads invalid, garbage value
    wavetableSize = MemoryInputStream (data, sizeof(int), false).readInt ();
}

Do you have an example of your suggestion?

I tried using “std::to_string” and then xml->setAttribute to write the data which works fine, but I am having difficulty using std:stof to read it back,

Hey, super nice synth, congratulations! It’s looking and sounding good and I can very much imagine using it!

As to what @benvining suggested: it’s actually not so unrealistic at all. It’s amazing what some seemingly simple equations can achieve. Although it’s easier to just save the wavetable as a binary (and it’s probably what I would do) it might be interesting to look into what he suggested at some point, even if just as an intellectual exercise. Perhaps it can be useful for something else. Here’s a video which demonstrates the general idea quite well. Truly fascinating stuff!

2 Likes