|
03-25-2010, 10:42 AM
|
#1
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Text Patch Storage
I've managed to get text storage as a chunk working inside the plugin, and it appears that serialze/unserialize are working as they should. The problem is that when the vsti is loaded the value reverts back to the default value. I've obviously missed something important. From what I can see, the vst is initialized with default values and then the saved values from the host project are serialized/unserialized. If anyone can think of what I may have missed here I'd be grateful. Enabling/disabling chunks makes no difference.
I wish that the ability to store text was part of the sdk, without it storing paths is impossible.
Andy
|
|
|
03-25-2010, 11:46 AM
|
#2
|
Human being with feelings
Join Date: May 2006
Posts: 58
|
If you want to store data persistently to have it remembered between plugin sessions you will have to write it into a file and read that when the information is needed again.
In windows you would write the data into the registry but that is not available under Mac OS. In older win versions applications used ini files to store their settings. You could also use an xml file to store settings or preferences.
I am new to Mac OSX and don't know how it is supposed to be done there. I have seen that applications have a standardized preferences dialog but that is not available for plugins as far as I am aware.
Anyway the ini file solution should of course work fine there as well.
Check out the ini file parser in swell-ini.cpp. This might be what you are looking for.
I would think the best location to store an ini file might be inside the application bundle. Or is there any reason to better avoid this?
Andreas
|
|
|
03-25-2010, 11:58 AM
|
#3
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Hi Andreas
Thanks for the reply but unfortunately global storage isn't what I'm looking for. The ini file method is great for global settings that are shared across instances, but for a sampler as an example where you need to store the file path as part of the preset it doesn't help. As far as I can figure it, VST Chunks can store any data type and there it is even implemented in the WDL pointer types to store const char, it was very easy to adapt the sdk to write/read text chunks. I have no chance of porting my existing products without this ability, and so I'm keen to get it implemented. I'm just puzzled as to why and where the reading back is not happening, I'm sure it is something simple I've missed.
thanks again though!
Andy
|
|
|
03-26-2010, 12:37 AM
|
#4
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
I would love to get this working too, but I can't figure it out at all! I looked in IPlugBase but I couldn't work out what to implement to even get started.
What have you done so far?
One thing that really confuses me is that getchunk/setchunk seem to deal with banks of presets (even if you only have one preset in the bank) and I can't see how that works in the code.
Last edited by cc_; 03-26-2010 at 12:47 AM.
|
|
|
03-26-2010, 04:39 AM
|
#5
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Here's my go on serializing chunks, which seems to work fine:
Code:
MyPlug::MyPlug(IPlugInstanceInfo instanceInfo): IPLUG_CTOR(kNumParams, 0, instanceInfo)
{
mMyStr.Set("REAPER");
}
bool MyPlug::SerializeState(ByteChunk* pChunk)
{
IMutexLock lock(this);
if (pChunk->PutStr("Audio Production Without Limits") <= 0) return false;
return SerializeParams(pChunk);
}
int MyPlug::UnserializeState(ByteChunk* pChunk, int startPos)
{
IMutexLock lock(this);
startPos = pChunk->GetStr(&mMyStr, startPos);
return UnserializeParams(pChunk, startPos);
}
This will set mMyStr to "REAPER" for newly added instances of the plug. When a preset or a project with the plug is loaded mMyStr will receive the string "Audio Production Without Limits".
|
|
|
03-26-2010, 04:59 AM
|
#6
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
That looks too easy! Maybe that's why I couldn't figure it out :-)
I'll give it a go when I get a chance...
|
|
|
03-26-2010, 05:47 AM
|
#7
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Well I've just woken up and I'm trying to understand the above, but not feeling too optimistic what I'm wondering is if you changed the text in a single instance to another string, would it be saved/restored in the preset?
here is my serialize params code, though it requires serious hacking of the sdk to get the the text parameter itself working:
Code:
bool IPlugBase::SerializeParams(ByteChunk* pChunk)
{
TRACE;
WDL_MutexLock lock(&mMutex);
bool savedOK = true;
int i, n = mParams.GetSize();
for (i = 0; i < n && savedOK; ++i) {
IParam* pParam = mParams.Get(i);
if(!pParam->IsText()) {
double v = pParam->Value();
savedOK &= (pChunk->Put(&v) > 0);
}
else {
const char* v = pParam->ValueText();
savedOK &= (pChunk->PutStr(v) > 0);
}
}
return savedOK;
}
Code:
int IPlugBase::UnserializeParams(ByteChunk* pChunk, int startPos)
{
TRACE;
WDL_MutexLock lock(&mMutex);
int i, n = mParams.GetSize(), pos = startPos;
for (i = 0; i < n && pos >= 0; ++i) {
IParam* pParam = mParams.Get(i);
if(!pParam->IsText())
{
double v = 0.0;
Trace(TRACELOC, "%d %s", i, pParam->GetNameForHost());
pos = pChunk->Get(&v, pos);
pParam->Set(v);
}
else
{
WDL_String v;
pos = pChunk->GetStr(&v, pos);
pParam->Set(v.Get());
}
}
OnParamReset();
return pos;
}
I set up a Set() for const char in IParam and there is an mValueT variable to hold the text etc...
From my experiments I think that the presets don't matter, all the chunks get stored, but I could be wrong and perhaps that is where the problem with my method lies...
|
|
|
03-26-2010, 09:33 AM
|
#8
|
Mortal
Join Date: Dec 2008
Location: France
Posts: 1,969
|
works fine here too (win). I see you manage "text params", here I separate true param chunks and, say, 'unrelated raw data' (such as text) with a fake control (i.e. a control that doesn't have a VST param), eg, typivcally, to restore a file path, after OnParamReset():
Code:
int PlugExample::UnserializeState(ByteChunk* pChunk, int startPos)
{
IMutexLock lock(this);
//from IPlugBase --->
int i, n = mParams.GetSize(), pos = startPos;
for (i = 0; i < n && pos >= 0; ++i) {
IParam* pParam = mParams.Get(i);
double v = 0.0;
Trace(TRACELOC, "%d %s", i, pParam->GetNameForHost());
pos = pChunk->Get(&v, pos);
pParam->Set(v);
}
OnParamReset();
//<---
#ifdef FX_REA_CONTROL
// load the path
WDL_String filename;
pos = pChunk->GetStr(&filename, pos);
((IFileSelectorControl*)m_gfx->GetControl(m_fileGfxIdx))->SetLastSelectedFileFromPlug(filename.Get());
#endif
return pos;
}
HTH
|
|
|
03-26-2010, 11:08 AM
|
#9
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
I tried Tale's method...
First I added an editable text control to IPlugExample (using my version of iplug I posted here):
Code:
ScribbleStrip = new IEditableTextControl(this, &IRECT(20,160,150,180) , &txt, "Scribble Strip");
if (ScribbleStrip) {
ScribbleStrip->SetBGColor( &COLOR_BLACK );
pGraphics->AttachControl(ScribbleStrip);
}
Then I added the functions to save/restore:
Code:
bool PlugExample::SerializeState(ByteChunk* pChunk)
{
IMutexLock lock(this);
if ( ScribbleStrip == NULL ) return false;
if (pChunk->PutStr(ScribbleStrip->GetText()) <= 0) return false;
return SerializeParams(pChunk);
}
int PlugExample::UnserializeState(ByteChunk* pChunk, int startPos)
{
IMutexLock lock(this);
WDL_String MyStr;
startPos = pChunk->GetStr(&MyStr, startPos);
if (ScribbleStrip) ScribbleStrip->SetTextFromPlug( MyStr.Get() );
return UnserializeParams(pChunk, startPos);
}
And set PLUG_DOES_STATE_CHUNKS to 1 in resource.h
That seemed to work! If I edit the text, then save, quit, reload the new text is there.
The only unexpected thing was if I change presets while Reaper is running all the regular parameters also change, but this text doesn't. Maybe there's something else that needs to be done?
|
|
|
03-26-2010, 12:25 PM
|
#10
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
That's great news! I'll explore these methods later on tonight, I like the idea of bolting it on instead of my hacked method (though I'd love to see text param added to the core officially considering it's usefulness).
CC I had trouble with my control display updating in my hack, I had to use hide/unhide to force it to refresh on preset change, prob not related to your prob but thought I'd mention it.
thanks to everyone for the input, I was afraid this thread would be silent, so I'm over the moon to have these avenues to explore, I've been stuck all week trying to figure out what was wrong.
EDIT: CC are you calling this from your control or from onParamChange()? I also remember reading in the VST SDK docs that serialize chunks has to be called twice, I forget why now... maybe that is the issue you are having.
|
|
|
03-26-2010, 01:02 PM
|
#11
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
Quote:
Originally Posted by Astralp
CC I had trouble with my control display updating in my hack, I had to use hide/unhide to force it to refresh on preset change, prob not related to your prob but thought I'd mention it.
|
Hiding/unhiding doesn't change it.
Quote:
EDIT: CC are you calling this from your control or from onParamChange()? I also remember reading in the VST SDK docs that serialize chunks has to be called twice, I forget why now... maybe that is the issue you are having.
|
I'm really not calling anything, I create the control in the plugin constructor and define serialise and unserialise function I gave above. Maybe I should be calling something!?
|
|
|
03-28-2010, 09:41 PM
|
#12
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Just managed to spend a bit of time trying to get this to work but infuriatingly overriding these functions does not work for me, they aren't called even in the example project (VS 2005 via codeblocks). I'm stumped... so looks like I will have to hack the core unless anyone has any suggestions.
EDIT oh cc, you shouldn't return the function by the way, otherwise in a fail situation the main params wouldn't get serialized?
EDIT again, DOES_STATE_CHUNKS 1 ahhhhhhhhh...... ok problem solved
Last edited by Astralp; 03-28-2010 at 10:36 PM.
|
|
|
03-28-2010, 11:37 PM
|
#13
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
well for me the above method doesn't update any parameters on a preset change it just makes everything default when PLUG_DOES_STATE_CHUNKS 1. So far I haven't found a solution, going back to serialize parameters with STATE_CHUNKS off is the same position I was in at the start of the thread.
|
|
|
03-29-2010, 11:58 AM
|
#14
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
I've been looking some more and made some progress... I'm not going to get a chance to do any more for a week or so, so I thought I'd report back here...
I think I have it all working, but haven't tested two much, but changing presets works for my text and all the parameters, and saving and loading the project keeps the state of all presets.
I think this is all:
- In IPlugBase.cpp everywhere there is a call to SerializeParams() you need to replace it with a call to SerializeState(), and similarly replace UnserializeParams() calls with UnserializeState().
- In IPlugVST.cpp there there are two commented out lines that you need to uncomment, and then comment out the next line, so it ends up like this:
Code:
savedOK = _this->SerializePresets(pChunk);
//savedOK = _this->SerializeState(pChunk);
...
pos = _this->UnserializePresets(pChunk, pos);
//pos = _this->UnserializeState(pChunk, pos);
- After the user changes the text field you need to somehow arrange for
ModifyCurrentPreset() to be called. This probably happens automatically for a file selector (I haven't tested it). But for my editable text field it doesn't. I haven't figured out a good place to do this. It does happen when you move one of the regular controls though.
- If you're working with IPlugExample you need to comment out the calls to MakePreset() as this function doesn't know about anything you've added to the chunk and so will write chunks that will break things later. I think MakeDefaultPreset() is OK, but I removed that too.
- If you're trying to get my example above working you'll need to change the serialize function so it puts something in the chunk even when there isn't a control yet:
Code:
bool PlugExample::SerializeState(ByteChunk* pChunk)
{
IMutexLock lock(this);
if ( ScribbleStrip == NULL ) {
if (pChunk->PutStr("default") <= 0)
return false;
}
else {
if (pChunk->PutStr(ScribbleStrip->GetText()) <= 0)
return false;
}
return SerializeParams(pChunk);
}
- Make sure you delete the plugin from your test project and insert a new copy once you've done all the fixes.
I will roll this into my IPlug code once I've tested it a bit more...
|
|
|
03-29-2010, 12:10 PM
|
#15
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Great CC, I'll give this a shot now, thanks for posting, I've been stuck on this for weeks now.
|
|
|
03-29-2010, 02:49 PM
|
#16
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
cc, many many thanks, I owe you big time, it works as it should, you've done us all a great favour by working this out. I was lost trying to work out why the presets weren't calling serializeState.
Your edit text is a nice control too, though I don't need it at the moment I'm sure it will come in useful at some point. For the record, to get modifyCurrentPreset() to work I added the following to IPlugBase in the public section:
Code:
void updateText() { ModifyCurrentPreset(); }
I then added this to your function in IGraphics.cpp
Code:
void IGraphics::SetFromStringAfterPrompt(char *txt) {
if (mEdParam) {
double v;
if (mEdParam->GetNDisplayTexts()) {
int vi = 0;
mEdParam->MapDisplayText(txt , &vi);
v = (double) vi;
}
else {
v = atof(txt);
if (mEdParam->DisplayIsNegated()) {
v = -v;
}
}
mEdControl->SetValueFromUserInput(mEdParam->GetNormalized(v));
}
else if (mEdControl) {
((ITextControl *)mEdControl)->SetTextFromPlug(txt);
mPlug->updateText(); // <------------------ Added this
}
}
Ok, I can start progressing again, thankyou.
|
|
|
03-29-2010, 05:06 PM
|
#17
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
I was just wondering how existing projects might be affected by future plugin updates when new parameters are added. Admittedly I haven't investigated this with the existing sdk yet as I haven't actually released anything official. Though I was thinking it might be easier to manage if the text params are stored after the main params, so that some sort of checking can implemented for the floats as at least they are of a standard size, whereas text can be of variable size. Just a thought..
|
|
|
03-30-2010, 01:12 AM
|
#18
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
Great news that it's working! It looked to me like schwa had figured it all out, but just hadn't quite finished making all the changes to make it work.
For coping with different plugin versions I don't think it makes a difference which order you put things in - if the parameters go first then you will have problems if you add a new parameter.
I guess what I will do is put a version number first in the chunk. Then if I ever change/add stuff I can check the version number and read the parameters in the data in the old format if necessary.
|
|
|
03-30-2010, 09:41 AM
|
#19
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
It is, you deserve beer! I think you're right.
What I've finally decided to do is to use a vector of strings at project level, and have set the number to 10 so that I have 10 reserved string storage chunks. I need 3 in the current project and I can't see needing anywhere near another 7, so that should cover the future I think.
I am now adapting my controls to take the string by reference so that changes between the vector and the various controls will remain in sync. This seems about the easiest way to manage it I think, so that in serialize it is just a loop to read to/from the vector like this:
Code:
bool PLUG_CLASS_NAME::SerializeState(ByteChunk* pChunk)
{
IMutexLock lock(this);
for (int i=0; i < textParams.size(); i++)
{
if (pChunk->PutStr(textParams[i].c_str()) <= 0)
return false;
}
return SerializeParams(pChunk);
}
int PLUG_CLASS_NAME::UnserializeState(ByteChunk* pChunk, int startPos)
{
IMutexLock lock(this);
for (int i=0; i < textParams.size(); i++)
{
WDL_String MyStr;
startPos = pChunk->GetStr(&MyStr, startPos);
textParams[i] = MyStr.Get();
}
OnParamChange(myTextParameter); // to do whatever with the value
return UnserializeParams(pChunk, startPos);
}
// In Header
vector<string> textParams;
// In Constructor
textParams.assign("unused", 10);
Then by making sure a fake paramIdx is associated with the appropriate controls, it should run through OnParamChange() or at the very least can be run manually where needed.
EDIT: Added OnParamChange, do one of these for the text params you are using so that any work can be carried out with the value. You would have one of these for each used parameter. Hope that makes sense, keeps things fairly clean that way.
Last edited by Astralp; 03-30-2010 at 04:12 PM.
|
|
|
03-30-2010, 04:06 PM
|
#20
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
ok I've found a problem, the presets in memory when altered aren't updated/stored unless the host project is explicitly saved. So if you go from preset 1 to preset 2 any changes made to preset 1 are lost, as when you go back to preset 1 it will restore the saved parameters.
Not an issue for me as I am using my own preset system and so only need one preset for automation purposes. But for the default behaviour of IPlug this is a change. I suppose we are just working with the currently loaded preset now, whereas originally it cycled through all the presets or something along those lines.
|
|
|
04-06-2010, 01:57 AM
|
#21
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
Quote:
Originally Posted by Astralp
ok I've found a problem, the presets in memory when altered aren't updated/stored unless the host project is explicitly saved. So if you go from preset 1 to preset 2 any changes made to preset 1 are lost, as when you go back to preset 1 it will restore the saved parameters.
|
OK, I'm back! But I can't replicate this problem, I only see this behaviour if ModifyCurrentPreset() is not called. Are you sure ModifyCurrentPreset() is getting called after your preset is altered?
|
|
|
04-06-2010, 06:42 AM
|
#22
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
Which host are you testing in? I am using Reaper. For regular parameters ModifyCurrentPreset() is being called as a result of Reaper doing an effGetChunk after I move a control, maybe other hosts don't do this?
Anyway I think the fix is in IPlugVST.cpp, it should be like this (currently the test is inverted):
Code:
case effSetProgram: {
if (_this->DoesStateChunks()) {
_this->ModifyCurrentPreset();
}
_this->RestorePreset((int) value);
return 0;
}
Although that seems a strange mistake to make, I hope I have not misunderstood something...
|
|
|
04-06-2010, 07:53 AM
|
#23
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
I've only tested in SE so far, I'll try this out and also try it in Reaper to see if it is ok, perhaps I missed something when I modified.
|
|
|
04-06-2010, 08:48 AM
|
#24
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
I should have mentioned: with that effSetProgram effSetProgram you should not need to call ModifyCurrentPreset() when the text field changes.
I also tried AU, the basic serializing works, but so far I only have one preset, I think because it is pruning all uninitialised presets which is all of them as I don't have MakePreset working at the moment.
|
|
|
04-06-2010, 10:06 AM
|
#25
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
Hmm, AU presets seem to be a bit different from VST presets. With VST presets they are just a bank you can edit how you want and the all get saved with the project. With AU presets they really seem to be just a list of fixed presets(!) which you can load into your plugin (REAPER won't even let you edit the titles).
If that's the correct behaviour, then it looks like it's all working.
I also changed MakePreset() so that there is a function you can implement to add your own stuff like the string I added:
Code:
void PlugExample::MakePresetState(ByteChunk *pChunk,va_list vp) {
// handle the first variable arg to MakePreset()
char *s = (char *) va_arg(vp, char * );
pChunk->PutStr(s);
// now handle all the other args (the parameters)
MakePresetParams(pChunk,vp);
}
That's the best way I could think of...
|
|
|
04-10-2010, 11:26 AM
|
#26
|
Human being with feelings
Join Date: Nov 2008
Posts: 35
|
Is anyone up for trying to explain what does the functions UnserializeState and UnserializeState
Best regards
__________________
ojoj...
|
|
|
04-10-2010, 11:58 AM
|
#27
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
hi debian
It is what the host uses to store the current state or preset of the vst. basically each chunk holds a piece of data that can be any data type. By default IPlug stores only floats and so using this method allows storing strings or other data types, but you have to then somehow manage the non float data yourself. When the data is unserialized, it is assigned to variables which we can use in our plugin.
For your sequencer data you could convert to a comma separated list and serialize it, and then explode it back to a vector in unserialize. Not the most efficient way, but I think storing vectors/arrays would need some more modifications to the core. I forget which file it is, but the data types available are defined somewhere, possibly in ptrlist.
hope this helps!
|
|
|
04-10-2010, 03:33 PM
|
#28
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Here's some code for int storage, needs adding to containers.h
Code:
inline int PutInt(int* b)
{
int n = mBytes.GetSize();
mBytes.Resize(n + sizeof(b));
memcpy(mBytes.Get() + n, (BYTE*) b, sizeof(b));
return mBytes.GetSize();
}
inline int GetInt(int* pB, int startPos)
{
int endPos = startPos + sizeof(pB);
if (startPos >= 0 && endPos <= mBytes.GetSize()) {
memcpy((BYTE*) pB, mBytes.Get() + startPos, sizeof(pB));
return endPos;
}
return -1;
}
|
|
|
04-10-2010, 06:17 PM
|
#29
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
just to add on the subject of storing vectors, I've looked into it and a vector can't be stored, it has to be rolled out storing each value, and then reconstructed to a vector when serialized. Makes more sense to use a string to me considering that serialize/unserialize isn't called that often.
|
|
|
04-11-2010, 01:00 AM
|
#30
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Astralp
Here's some code for int storage, needs adding to containers.h
|
Why? Ints can already be stored/serialized using the default Put() method. In fact ByteChunk::Put() can store any fixed-length data type.
Quote:
Originally Posted by Astralp
Code:
inline int PutInt(int* b)
{
int n = mBytes.GetSize();
mBytes.Resize(n + sizeof(b));
memcpy(mBytes.Get() + n, (BYTE*) b, sizeof(b));
return mBytes.GetSize();
}
|
I'm not exactly a C++ expert, but wouldn't give sizeof(b) give you sizeof(int*), thus the size of the pointer rather than the size of an int? (On Win32 pointers are also ints, so coincidentally they're the same size.)
|
|
|
04-11-2010, 04:15 AM
|
#31
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
I think you're right Tale.
Presumably Put would also store a fixed sized array if you defined it as a type (although I haven't tried it).
One thing I just realised though, presets probably aren't compatible between Intel and PPC macs (even for the regular parameters I think) because of endianess. Maybe I will try and fix this sometime, unless someone else wants to...
Last edited by cc_; 04-11-2010 at 04:22 AM.
|
|
|
04-11-2010, 04:08 PM
|
#32
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
Well I tried using put() first, but could not get it to work for ints, and my lack of understanding for templates led me to just copy the put() code in my above functions. I guess it's time to read up on templates... I'm not sure about sizeof pointer, but I think that is how it is in put isn't it? Can't check at the moment.
CC I don't have a level of experience to fix the file incompatibility, but that was one reason I'm using my own preset system, as well as the fact that all presets seem to be loaded into memory at runtime, amongst other reasons like sharing presets between my own different plugins. Be great if you can fix that though.
|
|
|
04-11-2010, 04:14 PM
|
#33
|
Human being with feelings
Join Date: Dec 2009
Posts: 73
|
oh just to explain why vectors can't be stored, it is to do with dynamic memory allocation, so the mem size can't accurately be determined of a vector, but yep I guess standard arrays will be fine. I'll have another look at put(), thanks for the heads up. I have to say, being able to store other data types is such a relief for me, I'm so thankful!
|
|
|
04-13-2010, 05:03 AM
|
#34
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Astralp
Well I tried using put() first, but could not get it to work for ints, and my lack of understanding for templates led me to just copy the put() code in my above functions.
|
The beauty of the template class stuff is that, even if you don't know much about it, you can still use it. You can simply do:
Code:
int mMyInt = 12345;
...
pChunk->Put(&mMyInt);
Quote:
Originally Posted by Astralp
I'm not sure about sizeof pointer, but I think that is how it is in put isn't it? Can't check at the moment.
|
No, ByteChunk::Put() does sizeof(T), not sizeof(pVal):
Code:
template <class T> inline int Put(const T* pVal)
{
int n = mBytes.GetSize();
mBytes.Resize(n + sizeof(T));
memcpy(mBytes.Get() + n, (BYTE*) pVal, sizeof(T));
return mBytes.GetSize();
}
|
|
|
04-14-2010, 06:58 AM
|
#35
|
Human being with feelings
Join Date: Mar 2009
Posts: 256
|
OK, here's a version of Containers.h modified so that plugin data stored in chunks is compatible between PPC and Intel machines.
There are no changes when compiling for Intel (although I had to move GetStr() and PutStr() to a different place in the file to keep the compiler happy). On PPC the data is converted and stored in little-endian format.
I have done the fix for int's and double's because these are the two types that IPlug uses internally. The code isn't too pretty, but it seems to work.
If you only have an intel mac you can still test this: Compile your plugin as a universal binary (I think this is the default for IPlugExample Release builds, but not for the Debug builds). Then find a PPC compatible sequencer and run it using arch -ppc, for example I use Reaper like this:
Code:
arch -ppc /Applications/REAPER3104_ppc/REAPER.app/Contents/MacOS/REAPER
Note: even if you are only saving your data as strings in the chunk using PutStr(), you still need this fix - because the string length is stored as an int.
If anyone can think of a cleaner way of doing this I'd be happy to hear it...
|
|
|
04-17-2011, 07:36 AM
|
#36
|
Human being with feelings
Join Date: Nov 2009
Location: memory
Posts: 633
|
how would i serialize control parameters that have no IParamIdx?
my intention is to hide some controls from host track automation, yet
to have their values restored when a saved project is reloaded.
|
|
|
04-17-2011, 05:27 PM
|
#37
|
Human being with feelings
Join Date: Nov 2009
Location: memory
Posts: 633
|
oh i figured it out... thanks in no small part to this thread.. ty!
|
|
|
09-29-2019, 10:01 AM
|
#38
|
Human being with feelings
Join Date: Dec 2015
Posts: 331
|
Quote:
Originally Posted by cc_
Which host are you testing in? I am using Reaper. For regular parameters ModifyCurrentPreset() is being called as a result of Reaper doing an effGetChunk after I move a control, maybe other hosts don't do this?
Anyway I think the fix is in IPlugVST.cpp, it should be like this (currently the test is inverted):
Code:
case effSetProgram: {
if (_this->DoesStateChunks()) {
_this->ModifyCurrentPreset();
}
_this->RestorePreset((int) value);
return 0;
}
Although that seems a strange mistake to make, I hope I have not misunderstood something...
|
Responding ot a message from 2010 because it's still referenced in IPlug (wdl/oli) and IPlug2 today:
Code:
case effSetProgram:
{
if (_this->DoesStateChunks() == false)
{
_this->ModifyCurrentPreset(); // TODO: test, something is funny about this http://forum.cockos.com/showpost.php?p=485113&postcount=22
It's hard for me to say which way is "right" because it seems they are both wrong. Although if no code where to be modified, I'd go with what's in IPlug/2 now, because there is no reason for PLUG_DOES_STATE_CHUNKS to be false (and therefore DoesStateChunks()) in any case I can possibly think of (because IPlug has a default chunks implementation).
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 07:16 AM.
|