Old 08-01-2021, 07:04 PM   #1
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default Runloop and defer is derferring my head in!

Seriously. Pun intended. It's really been doing my head in. !@#$

So I found I need to defer some code while waiting for an event to happen. But because of the cooperative multitasking nature of ReaScripts I've found it hard to put in a simple delay line because it doesn't work that way. Like others I expected defer() to work instantly and put the code on hold. Only to find it doesn't work that way. I suppose it's called defer for a reason and not instant. ;-)


I've read through the mespotine guide (TIA) about five times and soon it will be ten times. I think I finally get it now. I was confused by it running the code to the end after the defer. Then all defers after that being isolated to the routine calling it. Now I think I can make sense of it. The entire block of code must be executed on each defer from where Reaper starts it. If coming from main() then it must come back to it. If restarted from a defer location then the block is isolated to that routine so when that routine ends the script effectively ends until the next iteration. If I have understood it correctly.


Now here is where I am stuck. My need is for normal program flow. Setting up in main(). Calling a function that needs to wait for an event and return a value. Then coming back and continuing on in main(). The problem is a defer is needed to wait. But it disrupts the program flow. Effectively pulling the rug out. The waiting function would open some things it needs before it waits. But they could fail. So it needs to return success or fail. The problem here is that a defer is needed for the waiting. But the routine must return back immediately regardless. Because the defer needs to occur after the whole code block executes. After that routines exits. And this is where I'm stuck.



See, a top function deferring doesn't know where it was called from. Nor do I see any way for it to return. It would be handy here if there was a pause() function that suspended the script instead but there isn't. FR maybe? Yes I tried sleep() knowing full well what the consequences were. Lol. My main issue then is that I cannot stack the return address. And yes I am now thinking at the ASM level. I need to stack where my routine is called from so I can return back it. Either a defer or direct function call. But I can't do that either AFAIK.



I'm totally stuck on how to proceed. I have a simple flowing need in my program that's standard across the board. But I just can't see a way to solve it without jumping through hoops. And adding flags or checking functions. Because main() will be looped through before any waiting can even begin. I can only think that it would need to be coded in such a way as being aware that main() will be looped over and over and a simple function returning a result is not possible. Because such a function cannot be encapsulated in this manner. So would need to be divided into a set of open, check and close functions.

How would you guys solve a simple problem that is complicated by a deferring?


For reference the mespotine guide:
https://forum.cockos.com/showpost.ph...2&postcount=21


Long thread with exactly what I'm facing:
https://forum.cockos.com/showthread....ighlight=defer
Hypex is offline   Reply With Quote
Old 08-01-2021, 10:23 PM   #2
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Maybe explain task with details, and it can be solved in a esier way?
mpl is offline   Reply With Quote
Old 08-02-2021, 01:49 AM   #3
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default

In a nutshell what my script would be doing is opening up a named FX into a floating window. Then waits the floating window to be closed. Opening FX as floating and checking if it is floating is easy enough to do. But waiting for it to close is harder.


Plus I wanted to create a function library so I could just include it in. Then call one function with the FX name to do it all for me. But by the looks of it I will need to split it up.


Possible uses are scripting a few FX windows to be quickly edited in a row. Such as having a small script that can open them up one at a time by just calling one function.


Example code:
Code:
@import FloatyFX-Include.eel


function main()
(
  EditFloatyFX("Some delay");
  EditFloatyFX("Some reverb");
 );
Expected code:
Code:
 function main()
(
  // Complicated defer aware loop here...
);
Hypex is offline   Reply With Quote
Old 08-02-2021, 06:27 AM   #4
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

A "defer aware loop" is not possible.

You need to think the other way round.

A script is not allowed to "loop". It needs to quickly do its thing and return.
That is because all scripts (and the GUI and...) all run on the same OS thread one after the other and never in parallel, nor intercepting each other. Hence a loop in a script would stall Reaper completely.

So your algorithm needs to be a "state machine". It needs to hold a set of variables to define a "state". Each run might modify the state and return. The next run then acts according to that state.

Each run is triggered by something calling the appropriate action or by "defer" from the script itself.

-Michael

Last edited by mschnell; 08-02-2021 at 12:14 PM.
mschnell is offline   Reply With Quote
Old 08-02-2021, 11:46 PM   #5
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default

Quote:
Originally Posted by mschnell View Post
A "defer aware loop" is not possible.

You need to think the other way round.

A script is not allowed to "loop". It needs to quickly do its thing and return.

What I meant was, a defer aware main loop, where it's aware that main() will be restarted again and looped over. Not a self perpetuating loop as it looked like.



Quote:
So your algorithm needs to be a "state machine". It needs to hold a set of variables to define a "state". Each run might modify the state and return. The next run then acts according to that state.

Each run is triggered by something calling the appropriate action or by "defer" from the script itself.

This is what I expected. At first I tried to instantly defer main() but it failed as main() didn't get called. I also tried running counters so main() was deferred after another routine but that failed as well since it needs to work bottom up regardless. It explains why my original code kept dropping out.



So I will attempt to make it as simple as possible. It won't be as simple as I wanted it to be. But I should be able to build some steps to reduce the process as much as I can.


Thanks.
Hypex is offline   Reply With Quote
Old 08-03-2021, 12:14 AM   #6
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Code:
function msg(s) reaper.ShowConsoleMsg(s..'\n') end 

function main() 
  pscc = reaper.GetProjectStateChangeCount( 0 )
  if last_pscc and last_pscc ~= pscc then DoStuffAtProjectStateChange() end
  last_pscc = pscc
  reaper.defer(main)
end
---------------------------------------------
function InitAddFX(fxname)
  data = {}
  local tr= reaper.GetSelectedTrack(0,0)
  if tr then 
    local ret = reaper.TrackFX_AddByName( tr, fxname, false, 1 )
    if ret ~= -1 then 
      reaper.TrackFX_Show( tr, ret, 3 )
      data = {trGUID = reaper.GetTrackGUID( tr ),
              fxid =ret}
            end
  end
  
end
---------------------------------------------
function DoStuffAtProjectStateChange()
  if not data.trGUID then return end
  for i = 1, reaper.CountTracks(0) do
    local track = reaper.GetTrack(0,i-1)
    GUID = reaper.GetTrackGUID( track )
    if GUID == data.trGUID then
      isopen = reaper.TrackFX_GetOpen( track, data.fxid )
      if not isopen then 
        msg('FX closed')
      end
    end
  end
  
end


InitAddFX('ReaEQ')
main()

You can deal with {data} for example. To manipulate multiple FX states.
mpl is offline   Reply With Quote
Old 08-03-2021, 08:19 AM   #7
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default

Quote:
Originally Posted by mpl View Post
You can deal with {data} for example. To manipulate multiple FX states.

Thanks for your example. I see you also called a function before main to set it up. a method I have considered. It could help to keep a cleaner flow and looks like a useful method.
Hypex is offline   Reply With Quote
Old 08-03-2021, 11:19 AM   #8
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

OK, mpl already gave you an example of how to do what you want. But if you need more examples, look into my MFXlist script (https://forum.cockos.com/showthread.php?t=248411). I do exactly what you describe, keep track of floating FX windows and act on them being closed by the user.
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 08-05-2021, 01:33 AM   #9
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default

Quote:
Originally Posted by Fabian View Post
OK, mpl already gave you an example of how to do what you want. But if you need more examples, look into my MFXlist script (https://forum.cockos.com/showthread.php?t=248411). I do exactly what you describe, keep track of floating FX windows and act on them being closed by the user.

Thanks also. Fabulous. I see a trend with doing setup before it hits main() which looks like a good idea. I also need to take into account that any setup can fail along the line.


I see you reference preset_file_init on the bottom of the script but don't see it referenced elsewhere. I don't know if this is a Lua quirk of creating it automatically. But I don't see it used elsewhere.
Hypex is offline   Reply With Quote
Old 08-05-2021, 11:08 AM   #10
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

Quote:
Originally Posted by Hypex View Post
Thanks also. Fabulous. I see a trend with doing setup before it hits main() which looks like a good idea. I also need to take into account that any setup can fail along the line.


I see you reference preset_file_init on the bottom of the script but don't see it referenced elsewhere. I don't know if this is a Lua quirk of creating it automatically. But I don't see it used elsewhere.
The preset_file_init is set in the preset file when/if that file is run. So to set the presets, the preset file is run and it first sets up the customized settings and then calls MFXlist.

There's an explanation of this under the Customization heading on github https://github.com/martinfabian/MFXlist You also fin the MFXpreset.lua there so you can see how that works.
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 08-06-2021, 02:21 AM   #11
Hypex
Human being with feelings
 
Join Date: Mar 2015
Location: Australia
Posts: 451
Default

Quote:
Originally Posted by Fabian View Post
The preset_file_init is set in the preset file when/if that file is run. So to set the presets, the preset file is run and it first sets up the customized settings and then calls MFXlist..

Ok thanks, yes I somehow managed to miss that slight detail. I spent more time reading the script than the instructions. Helps to know what you are reading about. :-)


Well, I've managed to get a code draft working. Now got lots of test routines I should delete. It's still slightly complicated as one routine defers another that checks in a defer loop and then drops to main(). Might be able to simplify it but the code in main() to manage it is small and clean enough so it's not a big deal.
Hypex 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 06:01 AM.


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