Old 11-29-2018, 08:13 PM   #1
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default Reascript Global Memory?

Hello forum,

I'm hoping someone can shine some light on this: Is there a way to access (read/write) global reascript memory. I'm desperately looking for a solution to share a few objects between multiple deferred scripts, and seem to be killing my system reading/writing from extstate.

I found a post discussing gmem[] specifically in JS/OSCIIBOT, but am interested if there is the equivalent in reascript, there's no mention within the API.

Post in question:
https://forum.cockos.com/showthread.php?t=181580

Thanks for any info!
ausbaxter is offline   Reply With Quote
Old 11-30-2018, 03:53 AM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Untested, but from prerelease:


Code:
v5.961+dev1029 - October 29 2018   + ReaScript: add reaper.gmem_attach()/gmem_read()/gmem_write() to Lua for interacting with JSFX/Video Processors/EEL2 ReaScripts gmem[] segments
I wonder if this works through different ReaScripts or only between JSFX and ReaScripts.
X-Raym is offline   Reply With Quote
Old 11-30-2018, 05:45 AM   #3
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Yes, it works for anything.
mpl is offline   Reply With Quote
Old 12-01-2018, 08:01 AM   #4
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,889
Default

As I understand it, EEL ReaScripts have had gmem for a long time. The upcoming pre stuff is just for interaction between JSFX and ReaScripts.

https://www.cockos.com/EEL2/index.php#basic (5th and 6th bullet points)

I've never actually used it in a script though. Don't know if Lua and Python have anything similar.
IXix is offline   Reply With Quote
Old 02-24-2019, 05:37 PM   #5
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Has anyone a small code snippet to share to show the usage of this functions ? Not sure to understand the difference between attach and read and how to pass string values.
X-Raym is offline   Reply With Quote
Old 02-24-2019, 10:12 PM   #6
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Quote:
Originally Posted by X-Raym View Post
Not sure to understand the difference between attach and read and how to pass string values.
Easiest example here: https://forum.cockos.com/showthread.php?t=217291
You can`t pass strings, only floats. But I guess you can pass strings as character codes (would be nice to share strings though!).

http://reaper.fm/sdk/js/basiccode.php#op_gmem:

Quote:
If 'gmem' is specified as the left parameter to the brackets, then the global shared buffer is used, which is approximately 1 million (1,048,576) slots that are shared across all instances of all JSFX effects.
So if you not define name of the buffer, it makes that simply a global buffer with no name.
Quote:
The plug-in can also specify a line (before code sections):
options:gmem=someUniquelyNamedSpace which will make gmem[] refer to a larger shared buffer, accessible by any plugin that uses options:gmem=<the same name>.
It is gmem.attach in Lua. Other words you can have multiple global buffers, each of those should have a unique name (which it referenced by).
Quote:
So, if you have a single plug-in, or a few plug-ins that access the shared namespace, they can communicate without having to worry about other plug-ins. This option also increases the size of gmem[] to be 8 million entries (from the default 1 million). -- REAPER 4.6+

Last edited by mpl; 02-24-2019 at 10:25 PM.
mpl is offline   Reply With Quote
Old 02-24-2019, 10:22 PM   #7
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

JSFX:
Code:
desc:test_plug
options:gmem=test_name

@init
  gmem[1] = 1;
ReaScript:
Code:
gmem_attach('test_name')
test_output = gmem_read(1)
mpl is offline   Reply With Quote
Old 02-24-2019, 10:23 PM   #8
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Storing null-terminated strings:
Code:
function gmem_write_string(index, value)
  for c in value:gmatch('.') do
    reaper.gmem_write(index, string.byte(c))
    index = index + 1
  end

  reaper.gmem_write(index, 0)
end

function gmem_read_string(index)
  local chars = {}

  while true do
    local value = reaper.gmem_read(index)
    if value == 0 then break end

    table.insert(chars, string.char(value))
    index = index + 1
  end

  return table.concat(chars)
end
JSFX equivalent:
Code:
desc:Storing strings in global memory space
version:1.0
author:cfillion
options:gmem=some_namespace

@block
function gmem_write_string(index, value) local(offset) (
  offset = 0;

  loop(strlen(value),
    gmem[index] = str_getchar(value, offset);
    offset += 1;
    index += 1;
  );
  
  gmem[index] = 0;
);

trigger ? gmem_write_string(0, "foo");

@gfx
function gmem_read_string(index, output) local(offset, buf) (
  offset = 0;
  buf = #;

  while (
    gmem[index] ? (
      str_setchar(buf, offset, gmem[index]);
      offset += 1;
      index  += 1;
    ) : 0;
  );
  
  strcpy_substr(output, buf, 0, offset); // truncates the output
);

gfx_r = gfx_g = gfx_b = 1;
gfx_x = 0;

str = #;
gmem_read_string(0, str);
gfx_drawstr(str);

Last edited by cfillion; 02-24-2019 at 10:33 PM.
cfillion is offline   Reply With Quote
Old 02-25-2019, 02:24 AM   #9
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Ok thanks for the code !




Here is a demo with write from ReaScript to Video Processor:


Code:
reaper.gmem_attach('testname')
function gmem_write_string(index, value)
  for c in value:gmatch('.') do
    reaper.gmem_write(index, string.byte(c))
    index = index + 1
  end

  reaper.gmem_write(index, 0)
end

function Main()
  gmem_write_string(0, tostring(reaper.GetCursorPosition()) )
  reaper.defer(Main)
end

Main()

Code:
// JT: Essential Text Overlay
 //@gmem=testname
 
function gmem_read_string(index, output) local(offset, buf) (
  offset = 0;
  buf = #;

  while (
    gmem[index] ? (
      str_setchar(buf, offset, gmem[index]);
      offset += 1;
      index  += 1;
    ) : 0;
  );
  
  strcpy_substr(output, buf, 0, offset); // truncates the output
);


gmem_read_string(0, text); // set to string to override

text=gmem[0];
font="Futura";

//@param1:size 'Text height' 0.1 0.01 0.3 0.1 0.01
//@param2:xpos 'X position' 0.5 -0.5 1.5 0.5 0.01
//@param3:ypos 'Y position' 0.5 -0.5 1.5 0.5 0.01

//@param5:txtr 'Text R' 1 0 1 0.5 0.01
//@param6:txtg 'Text G' 1 0 1 0.5 0.01
//@param7:txtb 'Text B' 1 0 1 0.5 0.01
//@param8:fga 'Text opacity' 1 0 1 0.5 0.01

//@param10:border 'BG Size' 0.25 -0.5 15 2 0.25
//@param11:bgred 'BG R' 0 0 1 0.5 0.01
//@param12:bggreen 'BG G' 0 0 1 0.5 0.01 
//@param13:bgblue 'BG B' 0 0 1 0.5 0.01 
//@param14:bga 'BG opacity' 0 0 1 0.5 0.01

gfx_blit(0,1);
gfx_setfont(size*project_h,font);
gfx_str_measure(text,txtw,txth);
yt = (project_h- txth*(1+border*2))*ypos;

gfx_r=(bgred);
gfx_g=(bggreen);
gfx_b=(bgblue);
gfx_set(bgred,bggreen,bgblue,bga);
gfx_fillrect(0, yt, project_w, txth*(1+border*2));

gfx_r=(txtr);
gfx_g=(txtg);
gfx_b=(txtb);
gfx_set(txtr,txtg,txtb,fga);
gfx_str_draw(text,xpos * (project_w-txtw),yt+txth*border);

But note that Video Processor is really unefficient for this. As explain in the video processor doc:


Quote:
Note that when synchronizing with ReaScripts or JSFX, all processing is asynchronous, so your code will have to deal with synchronization issues (including vast differences between project_time and playback_position, and including race conditions).

Even getting something like playstate or curpos fails if playstate == stop.




Too bad... This is makes poorly reliable. Same with play state which is even more problematic.

X-Raym is offline   Reply With Quote
Old 02-25-2019, 02:56 AM   #10
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

reaper.GetCursorPosition() is already a number, so it can be stored directly: reaper.gmem_write(0, reaper.GetCursorPosition()).

Code:
gmem_read_string(0, text);
text=gmem[0];
The second line sets text to point to a different string slot depending on the value in gmem[0] (first character). So what is being displayed later isn't always the same string slot that gmem_read_string wrote into.

However most of the time the frame will be drawn before the script can update gmem (and updating gmem doesn't trigger a redraw).

Last edited by cfillion; 02-25-2019 at 03:31 AM.
cfillion is offline   Reply With Quote
Old 02-25-2019, 04:27 AM   #11
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Quote:
reaper.GetCursorPosition() is already a number, so it can be stored directly: reaper.gmem_write(0, reaper.GetCursorPosition()).
I was testing other things as well (like getting markers etc) :P



Quote:
However most of the time the frame will be drawn before the script can update gmem (and updating gmem doesn't trigger a redraw).
Yes, this is the main issue here, though the error happens a bit less more with your fix, but it is still not reliable enough. It can display "1" for record/play state despite the fact it is not.


Priority issue...
X-Raym 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 11:58 AM.


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