Old 03-09-2017, 06:47 PM   #1
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,458
Default Sexan, Lokasenna, I need your help!

Hello!

I ask for help specifically from Sexan and Lokasenna because of this. But, whoever else could help or has similar code, please help!

I need a function that just stores in the project file (or in another file - maybe safer!) just the chunk that has to do with the items of a specified track. And then another function that reads them from file and restores them.
So, function StoreItems(trackGUID) and function RestoreItems(trackGUID).

Since, you have done it with your TrackList Versions script, could you share with me the code that would do specifically these two things? I don't need any other part of the code. Just the ability to save whatever has to do with the items of a specific track and then to recall it.

Thanks!
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is online now   Reply With Quote
Old 03-09-2017, 08:08 PM   #2
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

Storing data in a project

reaper.SetProjExtState( proj, extname, key, value )

proj = 0 will refer to the active project
extname = "Amagalma"
key = "GUID"
value = your GUID

Loading data from a project

retval = reaper.GetProjExtState( proj, extname, key )

(The API shows two return values, I don't know what the second one is for)

Returns the value you saved as a string, or just "" if that key doesn't exist.

----

There are two equivalent functions for storing values globally in one of Reaper's .ini files, i.e. for user settings in a script, etc:

reaper.SetExtState( section, key, value, persist )

section = Same as 'extname' above.
persist = Whether Reaper should store the value permanently or just hold on to it for this session.

Personally I find it easier to work with an external .txt file myself, especially for anything more than one or two lines of data.

Saving data to an external file

Code:
-- Get the script's path, so we can save the data in the same place
local info = debug.getinfo(1,'S');
local script_path = info.source:match[[^@?(.*[\/])[^\/]-$]]

local file_path = script_path .. "amagalma script data.txt"

-- Open the file for writing, and avoid crashing if there's a problem
-- "w+" means "erase whatever's there".
local file, err = io.open(file_name, "w+") or nil
if not file then 
  reaper.ShowMessageBox("Couldn't open the file.\nError: "..tostring(err), "Whoops", 0)
  return 0 
end

-- If your table's indices are contiguous numbers starting from 1, i.e. 123456789, not 123  6 apple 9...
for i = 1, #my_table_of_data do
  file:write(my_table[i] .. "\n")
end

-- Otherwise
for k, v in pairs(my_table_of_data) do
  file:write( tostring(k) .. "=" .. tostring(v) .. "\n" )
end

-- Close the file
io.close(file)
Loading data from an external file

Obviously this will depend on which of the two methods you used to save it.

Code:
-- Get the script's path, so we can save the data in the same place
local info = debug.getinfo(1,'S');
local script_path = info.source:match[[^@?(.*[\/])[^\/]-$]]

local file_path = script_path .. "amagalma script data.txt"

-- Open the file in "read" mode
local file, err = io.open(file_name) or nil
if not file then 
  reaper.ShowMessageBox("Couldn't open the file.\nError: "..tostring(err), "Whoops", 0)
  return 0 
end

-- If your data was indexed with contiguous numbers
for line in file:lines() do
  table.insert(my_table_of_data, line)
end

-- A little more work if you're using string keys or noncontiguous indices
for line in file:lines() do

  -- Break the line back up into a key and value.
  -- The matching pattern here will only work for data stored as:  key=value
  -- I haven't tried it though, not sure if it does work or not.
  local key, val = string.match(line, "(^[^=]*)=([^=]*)$")

  -- Error checking
  if not (key and val) then
    reaper.ShowMessageBox("Error parsing this line:\n" .. line)
    my_error_checking_value = true
    break
  end

  -- Currently the key and value are strings. If either of them were 
  -- originally numbers, let's get them back that way
  key = not tonumber(key) and key or tonumber(key)
  val = not tonumber(val) and val or tonumber(val)

  my_table_of_data[key] = val

end

io.close(file)
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate

Last edited by Lokasenna; 03-09-2017 at 08:29 PM.
Lokasenna is offline   Reply With Quote
Old 03-10-2017, 06:07 AM   #3
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,458
Default

Thank you SO much Lokasenna!!!

A few questions:
1) if I wanted to save it in the project path, then I would replace:
Code:
local info = debug.getinfo(1,'S');
local script_path = info.source:match[[^@?(.*[\/])[^\/]-$]]
with: script_path = reaper.GetProjectPath(0)
Right?
2)I had a look at the patterns section of the Lua manual, but still cannot understand: [[^@?(.*[\/])[^\/]-$]]. Could you explain?
3) In your opinion is it safer to store the data in the Project itself or in an external file? In the first occasion, I am worried if by mistake I corrupt the project file and in the second occasion I am worried if I delete accidentally the external file and loose what I had stored..


Hopefully, Sexan comes with his get/restore items from track chunk code and I combine it all to the script I need
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is online now   Reply With Quote
Old 03-10-2017, 08:21 AM   #4
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

1. I think so, yes.

3. As far as I know it's not possible for an ExtState to corrupt a project file. As for accidentally deleting the external file... maybe don't delete it then? I prefer external files just because it's easier to store a lot of settings/data in whatever format you want. For instance, Radial Menu stores its settings as a Lua table in text form, so loading settings is just a matter of loadstring("settings.txt")()

2. Yeah, patterns are fun. I have to use bookmarked sites for them half the time. It helps to break them down into individual symbols/sections:

Code:
[[                  ]]
Tells Lua that this is a literal string, so you don't have to use \\s anywhere


Code:
  ^                $
These specify the beginning and end of the string, respectively.


Code:
   @?
The string can start with a single @, but it doesn't have to.


Code:
     (      )
()s tell string.match what part of the string we want to extract.


Code:
      .*
Matches any characters, of any length.


Code:
        [  ]
These define a 'set', so any of the characters in it will be a match.


Code:
         \/
In this case, the set will match either a \ or a /.


The total 'capture', then, translates as:
"Grab the longest string you can that ends with a \ or /"


Code:
             [^\/]-
Another set. Within a set, ^ means 'not', so it will match anything that ISN'T a \ or /. Additionally the - afterward tells it that the match should be as short as possible.

So the entire pattern translates as:

From the beginning of the string, ignoring the @ symbol if it starts with one, grab the longest string you can find that ends with a \ or /.

For example, info.source returns this on my system:
Code:
@C:\Users\Adam\AppData\Roaming\REAPER\Scripts\Lokasenna\misc + testing\display info.source .lua
After matching, that becomes:
Code:
C:\Users\Adam\AppData\Roaming\REAPER\Scripts\Lokasenna\misc + testing\
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 03-10-2017, 09:12 AM   #5
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,458
Default

Thank you very much for the explication and your time!

Regarding external files or ExtState.. I understood that when saving/recalling to/from external files, there are two ways to save/recall depending on the format of my table's indices. Right?

One does not have the same choice when using ExtState? Does it require a special format? What makes it more difficult than external files?
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is online now   Reply With Quote
Old 03-10-2017, 10:14 AM   #6
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

With an external file, you're free to store the data in whatever way you want. ExtStates are just a series of string keys and string values, so you still have to grab each of them and convert them back to numbers, etc if necessary.

ProjExtStates can use retval, keyOutOptional, valOutOptional reaper.EnumProjExtState( proj, extname, idx ) to loop through all of the keys for a given ExtName, which would be essentially the same as the second load method above - each loop would output a new key and value pair.

If it's project-related data, by all means use ProjExtStates.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna 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 09:49 AM.


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