230 lines
10 KiB
Lua
230 lines
10 KiB
Lua
-- Reaper Scripts for 4 point editing. This script executes "one edit" and copies source material from
|
|
-- already set source in/out markers to also set destination in/out markers.
|
|
-- Author: Ludwig Frühschütz
|
|
-- Source: https://www.eleton-audio.de
|
|
-- Git: https://files.eleton-audio.de/gitea/Ludwig/Reaper-Scripts.git
|
|
-- License: GPL v3.0
|
|
-- Requires: Reaper 5 or 6
|
|
-- Requires: SWS extensions, if not present no crossfades are created. http://standingwaterstudios.com
|
|
-- Requires: This script goes with several other scripts that work closely together.
|
|
|
|
local stored_cursorPos = 0
|
|
local stored_timeSelStart = 0
|
|
local stored_timeSelEnd = 0
|
|
local stored_sel_tracks = {}
|
|
local stored_sel_items = {}
|
|
local stored_view_start = 0
|
|
local stored_view_end = 0
|
|
local mark_srcin_pos = -1
|
|
local mark_srcin_id = -1
|
|
local mark_srcout_pos = -1
|
|
local mark_srcout_id = -1
|
|
local mark_dstin_pos = -1
|
|
local mark_dstin_id = -1
|
|
local mark_dstout_pos = -1
|
|
local mark_dstout_id = -1
|
|
local edit_mode = 0
|
|
local sws_present = false
|
|
-- edit modes: 0=not enough markers set; 1=src-in, src-out, dst-in; 2=src-in, src-out, dst-out;
|
|
-- 3=src-in, dst-in, dst-out; 4=src-out, dst-in, dst-out; 5=all four markers set;
|
|
|
|
-- Send a message to the console
|
|
function msg(m)
|
|
reaper.ShowConsoleMsg(tostring(m) .. "\n")
|
|
end
|
|
|
|
-- Round number
|
|
function round(num, numDecimalPlaces)
|
|
local mult = 10^(numDecimalPlaces or 0)
|
|
return math.floor(num * mult + 0.5) / mult
|
|
end
|
|
|
|
-- Selects the source tracks, or, if not stored in rpp, selects all tracks
|
|
function select_src_tracks()
|
|
local tracks_str = ''
|
|
local tracks = {}
|
|
local retval
|
|
|
|
retval, tracks_str = reaper.GetProjExtState(0, '4PointCut', 'src_tracks')
|
|
if retval > 0 then -- variable exists in rpp
|
|
-- separate GUIDs and populate track table
|
|
for str in string.gmatch(tracks_str, "([^"..'{'.."]+)") do
|
|
table.insert(tracks, reaper.BR_GetMediaTrackByGUID(0, '{' .. str))
|
|
end
|
|
-- select tracks
|
|
for _, track in ipairs(tracks) do
|
|
reaper.SetTrackSelected(track, true)
|
|
end
|
|
else
|
|
-- default to all tracks
|
|
for i = 0, reaper.CountTracks(0)-1 do
|
|
reaper.SetTrackSelected(reaper.GetTrack(0, i), true)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Select the destination tracks, or, if not stored in rpp, the first track
|
|
function select_dst_track_only()
|
|
local track_str = ''
|
|
local retval
|
|
retval, track_str = reaper.GetProjExtState(0, '4PointCut', 'dst_track')
|
|
if retval > 0 then -- variable exists in rpp
|
|
reaper.SetOnlyTrackSelected(reaper.BR_GetMediaTrackByGUID(0, track_str))
|
|
else --default to first track
|
|
reaper.SetOnlyTrackSelected(reaper.GetTrack(0, 0))
|
|
end
|
|
end
|
|
|
|
-- START HERE vvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
-- check for SWS extensions
|
|
if reaper.NamedCommandLookup('_SWS_ABOUT') > 0 then sws_present = true end
|
|
-- run through all markers and get position of the 4 points
|
|
local nof_markers = 0
|
|
local nof_regions = 0
|
|
_, nof_markers, nof_regions = reaper.CountProjectMarkers(0)
|
|
nof_markers = nof_markers + nof_regions -- adapt count of 'CountProjectMarkers()' to 'EnumProjectMarkers()'
|
|
for i = 0, nof_markers - 1 do
|
|
local name = ''
|
|
local pos = 0
|
|
local id = 0
|
|
local isregion = false
|
|
_, isregion, pos, _, name, id = reaper.EnumProjectMarkers(i)
|
|
if not isregion then
|
|
if name == 'SRC-IN_4Pcut' then
|
|
mark_srcin_pos = pos
|
|
mark_srcin_id = id
|
|
elseif name == 'SRC-OUT_4Pcut' then
|
|
mark_srcout_pos = pos
|
|
mark_srcout_id = id
|
|
elseif name == 'DST-IN_4Pcut' then
|
|
mark_dstin_pos = pos
|
|
mark_dstin_id = id
|
|
elseif name == 'DST-OUT_4Pcut' then
|
|
mark_dstout_pos = pos
|
|
mark_dstout_id = id
|
|
end
|
|
end
|
|
end
|
|
|
|
-- set edit mode depending on which markers are set (see comments next to definition of edit_mode)
|
|
if mark_srcin_id >= 0 and mark_srcout_id >= 0 and mark_dstin_id >= 0 and mark_dstout_id < 0 then
|
|
edit_mode = 1
|
|
elseif mark_srcin_id >= 0 and mark_srcout_id >= 0 and mark_dstin_id < 0 and mark_dstout_id >= 0 then
|
|
edit_mode = 2
|
|
elseif mark_srcin_id >= 0 and mark_srcout_id < 0 and mark_dstin_id >= 0 and mark_dstout_id >= 0 then
|
|
edit_mode = 3
|
|
elseif mark_srcin_id < 0 and mark_srcout_id >= 0 and mark_dstin_id >= 0 and mark_dstout_id >= 0 then
|
|
edit_mode = 4
|
|
elseif mark_srcin_id >= 0 and mark_srcout_id >= 0 and mark_dstin_id >= 0 and mark_dstout_id >= 0 then
|
|
edit_mode = 5
|
|
end
|
|
|
|
-- error messages
|
|
if edit_mode <= 0 then
|
|
msg('Please set at least 3 of the 4 markers first! Aborting.')
|
|
return
|
|
elseif (edit_mode == 1 or edit_mode == 2 or edit_mode == 5) and (mark_srcin_pos >= mark_srcout_pos) then
|
|
msg('SRC-IN Marker must be set left of SRC-OUT marker! Aborting.')
|
|
return
|
|
elseif (edit_mode == 3 or edit_mode == 4 or edit_mode == 5) and (mark_dstin_pos >= mark_dstout_pos) then
|
|
msg('DST-IN Marker must be set left of DST-OUT marker! Aborting.')
|
|
return
|
|
end
|
|
|
|
-- Do stuff before actual edits...
|
|
reaper.Undo_BeginBlock()
|
|
--store viewport off arranger
|
|
stored_view_start, stored_view_end = reaper.GetSet_ArrangeView2(0, false, 0, 0)
|
|
|
|
-- Store cursor position, time selection, selected tracks, selected items
|
|
stored_cursorPos = reaper.GetCursorPosition()
|
|
stored_timeSelStart, stored_timeSelEnd = reaper.GetSet_LoopTimeRange(false, true, 0, 1, false)
|
|
for i = 0, reaper.CountSelectedTracks(0)-1 do
|
|
stored_sel_tracks[i+1] = reaper.GetSelectedTrack(0, i)
|
|
end
|
|
for i = 0, reaper.CountSelectedMediaItems(0)-1 do
|
|
stored_sel_items[i+1] = reaper.GetSelectedMediaItem(0, i)
|
|
end
|
|
-- unselect items and tracks, select source tracks
|
|
reaper.Main_OnCommand(40289, 0) -- Unselect all items
|
|
reaper.Main_OnCommand(40297, 0) -- Unselect all tracks
|
|
select_src_tracks()
|
|
|
|
-- Set Source Time selection according to edit mode
|
|
if edit_mode == 1 then -- src-in, src-out and dst-in defined
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false)
|
|
elseif edit_mode == 2 then -- src-in, src-out and dst-out defined
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false)
|
|
mark_dstin_pos = mark_dstout_pos - (mark_srcout_pos - mark_srcin_pos) -- also set dst-in position, so we have a point to paste to
|
|
mark_dstin_id = reaper.AddProjectMarker(0, false, mark_dstin_pos, 0, 'DST-IN_4Pcut', -1)
|
|
elseif edit_mode == 3 then -- src-in, dst-in and dst-out defined
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcin_pos + (mark_dstout_pos - mark_dstin_pos), false)
|
|
elseif edit_mode == 4 then -- src-out, dst-in and dst-out defined
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcout_pos - (mark_dstout_pos - mark_dstin_pos), mark_srcout_pos, false)
|
|
elseif edit_mode == 5 then -- all 4 markers defined, get lenght of shortest region
|
|
if (mark_srcout_pos - mark_srcin_pos) < (mark_dstout_pos - mark_dstin_pos) then
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false)
|
|
else
|
|
reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcin_pos + (mark_dstout_pos - mark_dstin_pos), false)
|
|
end
|
|
end
|
|
|
|
-- Copy items
|
|
reaper.Main_OnCommand(40718, 0) -- select items on selected tracks under time selection
|
|
reaper.Main_OnCommand(40060, 0) -- copy selected items under time selection 41383
|
|
|
|
-- Move edit cursor to Dest-In and Paste
|
|
reaper.GoToMarker(0, mark_dstin_id, false)
|
|
select_dst_track_only()
|
|
--reaper.Main_OnCommand(40058, 0) -- paste item
|
|
reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWPASTE'), 0 ) -- SWS Paste
|
|
-- Crossfade (only with SWS extensions, "fill gaps")
|
|
if sws_present then
|
|
-- select track with selected items
|
|
local selected_items_count = reaper.CountSelectedMediaItems(0)
|
|
for i = 0, selected_items_count - 1 do
|
|
local item = reaper.GetSelectedMediaItem(0, i)
|
|
local track = reaper.GetMediaItem_Track(item)
|
|
reaper.SetTrackSelected(track, true)
|
|
end
|
|
reaper.Main_OnCommand( 40290, 0 ) -- set time selection to selected items
|
|
reaper.Main_OnCommand( 40320, 0 ) -- nudge left edge of time selection left
|
|
reaper.Main_OnCommand( 40323, 0 ) -- nudge right edge of time selection right
|
|
reaper.Main_OnCommand( 40718, 0 ) -- select items on selected tracks and in time selection
|
|
reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_CROSSFADE'), 0 ) -- fill gaps between selected items and crossfade
|
|
end
|
|
-- Move dstin marker according to edit mode
|
|
if edit_mode == 1 then
|
|
reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-IN_4Pcut')
|
|
elseif edit_mode == 2 then
|
|
reaper.SetProjectMarker(mark_dstout_id, false, mark_dstout_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-OUT_4Pcut')
|
|
reaper.DeleteProjectMarker(0, mark_dstin_id, false) -- remove dst-in marker, this was set just for the pasting!
|
|
elseif edit_mode == 3 or edit_mode == 4 then
|
|
reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_dstout_pos - mark_dstin_pos), 0, 'DST-IN_4Pcut')
|
|
reaper.SetProjectMarker(mark_dstout_id, false, mark_dstout_pos + (mark_dstout_pos - mark_dstin_pos), 0, 'DST-OUT_4Pcut')
|
|
elseif edit_mode == 5 then
|
|
if (mark_srcout_pos - mark_srcin_pos) < (mark_dstout_pos - mark_dstin_pos) then
|
|
reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-IN_4Pcut')
|
|
reaper.SetProjectMarker(mark_dstout_id, false, mark_dstout_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-OUT_4Pcut')
|
|
else
|
|
reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_dstout_pos - mark_dstin_pos), 0, 'DST-IN_4Pcut')
|
|
reaper.SetProjectMarker(mark_dstout_id, false, mark_dstout_pos + (mark_dstout_pos - mark_dstin_pos), 0, 'DST-OUT_4Pcut')
|
|
end
|
|
end
|
|
|
|
-- Restore cursor position, time selection, selected tracks, selected items
|
|
reaper.MoveEditCursor(stored_cursorPos - reaper.GetCursorPosition(), false)
|
|
reaper.Main_OnCommand(40297, 0) -- Unselect all tracks
|
|
for _, track in ipairs(stored_sel_tracks) do
|
|
reaper.SetTrackSelected(track, true)
|
|
end
|
|
reaper.Main_OnCommand(40289, 0) -- Unselect all items
|
|
for _, item in ipairs(stored_sel_items) do
|
|
reaper.SetMediaItemSelected(item, true)
|
|
end
|
|
reaper.GetSet_LoopTimeRange(true, true, stored_timeSelStart, stored_timeSelEnd, false)
|
|
-- Restore view port of arranger
|
|
reaper.GetSet_ArrangeView2(0, true, 0, 0, stored_view_start, stored_view_end)
|
|
|
|
reaper.Undo_EndBlock('4 point cut: Execute', 4) -- 4 is a flag for actions concerning items
|