Go Back   Cockos Incorporated Forums > REAPER Forums > ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum

Reply
 
Thread Tools Display Modes
Old 11-21-2011, 03:25 PM   #1
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default Python command to enable "consolidate undo points" within a ReaScript

Is there a Python command I can use in a ReaScript to consolidate undo points?

I read that one way is to place the script into a custom action, but surely it makes sense to have this option natively within the API.


======================= UPDATE =======================
spk77 kindly supplied a working script, see post #35 below

================================================== ====

All the best,
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]

Last edited by daxliniere; 06-22-2013 at 02:09 AM.
daxliniere is offline   Reply With Quote
Old 11-21-2011, 03:36 PM   #2
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

There are Undo_BeginBlock2 and Undo_EndBlock2.

Still I found the undo behavior with ReaScript somewhat odd, if not buggy with certain scripts of mine. Too hard to describe, but eg I have a script that doesn't call any Reaper actions, but still sets two undo points, even with those undo block functions added. I had to use at least one Main_OnCommand function to stop it doing that.
gofer is offline   Reply With Quote
Old 11-21-2011, 04:04 PM   #3
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Thanks Gofer, much appreciated.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 11-21-2011, 04:39 PM   #4
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Hi Gofer,
Could you help me out again?
What would be the correct syntax for this;

Code:
MoveCursor = 40513
OffsetCursorToLeft = 53617    #SWS: Move cursor left by default fade length
SplitItems = 40012


selItems = RPR_CountSelectedMediaItems(0)

RPR_Main_OnCommand(MoveCursor, 0)

if (selItems!=0):
  Undo_BeginBlock2
  RPR_Main_OnCommand(OffsetCursorToLeft, 0)
  RPR_Main_OnCommand(SplitItems, 0)
  Undo_EndBlock2
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 11-22-2011, 02:05 AM   #5
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Ok. But it won't be perfect, as I am actually finding my ways through trial and error myself and am by no means a code wizard .

First, when you call extension actions, you need to use the Custom ID string (an internal unique name of each extension action) and convert it into the CmdId integer with RPR_NamedCommandLookup. The CmdId integers for extension actions are given dynamically at start-up by Reaper, so they can change and won't be the same for everyone.

Then, with ReaScript each API function needs the RPR_ prefix. Very easy to forget that when copy/pasting from the API functions list.

And, both undo block functions need an argument. For Undo_BeginBlock2 it's pointing at the project tab (0 for current active project tab). For Undo_EndBlock2 it's that same project tab number, then a string that can give the undo point a name (that's supposed to come up in the undo history, the undo display in the menu header will always just call it "ReaScript: run" in my experience) The third argument of Undo_EndBlock2 is described as "extra flags"- I have no idea about that one and it might be a clue to the problems I have with ReaScript undos.

Here is your script as I would probably do it:

Code:
MoveCursor = 40513
SplitItems = 40012
OffsetCursorToLeft =  RPR_NamedCommandLookup('_SWS_MOVECURFADELEFT')

RPR_Undo_BeginBlock2(0)

selItems = RPR_CountSelectedMediaItems(0)

RPR_Main_OnCommand(MoveCursor, 0)

if (selItems!=0):
  RPR_Main_OnCommand(OffsetCursorToLeft, 0)
  RPR_Main_OnCommand(SplitItems, 0)
  
RPR_Undo_EndBlock2(0,"Your action name",0)

#-
For some reason the undo point name is only used if a split was performed. Oh well, hopefully someone else can shed some light...

Are you sure you want it to split at play cursor if playback is running? Maybe you rather want to use one of the "Split items at edit cursor" flavors?


Hope this helps
gofer is offline   Reply With Quote
Old 11-22-2011, 08:25 PM   #6
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Thanks again, Gofer, I really appreciate giving me your time for this.
I can't remember why, but there was a reason I went with split on playcursor instead of edit cursor. Hmmm, I'll have another look into it.

Cheers, mate!
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 11-26-2011, 04:25 AM   #7
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Gofer,
I think you are right, that code doesn't seem to always consolidate undo points, for some reason.

Perhaps a dev could chime in a let us know what we're doing wrong?
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 12-20-2011, 01:20 PM   #8
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

guys, about undo: I think you should rather use Undo_EndBlock2(NULL, "Undo point name", -1) where -1 is internally represented as 0xFFFFFFFF which is a bitmask defined as "UNDO_STATE_ALL" in the SDK.
From my little experience, a bad usage of this parameter can lead to unpredictable things, like some sort of "delayed crashes" (beachball occuring after the user undos several other things).
It is a bitmask, so using UNDO_STATE_ALL will not be optimized but will always work and it will be safer.

About the script above which creates an undo point "sometimes": it only moves the cursor when no split is perfomred (via native action and/or SWS/SetEditCurPos()) and this is a "special" case: no undo point unless the related preference is enabled (default: disabled).
Jeffos is offline   Reply With Quote
Old 12-20-2011, 02:44 PM   #9
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Dang! I tried some numbers there but not -1 of all things. Looking into that next chance.

Many thanks for chiming in
gofer is offline   Reply With Quote
Old 12-20-2011, 03:30 PM   #10
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

re-thinking to that.. 0 does not make sense for this parameter, so I bet 2 euros that Cockos replaces your 0 with -1 behind the scene anyway
Jeffos is offline   Reply With Quote
Old 12-20-2011, 04:18 PM   #11
WyattRice
Human being with feelings
 
WyattRice's Avatar
 
Join Date: Sep 2009
Location: Virginia
Posts: 2,068
Default

Wow, thanks for sharing the undo tip. I just did a test, and it worked. Cheers to -1
__________________
DDP To Cue Writer. | DDP Marker Editor.
WyattRice is offline   Reply With Quote
Old 12-22-2011, 06:18 AM   #12
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Quote:
Originally Posted by Jeffos View Post
guys, about undo: I think you should rather use Undo_EndBlock2(NULL, "Undo point name", -1)
Hey Jeffos,
Thanks for that, but I still don't get the defined undo point's name appearing in the Undo list, only "ReaScript: run"


Here's my updated Cut Tool script:
Code:
SelectItemUnderCursor = 40528
DeselectItems = 40289
MoveCursor = 40513
SplitItems = 40012
OffsetCursorToLeft = RPR_NamedCommandLookup('_SWS_MOVECURFADELEFT')
OffsetCursorToRight = RPR_NamedCommandLookup('_SWS_MOVECURFADERIGHT')

RPR_Undo_BeginBlock2(0)

selItems = RPR_CountSelectedMediaItems(0)

RPR_Main_OnCommand(MoveCursor, 0)

if (selItems==0):
  RPR_Main_OnCommand(SelectItemUnderCursor, 0)
  RPR_Main_OnCommand(OffsetCursorToLeft, 0)
  RPR_Main_OnCommand(SplitItems, 0)
  RPR_Main_OnCommand(OffsetCursorToRight, 0)
  RPR_Main_OnCommand(DeselectItems, 0)

if (selItems!=0):
  RPR_Main_OnCommand(OffsetCursorToLeft, 0)
  RPR_Main_OnCommand(SplitItems, 0)
  RPR_Main_OnCommand(OffsetCursorToRight, 0)

RPR_Undo_EndBlock2(0,"Split item(s)",-1)
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 12-22-2011, 06:21 AM   #13
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Hold your horses, -1 doesn't quite do the trick.

If you perform the same action several times in a row (i.e. not interrupted with other actions), when you perform an undo, it undoes the work of ALL those actions AND there is no redo.

However, the undo history does show the user-defined script name after you undo...
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 12-23-2011, 03:56 AM   #14
Breeder
Human being with feelings
 
Breeder's Avatar
 
Join Date: Nov 2010
Posts: 2,436
Default

Quote:
Originally Posted by daxliniere View Post
Hold your horses, -1 doesn't quite do the trick.

If you perform the same action several times in a row (i.e. not interrupted with other actions), when you perform an undo, it undoes the work of ALL those actions AND there is no redo.

However, the undo history does show the user-defined script name after you undo...
I'm still a python newb and not next to my computer to test it but it seems to me your script lacks RPR_Undo_EndBlock2 at the end.
Breeder is offline   Reply With Quote
Old 12-23-2011, 04:28 AM   #15
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Quote:
Originally Posted by Breeder View Post
...it seems to me your script lacks RPR_Undo_EndBlock2 at the end.
:blink: Nope, it's definitely there.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 12-23-2011, 07:35 AM   #16
Anton9
Human being with feelings
 
Anton9's Avatar
 
Join Date: Jun 2009
Location: Earth
Posts: 1,340
Default

Quote:
Originally Posted by daxliniere View Post
Hold your horses, -1 doesn't quite do the trick.

If you perform the same action several times in a row (i.e. not interrupted with other actions), when you perform an undo, it undoes the work of ALL those actions AND there is no redo.

However, the undo history does show the user-defined script name after you undo...
I can't test it right now.., but try waiting a few seconds between each execution and then see if that gives you an undo point for each execution.
Anton9 is offline   Reply With Quote
Old 12-24-2011, 06:09 PM   #17
klankschap
Human being with feelings
 
Join Date: Feb 2007
Posts: 99
Default

Code:
MoveCursor = 40513
SplitItems = 40012
OffsetCursorToLeft =  RPR_NamedCommandLookup('_SWS_MOVECURFADELEFT')

RPR_Undo_BeginBlock2(0)

selItems = RPR_CountSelectedMediaItems(0)

RPR_Main_OnCommand(MoveCursor, 0)

if (selItems!=0):
  RPR_Main_OnCommand(OffsetCursorToLeft, 0)
  RPR_Main_OnCommand(SplitItems, 0)
  
RPR_Undo_EndBlock2(0,"Your action name",0)

#-
Just wondering, why not defining a lambda function with the intended name, instead of using an alias for the instruction code.

Code:
moveCursor = lambda : RPR_Main_OnCommand(40513, 0)
splitItems = lambda : RPR_Main_OnCommand(40012, 0)
offsetCursorToLeft = lambda : RPR_Main_OnCommand(RPR_NamedCommandLookup('_SWS_MOVECURFADELEFT'), 0)
undoBeginBock = lambda : RPR_Undo_BeginBlock2(0)
undoEndBlock = lambda name : RPR_Undo_EndBlock2(0,name,0)


undoBeginBock()
moveCursor()
if RPR_CountSelectedMediaItems(0):
  offsetCursorToLeft()
  splitItems()
undoEndBlock( 'your action name' ) 

#-
It could make sense to have a cockos defined .py file which is automatically included with all these lambda / function definitions.
It will make scripting a lot easier (to understand) as well.

.F
klankschap is offline   Reply With Quote
Old 12-26-2011, 08:17 PM   #18
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Thanks for your time on my 2 script, F. It's appreciated.

The reason I've not done that myself is because I didn't know anything about it!

Can you tell me why this is a better way to code in Python, please?


All the best,
Dax.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 12-27-2011, 03:14 AM   #19
klankschap
Human being with feelings
 
Join Date: Feb 2007
Posts: 99
Default

Quote:
Originally Posted by daxliniere View Post
Can you tell me why this is a better way to code in Python, please?
More readable to humans ?

moveCursor()

is easier to understand and to type compared to

RPR_Main_OnCommand(40513, 0)

or

RPR_Main_OnCommand(moveCursor, 0)


(to the machine doing the work it doesn't really matter)
klankschap is offline   Reply With Quote
Old 01-05-2012, 06:16 AM   #20
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Justin? Schwa? Could we please have some assistance here? We can't seem to make UndoBlock in a Python script work reliably.

Any tips, please?


Best regards,
Dax.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 11-16-2012, 12:32 PM   #21
miche
Human being with feelings
 
miche's Avatar
 
Join Date: Jan 2009
Posts: 559
Default

Thread gravedigging!

Is the undo block reascript state still weird? I tried to toy with it and I confirm that if you repeat the script and undo it a few times, Reaper will act crazy. I even had to restart the program to be able to perform undo's. Simply opening another project was not enough.

Or maybe we just used the undo block function parameters wrong? Since there is no example in the API, it's a bit hard to know how those behave. Devs, any help? Anyone else?
miche is offline   Reply With Quote
Old 11-17-2012, 05:11 PM   #22
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Yes, I could never understand why the devs haven't either explained how this works or fixed it.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 11-20-2012, 01:54 PM   #23
miche
Human being with feelings
 
miche's Avatar
 
Join Date: Jan 2009
Posts: 559
Default

Since we don't know if it's a bug or not, I opened a thread in the bug section about this problem there:
http://forum.cockos.com/showthread.php?t=113717

Let's hope it gets a solution, I'd love to use this one.
miche is offline   Reply With Quote
Old 04-08-2013, 07:02 AM   #24
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,737
Default

OK here's some suggestions:
  • If you don't care about the project context, you should just use Undo_BeginBlock and Undo_EndBlock, which operate on the active project
  • You must ALWAYS match your Undo_BeginBlock to your Undo_EndBlock -- if you call Undo_BeginBlock and then never call Undo_EndBlock, you will really fudge the state of things up (you'll end up in a huge undo block, causing all kinds of weird behavior you describe).
  • The final parameter of Undo_EndBlock refers to extra things you'd like to add to the undo state; if you're simply calling other actions to do things, this should be 0. If you modify the state of the project directly, you can do -1 (or a more specific flag).
  • Always give the "desc" parameter of Undo_EndBlock a valid string.
Justin is offline   Reply With Quote
Old 04-08-2013, 07:11 AM   #25
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Thanks Justin, I'll give that a try!

(BTW, I haven't forgotten about my email, I've just been snowed-under for months! )
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 04-09-2013, 01:43 AM   #26
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

Justin, running this or other simple scripts makes two undo points. The topmost in the history is labelled "ReaScript: run", then the second is the undo set by the script. Undoing "ReaScript: run" does nothing. Undoing the script undo point does what it's supposed to.

Code:
from reaper_python import *
RPR_Undo_BeginBlock2(0)

pMaster = RPR_GetMasterTrack(0)
iIsone =  RPR_TrackFX_GetByName(pMaster, "TB_Isone", 1)
RPR_TrackFX_SetEnabled(pMaster, iIsone, 1)

RPR_Undo_EndBlock2(0, "Isone - Enable", 2)
So every time I run a script the last action is shown as "ReaScript: run" and if I need to undo, I have to do it twice. As far as I can tell, I'm using the API properly. I tried changing things around to use the original undo functions and tried setting flags of 0 and -1 but the behaviour is the same.

Using Python 3.1, Win 7 32bit.
IXix is offline   Reply With Quote
Old 04-09-2013, 07:01 AM   #27
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Try dropping the "2" from undo blocks? Justin's example is different.
Does it also need the "RPR_" part?
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 04-09-2013, 08:49 AM   #28
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

Quote:
Originally Posted by daxliniere View Post
Try dropping the "2" from undo blocks? Justin's example is different.
Tried that already.
Quote:
Originally Posted by daxliniere View Post
Does it also need the "RPR_" part?
Yes, it's ReaScript.
IXix is offline   Reply With Quote
Old 04-09-2013, 09:48 AM   #29
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

"RPR_Undo_EndBlock2(0, "Isone - Enable", -1)" works for me. Everything else seems to add two undo points.
spk77 is offline   Reply With Quote
Old 04-09-2013, 09:50 AM   #30
jnif
Human being with feelings
 
jnif's Avatar
 
Join Date: Dec 2008
Posts: 2,111
Default

Quote:
Originally Posted by Justin View Post
You must ALWAYS match your Undo_BeginBlock to your Undo_EndBlock -- if you call Undo_BeginBlock and then never call Undo_EndBlock, you will really fudge the state of things up (you'll end up in a huge undo block, causing all kinds of weird behavior you describe).
Here is a solution to this:
Code:
from reaper_python import *
from contextlib import contextmanager

@contextmanager
def undoable(message):
    RPR_Undo_BeginBlock2(0)
    try:
        yield
    finally:
        RPR_Undo_EndBlock2(0,message,-1)


with undoable('Put your undo history message here'):
    #Write your script here
This is useful because it calls the Undo_EndBlock automatically even when the script crashes. Very useful for testing and debugging.
And using with statement keeps the actual script code clean and readable.

Maybe this kind of contextmanager should be added to reaper_python library.

jnif
jnif is offline   Reply With Quote
Old 04-15-2013, 12:41 AM   #31
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Hey jnif,
That sounds like a really cool thing. Do you know if it adds much overhead/CPU time?

I would be concerned about using that for frequently-used scripts such as ones to split items.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 05-26-2013, 11:50 PM   #32
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Hey jnif,
Thanks a bunch for that code. I tried it in one of my scripts, but then started to notice my undo state was a bit messed up. If I click Undo, it takes me back to an old state, but only partially. (it's a bit screwed up)

It re-opens a plugin that I adjusted many 'steps' earlier (probably over 100 steps?)

So it seems like there is an 'open-ended' undo step somewhere, probably caused by the cut script. Is there some kind of failsafe I can add?


Thanks again for your help.
Dax.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 05-27-2013, 10:47 PM   #33
jnif
Human being with feelings
 
jnif's Avatar
 
Join Date: Dec 2008
Posts: 2,111
Default

Quote:
Originally Posted by daxliniere View Post
Hey jnif,
Thanks a bunch for that code. I tried it in one of my scripts, but then started to notice my undo state was a bit messed up. If I click Undo, it takes me back to an old state, but only partially. (it's a bit screwed up)

It re-opens a plugin that I adjusted many 'steps' earlier (probably over 100 steps?)

So it seems like there is an 'open-ended' undo step somewhere, probably caused by the cut script. Is there some kind of failsafe I can add?


Thanks again for your help.
Dax.
The 'undoable' context manager is the failsafe way to handle undos. I don't know any better way. Maybe someone else could help if there are situation where additional safety mechanisms are necessary.

Could you post your script code to this thread?
Maybe we can help you better then.

Do you have some of your code outside the 'with undoable' statement?
Or maybe you have used multiple nested 'with undoable' statements. I think there could be problems if do something like that.

Also, I recommend you to restart Reaper whenever you have some problems with undo history. The 'undoable' context manager will not "heal" undo history if the history has been corrupted already before using the 'undoable' context manager.

jnif
jnif is offline   Reply With Quote
Old 05-28-2013, 04:22 AM   #34
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Once again, thanks so much for your time and experience, jnif.

Here's the script:
Code:
SelectItemUnderCursor = 40528
DeselectItems = 40289
MoveCursor = 40513
SplitItems = RPR_NamedCommandLookup('_SWS_AWSPLITXFADELEFT')


from reaper_python import *
from contextlib import contextmanager

@contextmanager
def undoable(message):
    RPR_Undo_BeginBlock2(0)
    try:
        yield
    finally:
        RPR_Undo_EndBlock2(0,message,-1)


with undoable('Split item(s)'):
    #Write your script here


    selItems = RPR_CountSelectedMediaItems(0)

    RPR_Main_OnCommand(MoveCursor, 0)

    if (selItems==0):
      RPR_Main_OnCommand(SelectItemUnderCursor, 0)
      RPR_Main_OnCommand(SplitItems, 0)
      RPR_Main_OnCommand(DeselectItems, 0)

    if (selItems!=0):
      RPR_Main_OnCommand(SplitItems, 0)
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 05-28-2013, 08:09 AM   #35
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Now it should work. A couple of lines were outside the 'with undoable' statement.

Code:
from reaper_python import *
from contextlib import contextmanager

@contextmanager
def undoable(message):
    RPR_Undo_BeginBlock2(0)
    try:
        yield
    finally:
        RPR_Undo_EndBlock2(0,message,-1)

with undoable('Split item(s)'):
    #Write your script here

    SelectItemUnderCursor = 40528
    DeselectItems = 40289
    MoveCursor = 40513
    SplitItems = RPR_NamedCommandLookup('_SWS_AWSPLITXFADELEFT')

    selItems = RPR_CountSelectedMediaItems(0)

    RPR_Main_OnCommand(MoveCursor, 0)

    if (selItems==0):
      RPR_Main_OnCommand(SelectItemUnderCursor, 0)
      RPR_Main_OnCommand(SplitItems, 0)
      RPR_Main_OnCommand(DeselectItems, 0)

    if (selItems!=0):
      RPR_Main_OnCommand(SplitItems, 0)
spk77 is offline   Reply With Quote
Old 05-28-2013, 08:23 AM   #36
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Oh, my mistake. I assumed all variables had to be declared at the start of the script.

Thanks spk77, I'll try it out tomorrow!

All the best!
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 06-05-2013, 09:11 PM   #37
daxliniere
Human being with feelings
 
daxliniere's Avatar
 
Join Date: Nov 2008
Location: London, UK
Posts: 2,583
Default

Hey spk77, it looks like it's working without any problems now, so it must have been my (false) assumption about the declarations.

Thanks again for your help!


All the best,
Dax.
__________________
Puzzle Factory Sound Studios, London [Website] [Instagram]
[AMD 5800X, 32Gb RAM, Win10x64, NVidia GTX1080ti, UAD2-OCTO, FireFaceUCX, REAPER x64]
[Feature request: More details in Undo History]
daxliniere is offline   Reply With Quote
Old 07-11-2013, 02:30 AM   #38
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

I noticed that sometimes "RPR_Undo_OnStateChange2()" has to be used inside RPR_Undo_BeginBlock2/EndBlock to add an undo point with a correct name. Try to remove/comment out line 39 (blue text) in this script. If the line is removed, the undo point name is "ReaScript: run".

Flip selected notes (needs SWS extensions):
Code:
# Flip selected notes (flip positions)
from sws_python import *
from random import randint
from contextlib import contextmanager

@contextmanager
def undoable(message):
    RPR_Undo_BeginBlock2(0)
    try:
        yield
    finally:
##        msg(message)
        RPR_Undo_EndBlock2(0, message, -1)

def msg(m):
    RPR_ShowConsoleMsg(m)

def getActTakeInEditor():
    """Returns the pointer of the currently active take in the midieditor."""
    return RPR_MIDIEditor_GetTake(RPR_MIDIEditor_GetActive())

def isNoteSelected(midiTake, index):
    """Returns 1 if selected, 0 if not selected"""
    isSelected = FNG_GetMidiNoteIntProperty(FNG_GetMidiNote(midiTake, index), "SELECTED")
    return isSelected

def makeSelNoteIdList():
    """Returns a list with noteIds (selected notes) and take's id."""
    noteIdList = []
    midiTake = FNG_AllocMidiTake(getActTakeInEditor())
    noteCount = FNG_CountMidiNotes(midiTake)
    for i in range(noteCount):
        if isNoteSelected(midiTake, i):
            noteIdList.append(FNG_GetMidiNote(midiTake, i))
    return noteIdList, midiTake

def flipSelNotes(listName):
    with undoable("Flip"):
        RPR_Undo_OnStateChange2(0, "Flip")
        l = []
        noteIdList, midiTake = makeSelNoteIdList()
        for currNote in noteIdList:
            l.append(FNG_GetMidiNoteIntProperty(currNote, listName))
        noteIdList.reverse()
        for i, id in enumerate(noteIdList):
            FNG_SetMidiNoteIntProperty(id, listName, l[i])
        FNG_FreeMidiTake(midiTake)

flipSelNotes("POSITION")

Last edited by spk77; 07-30-2013 at 10:21 AM.
spk77 is offline   Reply With Quote
Old 09-17-2013, 02:21 AM   #39
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

What am I doing wrong? When I run this script, nothing gets added to the undo history (although the most recent action in the menu bar says "ReaScript: Run")...
Code:
from reaper_python import *
from contextlib import contextmanager

@contextmanager
def undoable(message) :
   RPR_Undo_BeginBlock2(0)
   try :
      yield
   finally :
      RPR_Undo_EndBlock2(0, message, -1)

with undoable('Set Master Output - B') :
   #void Undo_OnStateChangeEx2(void* proj, const char* descchange, int whichStates, int trackparm)
   #trackparm=-1 by default,or if updating one fx chain,you can specify track index
   RPR_Undo_OnStateChangeEx2(0, "test", 2, -1) # From reaper_plugin.h: #define UNDO_STATE_FX 2  // track/master fx

   pMasterTrack = RPR_GetMasterTrack(0)
   iSwitcher =  RPR_TrackFX_GetByName(pMasterTrack, "IX/Switcher4", 0)

   if iSwitcher > -1 :   
      iSource = RPR_TrackFX_GetParam(pMasterTrack, iSwitcher, 0, 0, 3)[0]
      if iSource != 1 :
         RPR_TrackFX_SetParam(pMasterTrack, iSwitcher, 0, 1)
IXix is offline   Reply With Quote
Old 09-17-2013, 08:41 AM   #40
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Quote:
Originally Posted by IXix View Post
What am I doing wrong? When I run this script, nothing gets added to the undo history (although the most recent action in the menu bar says "ReaScript: Run")...
Code:
from reaper_python import *
from contextlib import contextmanager

@contextmanager
def undoable(message) :
   RPR_Undo_BeginBlock2(0)
   try :
      yield
   finally :
      RPR_Undo_EndBlock2(0, message, -1)

with undoable('Set Master Output - B') :
   #void Undo_OnStateChangeEx2(void* proj, const char* descchange, int whichStates, int trackparm)
   #trackparm=-1 by default,or if updating one fx chain,you can specify track index
   RPR_Undo_OnStateChangeEx2(0, "test", 2, -1) # From reaper_plugin.h: #define UNDO_STATE_FX 2  // track/master fx

   pMasterTrack = RPR_GetMasterTrack(0)
   iSwitcher =  RPR_TrackFX_GetByName(pMasterTrack, "IX/Switcher4", 0)

   if iSwitcher > -1 :   
      iSource = RPR_TrackFX_GetParam(pMasterTrack, iSwitcher, 0, 0, 3)[0]
      if iSource != 1 :
         RPR_TrackFX_SetParam(pMasterTrack, iSwitcher, 0, 1)
Tested with v4.401 and v.4.53pre4 - undo point is added in v4.401, but not in v.4.53pre4. There have been undo-related updates lately.
spk77 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 08:54 AM.


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