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

Reply
 
Thread Tools Display Modes
Old 06-23-2023, 04:02 PM   #1
earhax
Human being with feelings
 
earhax's Avatar
 
Join Date: Nov 2015
Location: earth
Posts: 471
Default Big update to LKC Hover Edit - Untrim Script: dynamic fade editing while trimming!

I've really enjoyed using the LKC Hover Edit scripts, and decided to give something back by adding some dynamic improvements to the Untrim right/left script.

Now, simply by using either ⇧shift and/or ⌘cmd(Mac)/ctrl(PC) modifiers, you can change the way fades are edited when hover-trimming/extending items, including the ability to adjust, remove, or even add fades in the same step while editing item edges, and also determine whether they trim to mouse pointer position, or to the edit cursor (depending on relative mouse pointer/edit cursor positions).

Since I haven't yet found (or made) the time to get all of my scripts into ReaPack, I'll just paste the text for this modified script here. You should be able to get it working by manually overwriting the `/Scripts/LKC Tools/Hover editing package/lkc_hover_edit-untrim.lua` script file with the following script (unless/until LKC has the time and wants to update his ReaPack repository with these changes later on):

Code:
--------------------------------------------------------------------------------------------------
--	@Description: lkc_hover_edit-untrim.lua
--	@Version: 1.IDK
--	@Author: originally by LKC, heavily modded by EarHax
--	@Donation: https://paypal.me/earhax
--	@About: if mouse is hovering over an item, move the edit cursor to mouse pointer position, and select the item (if not already selected)
--			otherwise, the untrim operation will be performed at the current edit cursor location on selected items (normal operation)
--			EXCEPTIONS: if the mouse pointer is to the right of the edit cursor, on an "untrim right" operation, the right edge of selected item(s) will extend to the mouse pointer position.
--]]--		Similarly, when doing an "untrim left", if the pointer is to the left of the edit cursor, the left edge of any selected item(s) will extend to the pointer position.

_=[[NOTE: To work properly, this script needs 3 shortcuts assigned to each of the following scripts:
			LKC - HOVER EDIT W - Untrim right.lua
			LKC - HOVER EDIT Q - Untrim left.lua
			for whichever <key> is assigned to each of these scripts,
			the ⇧shift+<key> and ⌘cmd(mac)/ctrl(PC)+<key> modified versions of the assigned <key>
			must *also* be assigned to the same script!
			However, this will also work if the shortcut assigned is a note on a MIDI controller!
			In that case, only the MIDI note needs to be assigned. The modifiers will still be
			detected by the script properly when pressing the MIDI note.
			
			Using the ⇧shift or ⌘cmd(mac)/ctrl(PC) modifiers with this script will change how it handles
			adjusting/adding/removing fade in/out of items being trimmed/untrimmed.
			]]
_=''
-- @Changelog: 	- added optional trimming to edit cursor instead of mouse pointer location
--				- return edit cursor to original position after making the edits
--				- added logic to determine whether to trim selected items (no item hover), mouse-hovered items (no items selected), or both
--				- added ⇧ & ⌘ modifier detection to change modes for handling of item fade in/out when trimming/untrimming
-- @License: GNU GPL v3

--██████████████████████████████████████    CONFIG/SETUP    ████████████████████████████████████████
----------------------------------------------------------------------------------------------------
OS=reaper.GetOS();sep=OS:match'Win'and'\\'or'/';local scrPath,scrName=({reaper.get_action_context()})[2]:match'(.-)([^/\\]+).lua$';
----------------------------------------------------------------------------------------------------
ehxdebug=1
local r = reaper
local curpos = r.GetCursorPosition()
----------------------------------------------------------------------------------------------------
local function mItemInfo2(...) -- retrieves mutliple media item info values based on arguments passed to the function
	-- in other words, the numer and position of return values and arguments can be changed dynamically
	-- as long as the variables being assigned are in the same order as the arguments
	-- and the first argument needs to be a pointer to an audio media item
	-- example usage:
	-- item,ipos,ilen,itrk,itak,fadil,fadol,trate,toffs,tsrc,srcfil,srclen = mItemInfo('item','ipos','ilen','itrk','itak','fadil','fadol','trate','toffs','tsrc','srcfil','srclen')
	local args = {...}
	-- r.ClearConsole()
	local item = args[1]
	local pos = r.GetMediaItemInfo_Value(item, 'D_POSITION')
	local ilen = r.GetMediaItemInfo_Value(item, "D_LENGTH")
	local track = r.GetMediaItem_Track(item)
	local take = r.GetActiveTake(item)
	local rate = r.GetMediaItemTakeInfo_Value(take, 'D_PLAYRATE')
	local offset = r.GetMediaItemTakeInfo_Value(take, 'D_STARTOFFS')
	local tkSrc = r.GetMediaItemTake_Source(take)
	local tkSrc2 = r.GetMediaSourceParent(tkSrc)
	local source = tkSrc2 or tkSrc
	local srcfilename = r.GetMediaSourceFileName(source)
	local srclen, lengthIsQN = r.GetMediaSourceLength(source)
	local fadil = r.GetMediaItemInfo_Value(item, 'D_FADEINLEN')
	local fadol = r.GetMediaItemInfo_Value(item, 'D_FADEOUTLEN')
	local vals = {}
	for v = 1, #args do
		if tostring(args[v]):match('^userdata') then vals[v] =  item
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[pP][oO][sS][iItToOnN]-$') then vals[v] = pos
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[lL][eE][nN][gG]?[tT]?[hH]?$') then vals[v] = ilen
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[fF][aA][dD][eE]?[iI][nN]?[lL][eE]?[nN]?[gG]?[tT]?[hH]?$') then vals[v] = fadil
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[fF][aA][dD][eE]?[oO][uU]?[tT]?[lL][eE]?[nN]?[gG]?[tT]?[hH]?$') then vals[v] = fadol
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[tT][rR][aA]?[cC]?[kK]?$') then vals[v] = track
		elseif args[v]:match('^[IDP]?_?[iI]?[tT]?[eE]?[mM]?_?[tT][aA]?[kK][eE]?$') then vals[v] = take
		elseif args[v]:match('^[IDP]?_?[tT]?[aA]?[kK]?[eE]?_?[rR][aA]?[tT][eE]?$') then vals[v] = rate
		elseif args[v]:match('^[IDP]?_?[tT]?[aA]?[kK]?[eE]?_?[oO][fF][fF]?[sS][eE]?[tT]?$') then vals[v] = offset
		elseif args[v]:match('^[IDP]?_?[tT]?[aA]?[kK]?[eE]?_?[sS][oO]?[uU]?[rR][cC][eE]?$') then vals[v] = source
		elseif args[v]:match('^[IDP]?_?[tT]?[aA]?[kK]?[eE]?_?[sS][oO]?[uU]?[rR][cC][eE]?_?[fF][iInN][lL]?[eE]?[nN]?[aA]?[mM]?[eE]?$') then vals[v] = srcfilename
		elseif args[v]:match('^[IDP]?_?[tT]?[aA]?[kK]?[eE]?_?[sS][oO]?[uU]?[rR][cC][eE]?_?[lL][eE][nN][gG]?[tT]?[hH]?$') then vals[v] = srclen
		else vals[v] = 'Arg string unmatched!' 
		end
	end
return table.unpack(vals)
end
----------------------------------------------------------------------------------------------------
local function SaveSelItem() 
	local count = r.CountSelectedMediaItems(0)
	if not count or count < 1 then no_undo() return end
	sel_items = {}
	for i = 1, count do 
		sel_items[i] = r.GetSelectedMediaItem(0,i-1) 
	end
	return sel_items
end 
----------------------------------------------------------------------------------------------------
function LoadSelItem() 
	if not sel_items or #sel_items < 1 then no_undo() return end
	r.SelectAllMediaItems(0,0) -- unselects all items
	for i = 1, #sel_items do 
		r.SetMediaItemSelected(sel_items[i],1)
	end 
end
----------------------------------------------------------------------------------------------------
local function moc(...)
	local Table = {...}
	for i = 1, #Table do
		r.Main_OnCommand(Table[i], 0)
	end
end
----------------------------------------------------------------------------------------------------
local function showTip(tiptext)
	tiptext=tiptext:gsub('_','⎽')
	local x, y = r.GetMousePosition()
	r.TrackCtl_SetToolTip(tiptext,x+10,y-10,0)
end
----------------------------------------------------------------------------------------------------
function no_undo()r.defer(function()end)end
----------------------------------------------------------------------------------------------------
local modpressed = false
local modpressed2 = false
local function getModState()
	modstate = r.JS_Mouse_GetState(00001100)
	if modstate == 4 then
		showTip('⌘ pressed: untrimming without preserving fade lengths')
		modpressed = true
		modpressed2 = false
	elseif modstate == 8 or modstate > 8 then
		showTip('⇧ pressed: untrimming without preserving fade lengths \n\t\t adding new fades when lengthening items \n\t\t (for items that have no fade in/out)')
		modpressed = false
		modpressed2 = true
	else
		showTip('⌘/⇧ not pressed: untrimming and preserving fade lengths')
		modpressed = false
		modpressed2 = false
	end
end
--[[
flags:
	-1			return values for any pressed mouse button (1-3) or modifier key
	00000000	8-bit binary number, acts as a filter to only return states of desired keys/buttons
				bit values, in order L-R: 128(unknown key/button, if it's even used),64,32,16,8,4,2,1
			EXAMPLES:
				00011000 will only return values for shift or option being pressed
				00000011 will only return values for left or right mouse being pressed
				00100100 and 00000100 seem to be exceptions (on macOS, at least)
					00100100 will *BLOCK* return of value for ⌃ keypress, and only show 4 when ⌘ is pressed, ignoring other modifiers
					00000100 will return value for either or both ⌃ and ⌘ presses (32,4, or 36)
return values:	values will be added together based on what is pressed
	1		mousebutton1 (left click)
	2		mousebutton2 (right click)
	4		⌘
	8		⇧
	16		⌥
	32		⌃
	64		mousebutton3 (middle click)
--]]

--██████████████████████████████████████    MAIN  SCRIPT    ████████████████████████████████████████

function main()
	hover_editing = tonumber(r.GetExtState("LKC_TOOLS","hover_editing_state"))
	if hover_editing == nil then hover_editing = 1 end

	if hover_editing == 1 then
		-- check if mouse pointer is hovering over an item
		local window, segment, details = r.BR_GetMouseCursorContext(); 
		local item = r.BR_GetMouseCursorContext_Item(); 
		local mppos = r.BR_GetMouseCursorContext_Position()
		local selitemcount = r.CountSelectedMediaItems(0)
		if not item and selitemcount < 1 then
			showTip('LKC/erhx Hover_Edit-Untrim Fail: No item(s) selected or under mouse pointer/cursor!')
			no_undo()
			return
		end
			
		getModState()
		
		if item then; 
			r.SetMediaItemSelected(item, true)
			itrk = r.GetMediaItemTrack(item)
			r.SetTrackSelected(itrk, true)
			--moc(40514) --View: Move edit cursor to mouse cursor (no snapping)
			moc(40513) --View: Move edit cursor to mouse cursor (snapping)
			curpos = r.GetCursorPosition()
		elseif (mppos >= curpos) and (OPERATION == "right_untrim") then
			moc(40513) --View: Move edit cursor to mouse cursor (snapping)
			curpos = r.GetCursorPosition()
		elseif (mppos <= curpos) and (OPERATION == "left_untrim") then
			moc(40513) --View: Move edit cursor to mouse cursor (snapping)
			curpos = r.GetCursorPosition()
		end;
	end
	if OPERATION == "right_untrim" then
		if modpressed == true or modpressed2 == true then
			sel_items = SaveSelItem()
			for i=1, #sel_items do
				itm = sel_items[i]
				itm,ipos,ilen,fadol = mItemInfo2(itm,'ipos','ilen','fadol')
				local newlen = curpos - ipos
				if fadol ~= 0.0 or modpressed2 == true then
					local newfadol
					if newlen > ilen then
						newfadol = fadol + (newlen - ilen)
					elseif newlen < ilen then
						newfadol = fadol - (ilen - newlen)
					elseif newlen == ilen then
						newfadol = fadol
					end
					if newfadol < 0.0 then newfadol = 0.0 end
					r.SetMediaItemInfo_Value(itm, 'D_LENGTH', newlen)
					r.SetMediaItemInfo_Value(itm, 'D_FADEOUTLEN', newfadol)
				else
					r.SetMediaItemInfo_Value(itm, 'D_LENGTH', newlen)
				end
			end
		else
			moc(41311) --Item edit: Trim right edge of item to edit cursor
		end
		scrName = "LKC/erhx - HOVER EDIT - Untrim right"
	elseif OPERATION == "left_untrim" then
		if modpressed == true or modpressed2 == true then
			sel_items = SaveSelItem()
			for i=1, #sel_items do
				moc(40289) -- Item: Unselect (clear selection of) all items
				itm = sel_items[i]
				itm,ipos,ilen,fadil = mItemInfo2(itm,'ipos','ilen','fadil')
				local endpos = ipos + ilen
				local newlen = endpos - curpos
				r.SetMediaItemSelected(itm, true)
				moc(41305) --Item edit: Trim left edge of item to edit cursor

				if fadil ~= 0.0 or modpressed2 == true then
					local newfadil
					if newlen > ilen then
						newfadil = fadil + (newlen - ilen)
					elseif newlen < ilen then
						newfadil = fadil - (ilen - newlen)
					elseif newlen == ilen then
						newfadil = fadil
					end
					if newfadil < 0.0 then newfadil = 0.0 end
					r.SetMediaItemInfo_Value(itm, 'D_FADEINLEN', newfadil)
				end
			end
			LoadSelItem()
		else
			moc(41305) --Item edit: Trim left edge of item to edit cursor
		end
		scrName = "LKC/erhx - HOVER EDIT - Untrim left"
	end
end

r.Undo_BeginBlock()
r.PreventUIRefresh(1)
main()
r.Undo_EndBlock(scrName, -1)
r.PreventUIRefresh(-1)
r.UpdateArrange()
The script also includes some functions I wrote that I've found to be pretty useful/time-saving.

Please be sure to read the "About" section for info on how to set up/use the script properly. And if anyone has any problems with it, reply here and I'll do my best to fix/update it as needed.

Happy Friday!
earhax is offline   Reply With Quote
Old 06-24-2023, 01:06 AM   #2
Sid
Human being with feelings
 
Join Date: Apr 2018
Posts: 515
Default

If you are unsure what is being discussed here, apparently it is this stuff:
https://github.com/nikolalkc/LKC-Tools/tree/master
https://raw.githubusercontent.com/ni...ster/index.xml

From this person:
https://www.lkctools.com/
__________________
Reaper v6.81 Windows 10
Sid is offline   Reply With Quote
Old 06-25-2023, 11:23 AM   #3
earhax
Human being with feelings
 
earhax's Avatar
 
Join Date: Nov 2015
Location: earth
Posts: 471
Default

Quote:
Originally Posted by Sid View Post
If you are unsure what is being discussed here, apparently it is this stuff:
https://github.com/nikolalkc/LKC-Tools/tree/master
https://raw.githubusercontent.com/ni...ster/index.xml

From this person:
https://www.lkctools.com/
Thanks, Sid! I was searching for the original posting on REAPER forum, but was unable to find it. But this is a helpful link to the original scripts from LKC.
earhax is offline   Reply With Quote
Old 06-28-2023, 04:05 PM   #4
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

I appreciate you sharing the mod! I'll check it out!
hans is offline   Reply With Quote
Old 02-22-2024, 01:43 AM   #5
Ideosound
Human being with feelings
 
Ideosound's Avatar
 
Join Date: Oct 2017
Location: U.K
Posts: 542
Default

Does anyone know how to mod the script to respect ripple editing? So when you trim part of an item (which acts like deleting it) your items would move and close this gap if ripple edit is active (currently this doesn't work).
Ideosound 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:09 AM.


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