Old 05-20-2018, 12:02 AM   #1
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default Possible Bug In GetItemEditingTime2() [No Bug]

Hello everybody, I'm trying to write a shuffle editing script and had it working relatively well by comparing the item's "D_POSITION" over each frame to get a "moving state". However, there were problems with undo so I've opted to use GetItemEditingTime2() instead.

The function is great and is incredibly useful. It fixed my issues with undo easily, but, it doesn't handle quick twitch moves. In the gif below I click the item, get the desired item pickup/drop, then a slow item move performs as expected. However during a quick move, GetItemEditingTime2() does not update, there's a certain move rate where it will kick in, but that rate is still too slow imo. Shouldn't GetItemEditingTime2() return once on the frame of a mouse down?

(also something cool to have would be on_undo()/on_redo functions that perform like reaper.GetProjectStateChangeCount())


Last edited by ausbaxter; 05-26-2018 at 09:54 PM.
ausbaxter is offline   Reply With Quote
Old 05-20-2018, 08:50 AM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,900
Default

I only use the D_POSITION value from the GetMediaItemInfo_Value function. No problem with that.



Note that shuffle items scripts already exists : https://forum.cockos.com/showthread.php?t=159961


I even have other shuffle scripts with different shuffling algorithm like setting iems 1 2 3 4 5 6 to items 1 6 2 5 3 4 etc... :P


Also some with grouped items support.
X-Raym is offline   Reply With Quote
Old 05-20-2018, 11:10 AM   #3
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default

Hey X-Raym

I use those scripts daily .

Note that this isn't an item order shuffler. Its a "shuffle editing" deferred script ala Pro Tools. Basically an item move + edge offset. I hope I didn't miss the equivalent script you mention, but I checked the entirety of the actions list (reapack and sws installed) and didn't find one providing this function.



D_POSITION is fine for latching on an "item move" state and then having a timer wait after a stop in movement before committing the edit. But the script couldn't distinguish between the movement of the item due to an undo and an actual user moving the item with their cursor.

ItemEditingTime2() allows you (well ideally) to get a good pseudo mouse down/up event, and informs you of the type of edit being performed (move,fade,edge,etc) pretty powerful. But I'm thinking there's some sort of bug because the item edit state isn't reported effectively on quick moves. A simple click-release seems to report it on initial frame, but again it depends on the speed of the item edit itself whether it gets reported successfully or not.
ausbaxter is offline   Reply With Quote
Old 05-20-2018, 11:56 AM   #4
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,900
Default

In fact I made scripts to ripple edit from item edges
https://forum.cockos.com/showthread.php?t=157698


but it works differently that yours. Your solution seems more intuitive (the kind of Mouse Mofidier we would want !).


I'm really not use to the problematic functions you are talking, I think you are the only one who really explored it so far ^^


Any code snippet to share ?
X-Raym is offline   Reply With Quote
Old 05-20-2018, 01:45 PM   #5
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default

This is the full script, it should work as desired aside from the item drag speed issue. I wish we could assign deferred scripts to mouse modifier drag contexts! This is just a standard toggle.

I'm not sure if I like the deletion behavior when moving the item beyond its original bounds, maybe using item fades like protools will be nicer in general?

There shouldn't be any issues except for the return value of GetItemEditingTime2 although that may be foolishly hopeful lol

Code:
ripple_all_tracks_check = reaper.GetToggleCommandState(40311) --ripple all tracks check
ripple_one_track_check = reaper.GetToggleCommandState(40310) --ripple all tracks check
auto_cross_fade_off = 41119
auto_cross_fade_on = 41118
ripple_one_track = 40310
ripple_all_tracks = 40311
ripple_off = 40309
remove_item = 40006
deselect_items = 40289

function HandleItemMovement()
    
    current_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
    current_state = reaper.GetProjectStateChangeCount(0) --used to apply shuffle offset
    t,s,current_edit = reaper.GetItemEditingTime2()
    
    if init == false then
        --[[
        if current_edit ~= previous_edit then
            if current_edit == 4 then
                reaper.ShowConsoleMsg("Item Pickup Registered\n")
            elseif current_edit == 0 then
                reaper.ShowConsoleMsg("Item Dropped\n")
            end
        end]]
        
        if current_edit == 4 then
            not_moving = false
            new_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
        elseif current_edit == 1 then --edges are resizing make sure to update position
            original_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
        elseif current_edit == 0 then
            not_moving = false
        end
        
        if current_edit == 0 and previous_edit == 4 and current_state ~= previous_state and not_moving == false and item == previous_item and current_pos ~= original_pos then
        
            reaper.PreventUIRefresh(1)        
            reaper.Undo_BeginBlock()
            --reaper.ShowConsoleMsg("Shuffle Offset\n")
            not_moving = true
            length = reaper.GetMediaItemInfo_Value(item, "D_LENGTH")
            offset = new_pos - original_pos
            offset_length = offset + length
            reaper.SetMediaItemInfo_Value(item, "D_POSITION", original_pos)
            reaper.SetMediaItemInfo_Value(item, "D_LENGTH", offset_length)
            reaper.SetMediaItemInfo_Value(item, "B_LOOPSRC", 1)
            reaper.ApplyNudge(0,0,4,1,offset,false,0)
            reaper.UpdateItemInProject(item)
            new_pos = original_pos
            
            if current_pos + length < original_pos then --delete
                --reaper.ShowConsoleMsg("DELETE")
                --not the best, want to preserve fades maybe
                reaper.Undo_DoUndo2(0)
                item_idx = reaper.GetMediaItemInfo_Value(item, "IP_ITEMNUMBER")
                reaper.Main_OnCommand(deselect_items,0)
                reaper.SetMediaItemInfo_Value(reaper.GetTrackMediaItem(reaper.GetMediaItemTrack(item),item_idx-1), "B_UISEL", 1)
                reaper.Main_OnCommand(remove_item,0)
                
            end
            
            reaper.Undo_EndBlock("Shuffle Item",-1)
            reaper.UpdateArrange()
        end

    end
    
    previous_item = item
    previous_pos = current_pos
    previous_state = current_state
    previous_edit = current_edit
    
    --init is set to false here as at this point all variables have been initialized
    init = false
    
end

init = true
function main()
    
    --get item to compare to previous and track initially selected single item
    if reaper.CountSelectedMediaItems(0) == 1 then
        item = reaper.GetSelectedMediaItem(0,0)
        if init then original_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION") end
    else
        item = nil
    end
    
    --get new item and store start
    if item ~= nil then
        if init == false then
            if item ~= prev_item then
                original_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
            end 
        end
        HandleItemMovement()
    end
    
    prev_item = item 
    reaper.defer(main)
end

--don't force ripple state when script is toggled off
function RestoreRippleState()
    local cmd_id
    if ripple_all_tracks_check == 1 then cmd_id = ripple_all_tracks
    elseif ripple_one_track_check == 1 then cmd_id = ripple_one_track
    elseif ripple_all_tracks_check == 0 and ripple_one_track_check == 0 then cmd_id = ripple_off end
    
    reaper.Main_OnCommand(cmd_id, 0)
end

--ran when toggle is off
function exitnow()

    RestoreRippleState()
    is_new_value,filename,sectionID,cmdID,mode,resolution,val = reaper.get_action_context()
    reaper.SetToggleCommandState(sectionID, cmdID, 0)
    reaper.RefreshToolbar2(sectionID, cmdID)
    reaper.Main_OnCommand(auto_cross_fade_on,0)
    gfx.quit()

end

reaper.atexit(exitnow)

is_new_value,filename,sectionID,cmdID,mode,resolution,val = reaper.get_action_context()
reaper.SetToggleCommandState(sectionID, cmdID, 1)
reaper.RefreshToolbar2(sectionID, cmdID)

reaper.Main_OnCommand(auto_cross_fade_off,0)
reaper.Main_OnCommand(ripple_one_track,0)

main()
And then here is a script that you can use to see how GetItemEditTime2() works

Code:
function test_defer()
    t,s,e = reaper.GetItemEditingTime2()
    i = reaper.GetSelectedMediaItem(0,0)
    
    if t ~= p_t then
        reaper.ShowConsoleMsg("Time:\t" .. t .. "\nItem:\t" .. tostring(s) .. "\tvs\t" .. tostring(i) .. "\nEdit:\t" .. e .. "\t(1 = edge sizing, 2 fade change, 4 item move)\n" .. "*Item is PCM_Source not Mediaitem :( " .. "\n\n")
    end
    
    p_t = t
    reaper.defer(test_defer)
end

function exit() gfx.quit() end

reaper.atexit(exit)

test_defer()

Last edited by ausbaxter; 05-20-2018 at 11:05 PM. Reason: Now updates item position when performing edge edits
ausbaxter is offline   Reply With Quote
Old 05-20-2018, 02:12 PM   #6
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,900
Default

Intersting function, I wonder how usable it is.


What the basic idea to find which fades or wich edges has been edited ?
X-Raym is offline   Reply With Quote
Old 05-20-2018, 03:34 PM   #7
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default

You'd have to look at "D_POSITION" and "D_LENGTH" when GetItemEditTime2() returned the pseudo mouse up. if D_POSITION ~= original position then its a leading edge edit. If D_POSITION == original position and D_LENGTH ~= original length then its a tail edge edit. With fades you'd just check the corresponding fade in/out lengths, my way around that is to ensure that auto fades is off when the script is running.

I think the function would be incredibly useful if the values returned reliably. It provides a way to create mouse down and up events within the reaper main window (although only when dealing with items).

Try moving some items around at different speeds when running the small script in the previous post. You'll notice at a certain speed the pseudo mouse down event isn't triggered on item selection but once the speed of the cursor returns below that invisible movement rate threshold. It's clearly for performance, but I can't see the reason for not being able to get that value on the frame of an item selection, that seems to be the desired effect.

*Edit
Also, reaper.GetProjectStateChangeCount will update at every state change event, so you can use that as a filter with some other logic if you want to deal with things other than items. I had to use it in combination with GetItemEditTime to allow for every other edit function to perform as normal, but allowing item moves to perform the shuffle edit.
ausbaxter is offline   Reply With Quote
Old 05-25-2018, 05:01 AM   #8
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,746
Default

A bit of background: this function is used by the video component to determine what video to display during edits (it'll show you the edit time).

Also a side note: it won't return the edge time exactly, it adjusts it slightly to ensure proper video behavior.


I think the issue you're having is that you get a mousedown/move/mouseup in between your defer() calls, so GetItemEditingTime2() misses that edit (because when you call it, the edit is no longer happening).
Justin is online now   Reply With Quote
Old 05-26-2018, 10:05 PM   #9
ausbaxter
Human being with feelings
 
Join Date: Apr 2016
Posts: 39
Default

Thanks Justin for the clarification. Good to know the background for the function, it's the only way I was able to use lua to get the desired functionality. I was super close to using python.

For those who may be wondering, the problem was not with GetItemEditingTime2(), the rate at which defer is called is variable. (idk how I didn't know that before, seems pretty obvious now) So defer would defer (hehe) its calls as an optimization measure I imagine. And if you were quick enough defer would skip over the edit or miss the initial click on an item.

Still an issue but if you aren't prone to quick-twitch edits the script is still quite usable.

May put this up on reapack in the future.
ausbaxter 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 07:56 PM.


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