|
|
|
12-23-2017, 04:38 AM
|
#1
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Rookie question on ProjState, State Chunks, RPP format
Never played in this sandbox, but surely lots of folks must have used this stuff before and there must be some examples/snippets out there.
Basically, I just need to push/pull a small number of project specific data items to/from the .RPP file, is that the ProjState stuff ?
As well I've decided to use the .RPP format for the maps.
I think that means I have to understand StateChunks, yes ?
Anyone know of source examples I should grab for these jobs ?
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-23-2017, 06:35 AM
|
#2
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
|
Get/SetProjExtState() is good for storing basic key/value pairs in the project file.
https://www.extremraym.com/cloud/rea...etProjExtState
Example where I recently used it to make a value persitant across script execution (Lua, but you should get the gist, as it's basic stuff really)
Check for ext. state and get it:
https://github.com/nofishonfriday/Re...opping.lua#L55
Set it:
https://github.com/nofishonfriday/Re...pping.lua#L134
edit:
Correction, above script uses Get/SetExtState(), not Get/SetProjExtState().
The difference is that Get/SetExtState() stores the values in a separate file (reaper-extstate.ini) and so is project independant, while Get/SetProjExtState() directly stores in the project file.
If you need to store more advanced stuff, maybe have a look at how Klinke does it with his plugin (he stores the track states and things in the rpp, using JUCE)
https://bitbucket.org/Klinkenstecker...Tracks.cpp-936
edit:
Addition, Klinke uses a dedicated section in the <EXTENSIONS chunk of the .rpp to store his stuff which looks like this:
If you want to study StateChunks, I find these great resources:
- Eugene's chunk editor script (can be used to see track chunk states / changes almost in realtime)
https://forum.cockos.com/showthread.php?t=194369
- The chunk definitions Wiki
http://wiki.cockos.com/wiki/index.ph...nk_Definitions
Sorry if this is too basic stuff, wasn't sure where to start...
Last edited by nofish; 12-23-2017 at 07:07 AM.
|
|
|
12-23-2017, 08:33 AM
|
#3
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by nofish
Get/SetProjExtState() is good for storing basic key/value pairs in the project file.
https://www.extremraym.com/cloud/rea...etProjExtState
Example where I recently used it to make a value persitant across script execution (Lua, but you should get the gist, as it's basic stuff really)
Check for ext. state and get it:
https://github.com/nofishonfriday/Re...opping.lua#L55
Set it:
https://github.com/nofishonfriday/Re...pping.lua#L134
edit:
Correction, above script uses Get/SetExtState(), not Get/SetProjExtState().
The difference is that Get/SetExtState() stores the values in a separate file (reaper-extstate.ini) and so is project independant, while Get/SetProjExtState() directly stores in the project file.
If you need to store more advanced stuff, maybe have a look at how Klinke does it with his plugin (he stores the track states and things in the rpp, using JUCE)
https://bitbucket.org/Klinkenstecker...Tracks.cpp-936
edit:
Addition, Klinke uses a dedicated section in the <EXTENSIONS chunk of the .rpp to store his stuff which looks like this:
If you want to study StateChunks, I find these great resources:
- Eugene's chunk editor script (can be used to see track chunk states / changes almost in realtime)
https://forum.cockos.com/showthread.php?t=194369
- The chunk definitions Wiki
http://wiki.cockos.com/wiki/index.ph...nk_Definitions
Sorry if this is too basic stuff, wasn't sure where to start...
|
Thanks !!
I need almost exactly what Klinke has, and for basically the same reason, locked tracks are on a per project basis, that's perfect for my needs.
The rest I'll have a look at, betcha' what I need is in there, thanks again !!
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-23-2017, 12:30 PM
|
#4
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Hmmm...
I'm calling SetExtState("Section" "Key", "Value", true) but nothing is being written to disk in the <EXTENSIONS> section of the .RPP file, what have I left out ?
Must be missing something simple and obvious...
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-23-2017, 01:30 PM
|
#5
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Just to be perfectly clear, here is the actual code snippet:
Code:
string value = "";
string section = ControlSurfaceIntegrator;
string key = channels_[i]->GetGUID() + GetName();
SetExtState(section.c_str(), key.c_str(), to_string(i - 1).c_str(), true);
bool foundIt = HasExtState(section.c_str(), key.c_str());
if(foundIt)
value = GetExtState(section.c_str(), key.c_str());
foundIt == true, and the value returned is correct, just no persistence to disk...
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
Last edited by Geoff Waddington; 12-23-2017 at 01:35 PM.
|
|
|
12-23-2017, 01:31 PM
|
#6
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
SetExtState with persist=true writes into reaper-extstate.ini. You probably meant to use SetProjExtState.
|
|
|
12-23-2017, 02:00 PM
|
#7
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by cfillion
SetExtState with persist=true writes into reaper-extstate.ini. You probably meant to use SetProjExtState.
|
Doh !!
Works well now.
However, still have a couple of problems.
Need to save the project in order to flush the state.
So, what I'd like to do is mark the project dirty, so that it prompts for a save, any ideas?
I tried putting stuff in destructors, but it is already too late there.
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-23-2017, 05:08 PM
|
#9
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by nofish
|
Thanks, MarkProjectDirty() did the trick, I seem to remember it not working before too, but it does now prompt for a save.
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-23-2017, 05:35 PM
|
#10
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
|
Then I misunderstood, doesn't matter, glad it does what you need.
|
|
|
12-24-2017, 06:48 AM
|
#11
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Ok, so all of this Chunk stuff eventually leads you to GetSetObjectState().
Very cool, and I think I understand Reaper internals a bit better now.
Storing state that way looks useful for things like undo, etc. as well as writing/reading disk files.
Which brings us to the point.
GetSetObjectState() is a bit too meta for what's needed.
What's needed are the underlying parsing functions.
We won't be messing with .RPP files, with the exception of a few project specific items like locked tracks.
We don't need the high level stuff like GetSetObjectState() because we are writing/reading the map files NOT the .RPP file.
It just happens that the .RPP format is excellent for map file representation too.
So we just need much lower level parse functions, a lot more like SetProjExtState().
Are those even published anywhere ?
line parse.h ? projectContext.h ? projectContext.cpp ?
Is that where I should start ?
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-24-2017, 09:17 AM
|
#13
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by nofish
|
Yup, looked at those, that's what alerted me to the fact that the GetSetObjectState is very .RPP specific, I'm sure there are some things I can learn from there though, thanks again for the help.
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-25-2017, 10:02 AM
|
#14
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
Quote:
Originally Posted by Geoff Waddington
What's needed are the underlying parsing functions.
|
WDL's lineparse.h. You will need to write quite a lot of additional logic around the LineParser object. As its name says, it's just a a way to parse tokens from lines.
Here's my implementation for storing and loading a 1 chunk and 1 line state for my custom PCM_source object :
Code:
void SID_PCM_Source::SaveState(ProjectStateContext * ctx)
{
ctx->AddLine("FILE \"%s\" %f %d %d %d %d", m_sidfn.toRawUTF8(),m_sidlen,m_sid_track, m_sid_channelmode,m_sid_sr,m_sid_render_mode);
}
int SID_PCM_Source::LoadState(const char * firstline, ProjectStateContext * ctx)
{
LineParser lp;
char buf[2048];
for (;;)
{
if (ctx->GetLine(buf, sizeof(buf)))
break;
lp.parse(buf);
if (strcmp(lp.gettoken_str(0), "FILE") == 0)
{
m_sidfn = String(CharPointer_UTF8(lp.gettoken_str(1)));
m_sidlen = lp.gettoken_float(2);
m_sid_track = lp.gettoken_int(3);
m_sid_channelmode = lp.gettoken_int(4);
m_sid_sr = lp.gettoken_int(5);
m_sid_render_mode = lp.gettoken_int(6);
}
if (lp.gettoken_str(0)[0] == '>')
{
renderSID();
return 0;
}
}
return -1;
}
That uses the Reaper provided ProjectContext stuff though. You will of course need to do things a bit differently when using your own text files and if you are using multiple state lines/chunks and so on.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Last edited by Xenakios; 12-25-2017 at 11:40 AM.
|
|
|
12-25-2017, 11:41 AM
|
#15
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by Xenakios
WDL's lineparse.h. You will need to write quite a lot of additional logic around the LineParser object. As its name says, it's just a a way to parse tokens from lines.
Here's my implementation for storing and loading a 1 chunk and 1 line state for my custom PCM_source object :
Code:
void SID_PCM_Source::SaveState(ProjectStateContext * ctx)
{
ctx->AddLine("FILE \"%s\" %f %d %d %d %d", m_sidfn.toRawUTF8(),m_sidlen,m_sid_track, m_sid_channelmode,m_sid_sr,m_sid_render_mode);
}
int SID_PCM_Source::LoadState(const char * firstline, ProjectStateContext * ctx)
{
LineParser lp;
char buf[2048];
for (;;)
{
if (ctx->GetLine(buf, sizeof(buf)))
break;
lp.parse(buf);
if (strcmp(lp.gettoken_str(0), "FILE") == 0)
{
m_sidfn = String(CharPointer_UTF8(lp.gettoken_str(1)));
m_sidlen = lp.gettoken_float(2);
m_sid_track = lp.gettoken_int(3);
m_sid_channelmode = lp.gettoken_int(4);
m_sid_sr = lp.gettoken_int(5);
m_sid_render_mode = lp.gettoken_int(6);
}
if (lp.gettoken_str(0)[0] == '>')
{
renderSID();
return 0;
}
}
return -1;
}
That uses the Reaper provided ProjectContext stuff though. You will of course need to do things a bit differently when using your own text files and if you are using multiple state lines/chunks and so on.
|
Thanks man, that's exactly the "starter" code example I was searching for !!
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
12-25-2017, 12:55 PM
|
#16
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
As a bonus, a C++17 version (not completely tested and debugged) for parsing that uses fold expressions and constexpr if :
Code:
void SID_PCM_Source::SaveState(ProjectStateContext * ctx)
{
ctx->AddLine("FILE \"%s\" %f %d %d %d %d", m_sidfn.toRawUTF8(),m_sidlen,m_sid_track, m_sid_channelmode,m_sid_sr,m_sid_render_mode);
}
template<typename T>
inline void setFromToken(LineParser& lp, int index, T& value)
{
if constexpr (std::is_same<int, T>::value)
value = lp.gettoken_int(index);
else if constexpr (std::is_same<double, T>::value)
value = lp.gettoken_float(index);
else if constexpr (std::is_same<float, T>::value)
value = static_cast<float>(lp.gettoken_float(index));
else if constexpr (std::is_same<String, T>::value)
value = String(CharPointer_UTF8(lp.gettoken_str(index)));
else
static_assert(false, "Type not supported by LineParser");
}
template<typename... Args>
inline void setFromTokens(LineParser& lp, Args&&... args)
{
int index = 0;
(setFromToken(lp, ++index, args), ...);
}
int SID_PCM_Source::LoadState(const char * firstline, ProjectStateContext * ctx)
{
LineParser lp;
char buf[2048];
for (;;)
{
if (ctx->GetLine(buf, sizeof(buf)))
break;
lp.parse(buf);
if (strcmp(lp.gettoken_str(0), "FILE") == 0)
{
setFromTokens(lp, m_sidfn, m_sidlen, m_sid_track, m_sid_channelmode, m_sid_sr, m_sid_render_mode);
}
if (lp.gettoken_str(0)[0] == '>')
{
renderSID();
return 0;
}
}
return -1;
}
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
|
|
|
12-25-2017, 09:54 PM
|
#17
|
Human being with feelings
Join Date: Mar 2009
Location: Dartmouth, Nova Scotia
Posts: 11,184
|
Quote:
Originally Posted by Xenakios
As a bonus, a C++17 version (not completely tested and debugged) for parsing that uses fold expressions and constexpr if :
Code:
void SID_PCM_Source::SaveState(ProjectStateContext * ctx)
{
ctx->AddLine("FILE \"%s\" %f %d %d %d %d", m_sidfn.toRawUTF8(),m_sidlen,m_sid_track, m_sid_channelmode,m_sid_sr,m_sid_render_mode);
}
template<typename T>
inline void setFromToken(LineParser& lp, int index, T& value)
{
if constexpr (std::is_same<int, T>::value)
value = lp.gettoken_int(index);
else if constexpr (std::is_same<double, T>::value)
value = lp.gettoken_float(index);
else if constexpr (std::is_same<float, T>::value)
value = static_cast<float>(lp.gettoken_float(index));
else if constexpr (std::is_same<String, T>::value)
value = String(CharPointer_UTF8(lp.gettoken_str(index)));
else
static_assert(false, "Type not supported by LineParser");
}
template<typename... Args>
inline void setFromTokens(LineParser& lp, Args&&... args)
{
int index = 0;
(setFromToken(lp, ++index, args), ...);
}
int SID_PCM_Source::LoadState(const char * firstline, ProjectStateContext * ctx)
{
LineParser lp;
char buf[2048];
for (;;)
{
if (ctx->GetLine(buf, sizeof(buf)))
break;
lp.parse(buf);
if (strcmp(lp.gettoken_str(0), "FILE") == 0)
{
setFromTokens(lp, m_sidfn, m_sidlen, m_sid_track, m_sid_channelmode, m_sid_sr, m_sid_render_mode);
}
if (lp.gettoken_str(0)[0] == '>')
{
renderSID();
return 0;
}
}
return -1;
}
|
Nice !!
__________________
To install you need the CSI Software and Support Files
For installation instructions and documentation see the Wiki
Donate -- via PayPal to waddingtongeoff@gmail.com
|
|
|
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 01:59 PM.
|