Old 01-31-2019, 08:38 AM   #1
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default Wait Until Next Bar to do an action

Hey guys,

I'm sorry for being a newbie, but I'm trying to learn LUA.

I'm trying to find a way to "wait until the end of current measure" before doing something from within the script using some kind of
Code:
for i = 1
looping function.

Anybody can help me?

Thanks
lexaproductions is offline   Reply With Quote
Old 01-31-2019, 09:18 AM   #2
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Use reaper.defer to schedule a function to be run later (~33ms). Unlike regular loops which freeze REAPER until they stop, reaper.defer allows the GUI to run in between.

Code:
function onNextMeasure(callback)
  local beatsSinceLastMeasure = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
  
  if beatsSinceLastMeasure < 0.1 then
    -- if we're at (or very near) the start of a measure, call the given function
    callback()
  else
    -- or, if we're not at the start of a measure, check again ~33ms later
    reaper.defer(function() onNextMeasure(callback) end)
  end
end

onNextMeasure(function()
  -- code to run at the next measure here
  reaper.ShowConsoleMsg("Hello Next Measure!\n")
end)

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

Or simply put an action in a custom action after SWS: Wait for next bar (if playing) :P (depengind on what function is required of course)
X-Raym is offline   Reply With Quote
Old 01-31-2019, 12:02 PM   #4
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by X-Raym View Post
Or simply put an action in a custom action after SWS: Wait for next bar (if playing) :P (depengind on what function is required of course)
I thought that action was taken out? I can't find it in my action list.
lexaproductions is offline   Reply With Quote
Old 01-31-2019, 12:03 PM   #5
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Do you have http://sws-extension.org/ ?
X-Raym is offline   Reply With Quote
Old 01-31-2019, 12:06 PM   #6
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
Use reaper.defer to schedule a function to be run later (~33ms). Unlike regular loops which freeze REAPER until they stop, reaper.defer allows the GUI to run in between.
My only problem is that I need to use this to kill an already defered script. This Crashed Reaper.

If I test it using Reaper's programming window (Hitting CMS-S to run the script) it works. But if I close the Programming window and try to run the script from a key command. Reaper Crashes upon triggering the other Defered Script.

Any idea?
lexaproductions is offline   Reply With Quote
Old 01-31-2019, 12:07 PM   #7
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by X-Raym View Post
Yes I do.
lexaproductions is offline   Reply With Quote
Old 01-31-2019, 12:13 PM   #8
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Quote:
Originally Posted by lexaproductions View Post
Any idea?
Sounds like a bug (scripts should not be able to cause crashes)! How are you "killing an already defered script", which version of REAPER are you on, and can you post the crash report?

If you're using "ReaScript: Close all running reaScripts" (action 41898), this bug was fixed some time ago: https://forum.cockos.com/showthread.php?t=186699.

Quote:
Originally Posted by lexaproductions View Post
I thought that action was taken out? I can't find it in my action list.
It's only available on Windows.

Last edited by cfillion; 01-31-2019 at 12:32 PM.
cfillion is offline   Reply With Quote
Old 01-31-2019, 01:56 PM   #9
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
If you're using "ReaScript: Close all running reaScripts" (action 41898), this bug was fixed some time ago:
I'm not using that function as I have other scripts running that I don't want to kill at that moment

Quote:
Originally Posted by cfillion View Post
Sounds like a bug (scripts should not be able to cause crashes)!
Well that's what I thought, because I'm pretty novice at this and I don't want to compromise Reaper's stability.

Quote:
Originally Posted by cfillion View Post
which version of REAPER are you on,
I tried Reaper 5.77 and 5.965, same result

Quote:
Originally Posted by cfillion View Post
How are you "killing an already defered script"
I might not have used the right terms when I said "deferred". Here's a full explanation:
I have "Script A" running in the background. It's a window showing the current region in a window.
Then I trigger "Script B" which monitors if "Script A" is running (using GetToggleCommandState), and kills it at the end of current bar. The Way Script A is kill is simple; I just re-instantiate it, and Reaper kills it instead of making a 2nd instance of the script.

The Problem is: When I trigger "Script B", as soon as it kills "Script A", Reaper Crashes. I've confirmed that, if I don't trigger the kill, Reaper doesn't crash.


Quote:
Originally Posted by cfillion View Post
can you post the crash report?
Code:
Process:               REAPER [29796]
Path:                  /Volumes/VOLUME/*/ReaLiveDev.app/Contents/MacOS/REAPER
Identifier:            com.cockos.reaper
Version:               5.96.500 (5.96.500)
Code Type:             X86-64 (Native)
Parent Process:        ??? [1]
Responsible:           REAPER [29796]
User ID:               501

Date/Time:             2019-01-31 15:37:48.833 -0500
OS Version:            Mac OS X 10.11.6 (15G31)
Report Version:        11
Anonymous UUID:        48421833-45CE-0A6E-E670-0E640B1D81D1


Time Awake Since Boot: 770000 seconds

System Integrity Protection: disabled

Crashed Thread:        0  reaper  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000020
Exception Note:        EXC_CORPSE_NOTIFY

VM Regions Near 0x20:
--> 
    __TEXT                 0000000100000000-0000000100ad7000 [ 10.8M] r-x/rwx SM=COW  /Volumes/VOLUME/*/ReaLiveDev.app/Contents/MacOS/REAPER

Global Trace Buffer (reverse chronological seconds):
12.349460    libextension.dylib        	0x00007fff866fa533 tearing down extension request for pid 29799
23.491569    libextension.dylib        	0x00007fff866fa533 tearing down extension request for pid 29799

Thread 0 Crashed:: reaper  Dispatch queue: com.apple.main-thread
0   com.cockos.reaper             	0x00000001006dd41e ReaScript_RunDeferred() + 238
1   com.cockos.reaper             	0x00000001000e067b runMiscTimers() + 1947
2   com.cockos.reaper             	0x00000001000df446 Main_OnTimer(HWND__*, unsigned long) + 166
3   com.cockos.reaper             	0x000000010063ba09 MainProc(HWND__*, unsigned int, unsigned long, long) + 8089
4   ???                           	0x5fbfd33000000001 0 + 6899465357266780161

========================================================>
Crash Log Ending
========================================================>


Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x000000010b188600  rcx: 0x0000000000000000  rdx: 0x0000000000000000
  rdi: 0x0000000108135410  rsi: 0x0000000000000000  rbp: 0x00007fff5fbfbcc0  rsp: 0x00007fff5fbfbc70
   r8: 0x000000010b1c2800   r9: 0x000000000000000a  r10: 0x0000000000234200  r11: 0x0000000000000000
  r12: 0x0000000000000001  r13: 0x0000000000000010  r14: 0x000000010b188608  r15: 0x00000000ffffffff
  rip: 0x00000001006dd41e  rfl: 0x0000000000010246  cr2: 0x0000000000000020
  
Logical CPU:     8
Error Code:      0x00000004
Trap Number:     14


Binary Images:
       0x100000000 -        0x100ad6ff7 +com.cockos.reaper (5.96.500 - 5.96.500) <9096C7B2-2841-2A61-15BB-E7BFCA4059C4> /Volumes/VOLUME/*/ReaLiveDev.app/Contents/MacOS/REAPER
       0x100dc1000 -        0x100df8fff  com.apple.audio.midi.CoreMIDI (1.10 - 88) <51E79766-51D8-3A95-A7FD-18E7E11528F3>
lexaproductions is offline   Reply With Quote
Old 02-04-2019, 06:52 AM   #10
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Hey CF, I was wondering if you had a second to check out my last post?
lexaproductions is offline   Reply With Quote
Old 02-04-2019, 07:24 AM   #11
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Which scripts do you run? We could try to recreate the crash to help the devs fixing it, if we'd know the scripts you use...
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 02-04-2019, 01:32 PM   #12
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Thanks for replying to this.
The scripts I'm using are here:
https://www.dropbox.com/s/h0nh637jbf...Crash.zip?dl=0
Here are my steps:
1- Start the first Script which is a window showing the current Region. This was inspired by a script XRaym Made.
2- Start Playback
3- Forcing a smooth seek to edit cursor (I have it setup to "2 bars")
4- The Seek is initiated but upon arriving to the next bar and executing CFillion's function, The whole thing crashes. You can see the data in the Cap on in one of my previous posts in this thread.

I hope somebody can help me.

Here's a screen Capture.

Last edited by lexaproductions; 02-04-2019 at 01:44 PM. Reason: fixing the screen capture link
lexaproductions is offline   Reply With Quote
Old 02-04-2019, 02:52 PM   #13
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

I've reduced it to the following steps and minimal scripts:
  1. Run Script A.lua:
    Code:
    function loop() reaper.defer(loop) end
    loop()
  2. Run Script B.lua (with the correct command ID for Script A.lua):
    Code:
    reaper.defer(function()
      local cmd = reaper.NamedCommandLookup("command ID of script A here")
      reaper.Main_OnCommand(cmd, 0)
    end)
  3. Select "Terminate instances"

Maybe you could message the main script to terminate itself using a temporary extstate instead of re-running it?

Last edited by cfillion; 02-04-2019 at 03:40 PM.
cfillion is offline   Reply With Quote
Old 02-04-2019, 02:58 PM   #14
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

I'm glad I'm not crazy.

Now I have to understand how to use extstate

I'll file a bug report on the Forum, thanks
lexaproductions is offline   Reply With Quote
Old 02-04-2019, 03:08 PM   #15
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Code:
function runRegionWindow()
  if reaper.HasExtState('lexa_Name of the script', 'exit') then
    reaper.DeleteExtState('lexa_Name of the script', 'exit', false);
    return
  end

  -- rest of the code...
end
Code:
onNextMeasure(function()
  reaper.SetExtState('lexa_Name of the script', 'exit', '', false)
end)
cfillion is offline   Reply With Quote
Old 02-05-2019, 06:19 AM   #16
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Thanks a lot.
It works great
lexaproductions is offline   Reply With Quote
Old 02-20-2019, 06:53 PM   #17
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

I have to fix a small bug though.
If I terminate the script this way, then How should I re-instantiate it?
Because Now I have to instantiate it twice to restart it?
lexaproductions is offline   Reply With Quote
Old 02-20-2019, 09:24 PM   #18
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

That should not be the case. Maybe the script doesn't stop when told to or the ExtState is not deleted? (More info needed)
cfillion is offline   Reply With Quote
Old 02-21-2019, 06:06 AM   #19
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Ok Thanks for the insight. It was my mistake, As the name of the script, I only wrote
Code:
Realive_RegionWindow
but I had to prefix with "Script: " and add the extension as well.

Code:
Script: Realive_RegionWindow.lua
Now it seems to be working.

Thanks a lot for the help. I'm learning everyday slowly but surely.
lexaproductions is offline   Reply With Quote
Old 02-22-2019, 08:20 PM   #20
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

Quote:
Originally Posted by cfillion View Post
I've reduced it to the following steps and minimal scripts:
  1. Run Script A.lua:
    Code:
    function loop() reaper.defer(loop) end
    loop()
  2. Run Script B.lua (with the correct command ID for Script A.lua):
    Code:
    reaper.defer(function()
      local cmd = reaper.NamedCommandLookup("command ID of script A here")
      reaper.Main_OnCommand(cmd, 0)
    end)
  3. Select "Terminate instances"

Maybe you could message the main script to terminate itself using a temporary extstate instead of re-running it?
Thanks, I think I've duplicated this and am working on a fix.
Justin is offline   Reply With Quote
Old 03-09-2019, 07:19 PM   #21
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
Use reaper.defer to schedule a function to be run later (~33ms). Unlike regular loops which freeze REAPER until they stop, reaper.defer allows the GUI to run in between.

[code]function onNextMeasure(callback)
local beatsSinceLastMeasure = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())

if beatsSinceLastMeasure < 0.1 then
-- if we're at (or very near) the start of a measure, call the given function
callback()
else
-- or, if we're not at the start of a measure, check again ~33ms later
reaper.defer(function() onNextMeasure(callback) end)
end
end
Hey CFillion, I realized a bug in the function: If playback is stopped while the function in in the defer loop, it never ends as it never reaches "beatsSinceLastMeasure < 0.1"

I tried this, but it did't work:
Code:
function onNextMeasure(callback)
      local beatsSinceLastMeasure = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
	if playState ~= 0 then
      if beatsSinceLastMeasure < 0.3 then      -- if we're at (or very near) the start of a measure, call the given function
          callback()
      else       -- or, if we're not at the start of a measure, check again ~33ms later
          reaper.defer(function() onNextMeasure(callback) end)
			Msg("BeatsSinceLastMeasure: "..beatsSinceLastMeasure)
      end
	else
		callback()
    end
end
Also, if I retrigger the script while the "onNextMeasure" function is in the defer loop, the loop stops thus once again never reaches the condition to execute the callback function. You have an idea for both conditions?
lexaproductions is offline   Reply With Quote
Old 03-11-2019, 08:48 AM   #22
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Quote:
Originally Posted by lexaproductions View Post
Hey CFillion, I realized a bug in the function: If playback is stopped while the function in in the defer loop, it never ends as it never reaches "beatsSinceLastMeasure < 0.1"
You could check the playback state (reaper.GetPlayState()&1==0) and either do nothing or invoke the callback function when stopped.

Quote:
Originally Posted by lexaproductions View Post
Also, if I retrigger the script while the "onNextMeasure" function is in the defer loop, the loop stops thus once again never reaches the condition to execute the callback function. You have an idea for both conditions?
Is this because the script is set to "Terminate instances" if launched while it's running?
cfillion is offline   Reply With Quote
Old 03-11-2019, 09:18 AM   #23
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
You could check the playback state (reaper.GetPlayState()&1==0) and either do nothing or invoke the callback function when stopped.
Well that's what I tried to do but if you can see in my last example, the way I did it does not work...


Quote:
Originally Posted by cfillion View Post
Is this because the script is set to "Terminate instances" if launched while it's running?
I believe so. But I can't find where to reset it. Where do we change the Terminate instances settings?
lexaproductions is offline   Reply With Quote
Old 03-11-2019, 09:25 AM   #24
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Quote:
Originally Posted by lexaproductions View Post
Well that's what I tried to do but if you can see in my last example, the way I did it does not work...
The playState variable does not appear to be defined (or if it is elsewhere in the script, it's not being updated in the loop).

Code:
function onNextMeasure(callback)
  local beatsSinceLastMeasure = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
  
  if beatsSinceLastMeasure < 0.1 then
    -- if we're at (or very near) the start of a measure, call the given function
    callback()
  else if reaper.GetPlayState()&1 == 1 -- only if the project is playing
    -- or, if we're not at the start of a measure, check again ~33ms later
    reaper.defer(function() onNextMeasure(callback) end)
  end
end

onNextMeasure(function()
  -- code to run at the next measure here
  reaper.ShowConsoleMsg("Hello Next Measure!\n")
end)
Quote:
Originally Posted by lexaproductions View Post
I believe so. But I can't find where to reset it. Where do we change the Terminate instances settings?
Remove and re-import the script in the action list.
cfillion is offline   Reply With Quote
Old 03-11-2019, 09:51 AM   #25
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

playState is defined elsewhere. From what I can tell it works. I'll investigate thanks
lexaproductions is offline   Reply With Quote
Old 03-11-2019, 02:18 PM   #26
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
You could check the playback state (reaper.GetPlayState()&1==0) and either do nothing or invoke the callback function when stopped.



Is this because the script is set to "Terminate instances" if launched while it's running?
Yes it seems to be. But I have no other choice then set it to "Terminate instances" no?
lexaproductions is offline   Reply With Quote
Old 10-07-2020, 07:11 AM   #27
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Bringing back this function as I always wanted to make this more precise and simpler,
I came up with this. CFillion, what do you think?

Code:
function on_NextMeasure(outfunction, timingAdjust)
	local _,curBar = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
-- Polling loop function
	local function on_NextMeasure_Loop(outfunction, timingAdjust)
		if reaper.GetPlayState() == 0 then return end -- if stopped while running abort without doing anything.
		for i = 0, 10000 do -- to poll at 0.03ms precision
			local _, msr = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition()+timingAdjust) -- added 100ms as timing adjust
			if curBar ~= msr then      -- if the measure number changed...
				outfunction()
				return
			end
		end
		reaper.defer(function() on_NextMeasure_Loop(outfunction, timingAdjust) end)
	end
-- Call polling loop function
	on_NextMeasure_Loop(outfunction, timingAdjust)
end
lexaproductions is offline   Reply With Quote
Old 10-07-2020, 08:03 AM   #28
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Code:
for i = 0, 10000 do
reaper.GetPlayPosition() remains the same for all 10,001 iterations (because it freezes the main thread).
cfillion is offline   Reply With Quote
Old 10-07-2020, 09:51 AM   #29
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by lexaproductions View Post
Bringing back this function as I always wanted to make this more precise and simpler,
I came up with this. CFillion, what do you think?

Code:
function on_NextMeasure(outfunction, timingAdjust)
	local _,curBar = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
-- Polling loop function
	local function on_NextMeasure_Loop(outfunction, timingAdjust)
		if reaper.GetPlayState() == 0 then return end -- if stopped while running abort without doing anything.
		for i = 0, 10000 do -- to poll at 0.03ms precision
			local _, msr = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition()+timingAdjust) -- added 100ms as timing adjust
			if curBar ~= msr then      -- if the measure number changed...
				outfunction()
				return
			end
		end
		reaper.defer(function() on_NextMeasure_Loop(outfunction, timingAdjust) end)
	end
-- Call polling loop function
	on_NextMeasure_Loop(outfunction, timingAdjust)
end
All Get-functions of Reaper update their states only when
a) you changed the state programmatically
b) at start of a script
c) at the beginning of each defer-cycle

So defer is still your only option.

But that does not prevent you from having greater precision.

Usually deferred function are run about 30 times per second. Now here's the thing: you can have multiple deferred functions in one script.

The next example will run about 30/second:

Code:
A=0

function main()
  A=A+1
  reaper.ClearConsole()
  reaper.ShowConsoleMsg(A)
  reaper.defer(main)
end

main()
It will count up the global variable A with each defer-cycle and show it in the console.

Now, let's see, what happens when we start main() twice:

Code:
A=0

function main()
  A=A+1
  reaper.ClearConsole()
  reaper.ShowConsoleMsg(A)
  reaper.defer(main)
end

main()
main() -- let's start it another time
You will see, it will count up not only 30 times/second but 60 times/second.
You can go on with it. Start main() three times and it will count up 90 times per second.

The reason is, because you started main(which is deferred) three times, Reaper runs main as three instances as deferred. Each main() is looped as its own instance, who can access the global variable A and therefor count up with each loop.
You can run main() a fourth time and Reaper will fun four instances of main as deferred, and so on.

The great thing about this is, that you can speed up things that way. Usually you could only do it 30times/second but by running multiple instances of the deferred main-function, you can have (number_of_main_instance*30times)/second-iterations.
AND, as I pointed out earlier: the get-functions of Reaper will be updated with each defer-cycle which means: you can get the current time-position more often than only 30/second with this approach.

So let's modify the code from above to do that:

Code:
function main()
  playposition=reaper.GetPlayPosition()  
  reaper.ShowConsoleMsg(playposition.."\n")
  reaper.defer(main)
end

main()
This will show the current playposition in the console. It will update it 30 time/second.

Code:
function main()
  playposition=reaper.GetPlayPosition()  
  reaper.ShowConsoleMsg(playposition.."\n")
  reaper.defer(main)
end

main()
main() -- run the main-function as a second defer-instance
When we run main two times, the console will show the playposition 60 times/second. And each one shown will be different and not block Reaper's GUI(unlike your democode that tried to achieve this with a for-loop).

You can run the main-loop for 1024-times and create therefor 1024 instances of the function. Though I think, running main() 10 times should be enough precision, with 300 times per second, as more instances may eat too many resources slowing down the instances at some point. So test out the balance between number of defer-main()-instances running vs needed computing resources.
Rule of thumb: if you have the feeling of Reaper's GUI becoming sluggish, laggy or not precisely reacting, you should start fewer instances of your check-function.

That being said: try to solve it as a defer-looped-function and then run this defer-function multiple times and you'll get greater check-precision.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...

Last edited by Meo-Ada Mespotine; 10-07-2020 at 09:56 AM.
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-07-2020, 10:16 AM   #30
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Deferred functions are run from the same global timer no matter how many of them are queued. It does not increase resolution.

Code:
i = 0
t = reaper.time_precise()

function callback()
  i = i + 1

  new_t = reaper.time_precise()
  diff = new_t - t
  t = new_t

  reaper.ShowConsoleMsg(string.format('%fms since the previous call\n', diff * 1000))
  
  if i <= 3*3 then
    reaper.defer(callback)
  end
end

reaper.defer(callback)
reaper.defer(callback)
reaper.defer(callback)
Code:
23.468971ms since the previous call
0.524998ms since the previous call
0.306129ms since the previous call
29.727936ms since the previous call
0.660896ms since the previous call
0.554085ms since the previous call
28.505087ms since the previous call
0.995874ms since the previous call
0.833035ms since the previous call
28.582096ms since the previous call
1.338005ms since the previous call
1.116991ms since the previous call

Last edited by cfillion; 10-07-2020 at 10:29 AM.
cfillion is offline   Reply With Quote
Old 10-07-2020, 10:38 AM   #31
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

I'm not sure, how your benchmark-function is supposed to work, but I think that reaper.time_precise() is not a good example, as this function is the only one that gets updated all the time, even during script-run.
To see the effect, you would need to take a function, that gets only updated with each defer-cycle, like GetPlayPosition or something like that.

Edit: I have multiple features in Ultraschall-API working with this effect circumventing the Gui-block-problem.


Edit2: I think I forgot to mention another thing: the first run of the (not yet deferred)-main-function will NOT benefit from it.
The precision will only benefit from the first time it has been deferred(second run onward).
This could maybe explain some of the effects shown in your code, that is probably influenced by the stop-variable i.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...

Last edited by Meo-Ada Mespotine; 10-07-2020 at 10:51 AM.
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-07-2020, 10:49 AM   #32
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

It was meant to demonstrate that all calls to reaper.defer go into the same queue served by a single global timer, which then executes all of them synchronously (so the main thread cannot update in-between).

With GetPlayPosition:

Code:
33.976854
33.976854
33.976854
34.008854
34.008854
34.008854
34.040854
34.040854
34.040854
34.072854
34.072854
34.072854
34.104854
34.104854
34.104854
In other words, these two blocks are equivalent:
Code:
reaper.defer(callback)
reaper.defer(callback)
reaper.defer(callback)

reaper.defer(function()
  callback()
  callback()
  callback()
end)

Last edited by cfillion; 10-07-2020 at 10:56 AM.
cfillion is offline   Reply With Quote
Old 10-07-2020, 10:52 AM   #33
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Just in case, this got swept under:

Quote:
Originally Posted by Meo-Ada Mespotine View Post
Edit2: I think I forgot to mention another thing: the first run of the (not yet deferred)-main-function will NOT benefit from it.
The precision will only benefit from the first time it has been deferred(second run onward).
This could maybe explain some of the effects shown in your code, that is probably influenced by the stop-variable i.
It's so normal to me, that I simply forgot to mention that...
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-07-2020, 11:03 AM   #34
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

@cfillion
Ok, I can confirm you're right.

Code:
reaper.ClearConsole()
OldPos=0
A=0
NumberOfInstances_and_WaitTilShowing=5

function main()
  A=A+1
  local NewPos=reaper.GetPlayPosition()
  if A>NumberOfInstances_and_WaitTilShowing then
    reaper.ShowConsoleMsg(NewPos.."\n")
  end
  OldPos=NewPos
  if A<NumberOfInstances_and_WaitTilShowing*120 then
    reaper.defer(main)
  end
end


for i=1, NumberOfInstances_and_WaitTilShowing do
  main()
end
If my assumption would be correct, every shown time would be different, but instead is shown NumberOfInstances_and_WaitTilShowing -times (in this code 5 times).

So it seems like Reaper updates its states only after every "full-gui-and-defer-script-turnaround", while it seems to be more flexible in other regards(Lua's file-io for instance).

Thnx for pointing this out...

@lexaproductions

I was wrong, no greater precision possible. I wonder, if using gmem being fed by a JSFX could be a possible workaround, but this would be hacky if at all possible.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-07-2020, 01:58 PM   #35
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Thanks fro taking the time to answer my questions guys. I really appreciate it.
I could've sworn using this function felt tighter. Might be placebo effect hehe.

Back to the drawing board.
lexaproductions is offline   Reply With Quote
Old 10-07-2020, 03:57 PM   #36
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

But hearing you guys talk about
Code:
time_precise()
still being updated would that work?



Code:
function on_NextMeasure(outfunction)
	local timingAdjust = 0
        local _, msr = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
	local barSt, barEnd = reaper.TimeMap_GetMeasureInfo(0, msr)
	local barEnd_precise = barEnd-position+reaper.time_precise()
	local _,curBar = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
-- Polling loop function
	local function on_NextMeasure_Loop(outfunction, timingAdjust)
		if reaper.GetPlayState() == 0 then return end -- if stopped while running abort without doing anything.
		for i = 0, 10 do
			local t = reaper.time_precise()
			if t >=barEnd_precise then      -- if the measure number changed...
				outfunction()
				return
			end
		end
		reaper.defer(function() on_NextMeasure_Loop(outfunction, timingAdjust) end)
	end
-- Call polling loop function
	on_NextMeasure_Loop(outfunction, timingAdjust)
end
lexaproductions is offline   Reply With Quote
Old 10-07-2020, 05:37 PM   #37
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by lexaproductions View Post
But hearing you guys
...and girls

Quote:
talk about
Code:
time_precise()
still being updated would that work?



Code:
function on_NextMeasure(outfunction)
	local timingAdjust = 0
        local _, msr = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
	local barSt, barEnd = reaper.TimeMap_GetMeasureInfo(0, msr)
	local barEnd_precise = barEnd-position+reaper.time_precise()
	local _,curBar = reaper.TimeMap2_timeToBeats(0, reaper.GetPlayPosition())
-- Polling loop function
	local function on_NextMeasure_Loop(outfunction, timingAdjust)
		if reaper.GetPlayState() == 0 then return end -- if stopped while running abort without doing anything.
		for i = 0, 10 do
			local t = reaper.time_precise()
			if t >=barEnd_precise then      -- if the measure number changed...
				outfunction()
				return
			end
		end
		reaper.defer(function() on_NextMeasure_Loop(outfunction, timingAdjust) end)
	end
-- Call polling loop function
	on_NextMeasure_Loop(outfunction, timingAdjust)
end
No, as the other Api-functions still don't return updated values. And for-loops always block Reaper's Gui after some time, no matter what. Time_precise will not be helpful for your needs.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-07-2020, 07:51 PM   #38
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
...and girls
Thanks Miss.
lexaproductions 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 12:43 AM.


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