COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 03-25-2010, 10:42 AM   #1
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default 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
Astralp is offline   Reply With Quote
Old 03-25-2010, 11:46 AM   #2
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default

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
__________________
www.soundbytes.de
Soundbytes is offline   Reply With Quote
Old 03-25-2010, 11:58 AM   #3
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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
Astralp is offline   Reply With Quote
Old 03-26-2010, 12:37 AM   #4
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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.
cc_ is offline   Reply With Quote
Old 03-26-2010, 04:39 AM   #5
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

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".
Tale is offline   Reply With Quote
Old 03-26-2010, 04:59 AM   #6
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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...
cc_ is offline   Reply With Quote
Old 03-26-2010, 05:47 AM   #7
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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...
Astralp is offline   Reply With Quote
Old 03-26-2010, 09:33 AM   #8
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

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
Jeffos is offline   Reply With Quote
Old 03-26-2010, 11:08 AM   #9
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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?
cc_ is offline   Reply With Quote
Old 03-26-2010, 12:25 PM   #10
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 03-26-2010, 01:02 PM   #11
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

Quote:
Originally Posted by Astralp View Post
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!?
cc_ is offline   Reply With Quote
Old 03-28-2010, 09:41 PM   #12
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 03-28-2010, 11:37 PM   #13
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 03-29-2010, 11:58 AM   #14
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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...
cc_ is offline   Reply With Quote
Old 03-29-2010, 12:10 PM   #15
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

Great CC, I'll give this a shot now, thanks for posting, I've been stuck on this for weeks now.
Astralp is offline   Reply With Quote
Old 03-29-2010, 02:49 PM   #16
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 03-29-2010, 05:06 PM   #17
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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..
Astralp is offline   Reply With Quote
Old 03-30-2010, 01:12 AM   #18
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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.
cc_ is offline   Reply With Quote
Old 03-30-2010, 09:41 AM   #19
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 03-30-2010, 04:06 PM   #20
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 04-06-2010, 01:57 AM   #21
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

Quote:
Originally Posted by Astralp View Post
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?
cc_ is offline   Reply With Quote
Old 04-06-2010, 06:42 AM   #22
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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...
cc_ is offline   Reply With Quote
Old 04-06-2010, 07:53 AM   #23
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 04-06-2010, 08:48 AM   #24
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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.
cc_ is offline   Reply With Quote
Old 04-06-2010, 10:06 AM   #25
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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...
cc_ is offline   Reply With Quote
Old 04-10-2010, 11:26 AM   #26
debian
Human being with feelings
 
debian's Avatar
 
Join Date: Nov 2008
Posts: 35
Default

Is anyone up for trying to explain what does the functions UnserializeState and UnserializeState

Best regards
__________________
ojoj...
debian is offline   Reply With Quote
Old 04-10-2010, 11:58 AM   #27
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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!
Astralp is offline   Reply With Quote
Old 04-10-2010, 03:33 PM   #28
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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;
  }
Astralp is offline   Reply With Quote
Old 04-10-2010, 06:17 PM   #29
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 04-11-2010, 01:00 AM   #30
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

Quote:
Originally Posted by Astralp View Post
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 View Post
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.)
Tale is offline   Reply With Quote
Old 04-11-2010, 04:15 AM   #31
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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.
cc_ is offline   Reply With Quote
Old 04-11-2010, 04:08 PM   #32
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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.
Astralp is offline   Reply With Quote
Old 04-11-2010, 04:14 PM   #33
Astralp
Human being with feelings
 
Join Date: Dec 2009
Posts: 73
Default

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!
Astralp is offline   Reply With Quote
Old 04-13-2010, 05:03 AM   #34
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

Quote:
Originally Posted by Astralp View Post
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 View Post
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();
}
Tale is offline   Reply With Quote
Old 04-14-2010, 06:58 AM   #35
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

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...
Attached Files
File Type: txt Containers.h.txt (5.4 KB, 423 views)
cc_ is offline   Reply With Quote
Old 04-17-2011, 07:36 AM   #36
cerberus
Human being with feelings
 
Join Date: Nov 2009
Location: memory
Posts: 633
Default

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.
cerberus is offline   Reply With Quote
Old 04-17-2011, 05:27 PM   #37
cerberus
Human being with feelings
 
Join Date: Nov 2009
Location: memory
Posts: 633
Default

oh i figured it out... thanks in no small part to this thread.. ty!
cerberus is offline   Reply With Quote
Old 09-29-2019, 10:01 AM   #38
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

Quote:
Originally Posted by cc_ View Post
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).
earlevel is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 07:16 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.