From 2ba98cd1dee77ea0fa1222cdd0d62bdfc5d5f142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 26 Jan 2020 23:16:30 +0100 Subject: [PATCH 01/20] 4PointCutting: First commit, working but probably not bug-free --- 4PointCutting/4Pcut_execute.lua | 144 ++++++++++++++++++ 4PointCutting/4Pcut_reset_markers.lua | 22 +++ 4PointCutting/4Pcut_reset_src-dest-tracks.lua | 2 + 4PointCutting/4Pcut_select_dst-track.lua | 13 ++ 4PointCutting/4Pcut_select_src-tracks.lua | 22 +++ 4PointCutting/4Pcut_set_DST-IN.lua | 25 +++ 4PointCutting/4Pcut_set_DST-OUT.lua | 25 +++ 4PointCutting/4Pcut_set_SRC-IN.lua | 25 +++ 4PointCutting/4Pcut_set_SRC-OUT.lua | 25 +++ 4PointCutting/4Pcut_set_dst-track.lua | 10 ++ 4PointCutting/4Pcut_set_src-tracks.lua | 14 ++ 4PointCutting/README.md | 2 + 12 files changed, 329 insertions(+) create mode 100644 4PointCutting/4Pcut_execute.lua create mode 100644 4PointCutting/4Pcut_reset_markers.lua create mode 100644 4PointCutting/4Pcut_reset_src-dest-tracks.lua create mode 100644 4PointCutting/4Pcut_select_dst-track.lua create mode 100644 4PointCutting/4Pcut_select_src-tracks.lua create mode 100644 4PointCutting/4Pcut_set_DST-IN.lua create mode 100644 4PointCutting/4Pcut_set_DST-OUT.lua create mode 100644 4PointCutting/4Pcut_set_SRC-IN.lua create mode 100644 4PointCutting/4Pcut_set_SRC-OUT.lua create mode 100644 4PointCutting/4Pcut_set_dst-track.lua create mode 100644 4PointCutting/4Pcut_set_src-tracks.lua create mode 100644 4PointCutting/README.md diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua new file mode 100644 index 0000000..53a1661 --- /dev/null +++ b/4PointCutting/4Pcut_execute.lua @@ -0,0 +1,144 @@ +local stored_cursorPos = 0 +local stored_timeSelStart = 0 +local stored_timeSelEnd = 0 +local stored_sel_tracks = {} +local stored_sel_items = {} +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 + +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +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 + --reaper.Main_OnCommand(40297, 0) -- Unselect all 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 + +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 +-- 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 +if reaper.CountSelectedMediaItems(0) > 0 then + reaper.Main_OnCommand(40289, 0) -- Unselect all items +end +if reaper.CountSelectedTracks(0) > 0then + reaper.Main_OnCommand(40297, 0) -- Unselect all tracks +end +--reaper.Main_OnCommand(40769, 0) +select_src_tracks() -- select tracks specified in rpp (by using 4Pcut_set_src-tracks.lua) + +-- run through all markers and get position of the 4 points +local nof_markers = 0 +_, nof_markers, _ = reaper.CountProjectMarkers(0) +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 + +-- error messages +if mark_srcin_pos < 0 then + msg('Please set Source-In Marker first!') + return +end +if mark_srcout_pos < 0 then + msg('Please set Source-Out Marker first!') +end +if mark_dstin_pos < 0 then + msg('Please set Destination-In Marker first!') + return +end + +-- Do stuff before actual edits... +reaper.Undo_BeginBlock() + + +-- Set Source Time selection and Copy Items +reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false) +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 +-- reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_SMARTCOPY'), 0 ) + + +-- Move edit cursor to Dest-In and Paste +--reaper.GoToMarker(0, mark_dstin_id, false) +-- reaper.GetSet_LoopTimeRange(true, false, mark_dstin_pos, mark_dstout_pos, false) +reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), false) +select_dst_track_only() +reaper.Main_OnCommand(40058, 0) -- paste item +reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-IN_4Pcut') + +-- 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) + +reaper.Undo_EndBlock('4 point cut: Execute', 4) -- 4 is a flag for actions concerning items \ No newline at end of file diff --git a/4PointCutting/4Pcut_reset_markers.lua b/4PointCutting/4Pcut_reset_markers.lua new file mode 100644 index 0000000..80a7387 --- /dev/null +++ b/4PointCutting/4Pcut_reset_markers.lua @@ -0,0 +1,22 @@ +local nof_markers = 0 +local id = -1 +local name = '' +local isregion = false +local ids = {} + +-- check if markers exist +_, nof_markers, _ = reaper.CountProjectMarkers(0) +for i = 0, nof_markers - 1 do + _, isregion, _, _, name, id = reaper.EnumProjectMarkers(i) + if not isregion and + (name == 'SRC-IN_4Pcut' or + name == 'SRC-OUT_4Pcut' or + name == 'DST-IN_4Pcut' or + name == 'DST-OUT_4Pcut') then + table.insert(ids, id) + end +end +-- delete markers +for _, id in ipairs(ids) do + reaper.DeleteProjectMarker(0, id, false) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_reset_src-dest-tracks.lua b/4PointCutting/4Pcut_reset_src-dest-tracks.lua new file mode 100644 index 0000000..8cbbb97 --- /dev/null +++ b/4PointCutting/4Pcut_reset_src-dest-tracks.lua @@ -0,0 +1,2 @@ +reaper.SetProjExtState(0, '4PointCut', 'dst_track', '') +reaper.SetProjExtState(0, '4PointCut', 'src_tracks', '') \ No newline at end of file diff --git a/4PointCutting/4Pcut_select_dst-track.lua b/4PointCutting/4Pcut_select_dst-track.lua new file mode 100644 index 0000000..d9705f7 --- /dev/null +++ b/4PointCutting/4Pcut_select_dst-track.lua @@ -0,0 +1,13 @@ +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +-- START HERE vvvvvvvvvvvvvvvvv +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)) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_select_src-tracks.lua b/4PointCutting/4Pcut_select_src-tracks.lua new file mode 100644 index 0000000..20f3a8a --- /dev/null +++ b/4PointCutting/4Pcut_select_src-tracks.lua @@ -0,0 +1,22 @@ +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +-- START HERE vvvvvvvvvvvvvvvvv +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 + reaper.Main_OnCommand(40297, 0) -- Unselect all tracks + for _, track in ipairs(tracks) do + reaper.SetTrackSelected(track, true) + end +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_DST-IN.lua b/4PointCutting/4Pcut_set_DST-IN.lua new file mode 100644 index 0000000..fc08dc6 --- /dev/null +++ b/4PointCutting/4Pcut_set_DST-IN.lua @@ -0,0 +1,25 @@ +local nof_markers = 0 +local id = -1 + +-- check if marker already exists +_, nof_markers, _ = reaper.CountProjectMarkers(0) +for i = 0, nof_markers - 1 do + local name_tmp = '' + local isregion_tmp = false + local id_tmp = 0 + _, isregion_tmp, _, _, name_tmp, id_tmp = reaper.EnumProjectMarkers(i) + if not isregion then + if name_tmp == 'DST-IN_4Pcut' then + id = id_tmp + break + end + end +end + +if id >= 0 then + -- edit existing marker + reaper.SetProjectMarker(id, false, reaper.GetCursorPosition(), 0, 'DST-IN_4Pcut') +else + -- create new marker + reaper.AddProjectMarker2(0, false, reaper.GetCursorPosition(), 0, 'DST-IN_4Pcut', -1, reaper.ColorToNative(0, 255, 0)|0x1000000) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_DST-OUT.lua b/4PointCutting/4Pcut_set_DST-OUT.lua new file mode 100644 index 0000000..202aff2 --- /dev/null +++ b/4PointCutting/4Pcut_set_DST-OUT.lua @@ -0,0 +1,25 @@ +local nof_markers = 0 +local id = -1 + +-- check if marker already exists +_, nof_markers, _ = reaper.CountProjectMarkers(0) +for i = 0, nof_markers - 1 do + local name_tmp = '' + local isregion_tmp = false + local id_tmp = 0 + _, isregion_tmp, _, _, name_tmp, id_tmp = reaper.EnumProjectMarkers(i) + if not isregion then + if name_tmp == 'DST-OUT_4Pcut' then + id = id_tmp + break + end + end +end + +if id >= 0 then + -- edit existing marker + reaper.SetProjectMarker(id, false, reaper.GetCursorPosition(), 0, 'DST-OUT_4Pcut') +else + -- create new marker + reaper.AddProjectMarker2(0, false, reaper.GetCursorPosition(), 0, 'DST-OUT_4Pcut', -1, reaper.ColorToNative(0, 255, 0)|0x1000000) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_SRC-IN.lua b/4PointCutting/4Pcut_set_SRC-IN.lua new file mode 100644 index 0000000..dbeb5ef --- /dev/null +++ b/4PointCutting/4Pcut_set_SRC-IN.lua @@ -0,0 +1,25 @@ +local nof_markers = 0 +local id = -1 + +-- check if marker already exists +_, nof_markers, _ = reaper.CountProjectMarkers(0) +for i = 0, nof_markers - 1 do + local name_tmp = '' + local isregion_tmp = false + local id_tmp = 0 + _, isregion_tmp, _, _, name_tmp, id_tmp = reaper.EnumProjectMarkers(i) + if not isregion then + if name_tmp == 'SRC-IN_4Pcut' then + id = id_tmp + break + end + end +end + +if id >= 0 then + -- edit existing marker + reaper.SetProjectMarker(id, false, reaper.GetCursorPosition(), 0, 'SRC-IN_4Pcut') +else + -- create new marker + reaper.AddProjectMarker2(0, false, reaper.GetCursorPosition(), 0, 'SRC-IN_4Pcut', -1, reaper.ColorToNative(0, 255, 0)|0x1000000) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_SRC-OUT.lua b/4PointCutting/4Pcut_set_SRC-OUT.lua new file mode 100644 index 0000000..aa93d47 --- /dev/null +++ b/4PointCutting/4Pcut_set_SRC-OUT.lua @@ -0,0 +1,25 @@ +local nof_markers = 0 +local id = -1 + +-- check if marker already exists +_, nof_markers, _ = reaper.CountProjectMarkers(0) +for i = 0, nof_markers - 1 do + local name_tmp = '' + local isregion_tmp = false + local id_tmp = 0 + _, isregion_tmp, _, _, name_tmp, id_tmp = reaper.EnumProjectMarkers(i) + if not isregion then + if name_tmp == 'SRC-OUT_4Pcut' then + id = id_tmp + break + end + end +end + +if id >= 0 then + -- edit existing marker + reaper.SetProjectMarker(id, false, reaper.GetCursorPosition(), 0, 'SRC-OUT_4Pcut') +else + -- create new marker + reaper.AddProjectMarker2(0, false, reaper.GetCursorPosition(), 0, 'SRC-OUT_4Pcut', -1, reaper.ColorToNative(0, 255, 0)|0x1000000) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_dst-track.lua b/4PointCutting/4Pcut_set_dst-track.lua new file mode 100644 index 0000000..ea33216 --- /dev/null +++ b/4PointCutting/4Pcut_set_dst-track.lua @@ -0,0 +1,10 @@ +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +-- START HERE vvvvvvv +if reaper.CountSelectedTracks(0) > 0 then + local first_sel_track = reaper.GetTrackGUID(reaper.GetSelectedTrack(0, 0)) + reaper.SetProjExtState(0, '4PointCut', 'dst_track', first_sel_track) +end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_src-tracks.lua b/4PointCutting/4Pcut_set_src-tracks.lua new file mode 100644 index 0000000..210963d --- /dev/null +++ b/4PointCutting/4Pcut_set_src-tracks.lua @@ -0,0 +1,14 @@ +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +-- START HERE vvvvvvv + +-- get list of selected tracks and make string of GUIDs +local sel_tracks = '' +for i = 0, reaper.CountSelectedTracks(0)-1 do + sel_tracks = sel_tracks .. reaper.GetTrackGUID(reaper.GetSelectedTrack(0, i)) +end +-- store selected tracks to rpp +reaper.SetProjExtState(0, '4PointCut', 'src_tracks', sel_tracks) \ No newline at end of file diff --git a/4PointCutting/README.md b/4PointCutting/README.md new file mode 100644 index 0000000..f8bce9b --- /dev/null +++ b/4PointCutting/README.md @@ -0,0 +1,2 @@ +# 4 Point Cutting (WORK IN PROGRESS) +Brings 4 point editing to reaper... \ No newline at end of file From 8c100ef186c83bbe188a3dad3f27e1298e361719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 26 Jan 2020 23:41:10 +0100 Subject: [PATCH 02/20] 4PointCutting: Cleaned up comments, addd headers --- 4PointCutting/4Pcut_execute.lua | 20 +++++++++++-------- 4PointCutting/4Pcut_reset_markers.lua | 9 +++++++++ 4PointCutting/4Pcut_reset_src-dest-tracks.lua | 8 ++++++++ 4PointCutting/4Pcut_select_dst-track.lua | 10 +++++++++- 4PointCutting/4Pcut_select_src-tracks.lua | 9 +++++++++ 4PointCutting/4Pcut_set_DST-IN.lua | 8 ++++++++ 4PointCutting/4Pcut_set_DST-OUT.lua | 8 ++++++++ 4PointCutting/4Pcut_set_SRC-IN.lua | 8 ++++++++ 4PointCutting/4Pcut_set_SRC-OUT.lua | 8 ++++++++ 4PointCutting/4Pcut_set_dst-track.lua | 9 +++++++++ 4PointCutting/4Pcut_set_src-tracks.lua | 8 ++++++++ 11 files changed, 96 insertions(+), 9 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 53a1661..2b6bf00 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -1,3 +1,12 @@ +-- 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: This script goes with several other scripts that work closely together. + local stored_cursorPos = 0 local stored_timeSelStart = 0 local stored_timeSelEnd = 0 @@ -17,6 +26,7 @@ function msg(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") end +-- Selects the source tracks, or, if not stored in rpp, selects all tracks function select_src_tracks() local tracks_str = '' local tracks = {} @@ -29,7 +39,6 @@ function select_src_tracks() table.insert(tracks, reaper.BR_GetMediaTrackByGUID(0, '{' .. str)) end -- select tracks - --reaper.Main_OnCommand(40297, 0) -- Unselect all tracks for _, track in ipairs(tracks) do reaper.SetTrackSelected(track, true) end @@ -41,6 +50,7 @@ function select_src_tracks() 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 @@ -68,8 +78,7 @@ end if reaper.CountSelectedTracks(0) > 0then reaper.Main_OnCommand(40297, 0) -- Unselect all tracks end ---reaper.Main_OnCommand(40769, 0) -select_src_tracks() -- select tracks specified in rpp (by using 4Pcut_set_src-tracks.lua) +select_src_tracks() -- run through all markers and get position of the 4 points local nof_markers = 0 @@ -113,17 +122,12 @@ end -- Do stuff before actual edits... reaper.Undo_BeginBlock() - -- Set Source Time selection and Copy Items reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false) 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 --- reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_SMARTCOPY'), 0 ) - -- Move edit cursor to Dest-In and Paste ---reaper.GoToMarker(0, mark_dstin_id, false) --- reaper.GetSet_LoopTimeRange(true, false, mark_dstin_pos, mark_dstout_pos, false) reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), false) select_dst_track_only() reaper.Main_OnCommand(40058, 0) -- paste item diff --git a/4PointCutting/4Pcut_reset_markers.lua b/4PointCutting/4Pcut_reset_markers.lua index 80a7387..bc52211 100644 --- a/4PointCutting/4Pcut_reset_markers.lua +++ b/4PointCutting/4Pcut_reset_markers.lua @@ -1,3 +1,12 @@ +-- Reaper Script for 4 point editing. This script deletes all the special markers that are +-- used to define source and destination areas. +-- 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: This script goes with several other scripts that work closely together. + local nof_markers = 0 local id = -1 local name = '' diff --git a/4PointCutting/4Pcut_reset_src-dest-tracks.lua b/4PointCutting/4Pcut_reset_src-dest-tracks.lua index 8cbbb97..208556e 100644 --- a/4PointCutting/4Pcut_reset_src-dest-tracks.lua +++ b/4PointCutting/4Pcut_reset_src-dest-tracks.lua @@ -1,2 +1,10 @@ +-- Reaper Scripts for 4 point editing. This script resets the source and destination tracks to "all" and "first". +-- 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: This script goes with several other scripts that work closely together. + reaper.SetProjExtState(0, '4PointCut', 'dst_track', '') reaper.SetProjExtState(0, '4PointCut', 'src_tracks', '') \ No newline at end of file diff --git a/4PointCutting/4Pcut_select_dst-track.lua b/4PointCutting/4Pcut_select_dst-track.lua index d9705f7..57e3d68 100644 --- a/4PointCutting/4Pcut_select_dst-track.lua +++ b/4PointCutting/4Pcut_select_dst-track.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script selects the previous set destination track +-- 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: This script goes with several other scripts that work closely together. + -- Send a message to the console function msg(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") @@ -6,7 +14,7 @@ end -- START HERE vvvvvvvvvvvvvvvvv local track_str = '' local retval - +-- get the setting stored in rpp and select the track 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)) diff --git a/4PointCutting/4Pcut_select_src-tracks.lua b/4PointCutting/4Pcut_select_src-tracks.lua index 20f3a8a..14efa95 100644 --- a/4PointCutting/4Pcut_select_src-tracks.lua +++ b/4PointCutting/4Pcut_select_src-tracks.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script selects the previous set source tracks +-- 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: This script goes with several other scripts that work closely together. + -- Send a message to the console function msg(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") @@ -8,6 +16,7 @@ local tracks_str = '' local tracks = {} local retval +-- get stored GUIDs from rpp and select the tracks retval, tracks_str = reaper.GetProjExtState(0, '4PointCut', 'src_tracks') if retval > 0 then -- variable exists in rpp -- separate GUIDs and populate track table diff --git a/4PointCutting/4Pcut_set_DST-IN.lua b/4PointCutting/4Pcut_set_DST-IN.lua index fc08dc6..0fdbb55 100644 --- a/4PointCutting/4Pcut_set_DST-IN.lua +++ b/4PointCutting/4Pcut_set_DST-IN.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script sets the Destination Start marker to the position of the edit cursor +-- 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: This script goes with several other scripts that work closely together. + local nof_markers = 0 local id = -1 diff --git a/4PointCutting/4Pcut_set_DST-OUT.lua b/4PointCutting/4Pcut_set_DST-OUT.lua index 202aff2..00f3b27 100644 --- a/4PointCutting/4Pcut_set_DST-OUT.lua +++ b/4PointCutting/4Pcut_set_DST-OUT.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script sets the Destination End marker to the position of the edit cursor +-- 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: This script goes with several other scripts that work closely together. + local nof_markers = 0 local id = -1 diff --git a/4PointCutting/4Pcut_set_SRC-IN.lua b/4PointCutting/4Pcut_set_SRC-IN.lua index dbeb5ef..ca7e335 100644 --- a/4PointCutting/4Pcut_set_SRC-IN.lua +++ b/4PointCutting/4Pcut_set_SRC-IN.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script sets the Source Start marker to the position of the edit cursor +-- 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: This script goes with several other scripts that work closely together. + local nof_markers = 0 local id = -1 diff --git a/4PointCutting/4Pcut_set_SRC-OUT.lua b/4PointCutting/4Pcut_set_SRC-OUT.lua index aa93d47..8a54876 100644 --- a/4PointCutting/4Pcut_set_SRC-OUT.lua +++ b/4PointCutting/4Pcut_set_SRC-OUT.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script sets the Source End marker to the position of the edit cursor +-- 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: This script goes with several other scripts that work closely together. + local nof_markers = 0 local id = -1 diff --git a/4PointCutting/4Pcut_set_dst-track.lua b/4PointCutting/4Pcut_set_dst-track.lua index ea33216..adc81af 100644 --- a/4PointCutting/4Pcut_set_dst-track.lua +++ b/4PointCutting/4Pcut_set_dst-track.lua @@ -1,3 +1,12 @@ +-- Reaper Scripts for 4 point editing. This script sets the Destination track and stores it to the rpp. +-- Only one (the first) selected track is used here. +-- 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: This script goes with several other scripts that work closely together. + -- Send a message to the console function msg(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") diff --git a/4PointCutting/4Pcut_set_src-tracks.lua b/4PointCutting/4Pcut_set_src-tracks.lua index 210963d..952e2c2 100644 --- a/4PointCutting/4Pcut_set_src-tracks.lua +++ b/4PointCutting/4Pcut_set_src-tracks.lua @@ -1,3 +1,11 @@ +-- Reaper Scripts for 4 point editing. This script sets the source tracks and stores it to the rpp. +-- 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: This script goes with several other scripts that work closely together. + -- Send a message to the console function msg(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") From 41572c4f84918d9ee0005d5d401b8917e4dea7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 26 Jan 2020 23:55:03 +0100 Subject: [PATCH 03/20] 4PointCutting: Cleaned up some code, added some error messages --- 4PointCutting/4Pcut_execute.lua | 30 ++++++++++------------- 4PointCutting/4Pcut_select_dst-track.lua | 3 +++ 4PointCutting/4Pcut_select_src-tracks.lua | 3 +++ 4PointCutting/4Pcut_set_dst-track.lua | 3 +++ 4PointCutting/4Pcut_set_src-tracks.lua | 6 ++++- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 2b6bf00..891afec 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -63,23 +63,6 @@ function select_dst_track_only() end -- START HERE vvvvvvvvvvvvvvvvvvvvvvvvvv --- 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 -if reaper.CountSelectedMediaItems(0) > 0 then - reaper.Main_OnCommand(40289, 0) -- Unselect all items -end -if reaper.CountSelectedTracks(0) > 0then - reaper.Main_OnCommand(40297, 0) -- Unselect all tracks -end -select_src_tracks() - -- run through all markers and get position of the 4 points local nof_markers = 0 _, nof_markers, _ = reaper.CountProjectMarkers(0) @@ -121,6 +104,19 @@ end -- Do stuff before actual edits... reaper.Undo_BeginBlock() +-- 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 and Copy Items reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false) diff --git a/4PointCutting/4Pcut_select_dst-track.lua b/4PointCutting/4Pcut_select_dst-track.lua index 57e3d68..1b85236 100644 --- a/4PointCutting/4Pcut_select_dst-track.lua +++ b/4PointCutting/4Pcut_select_dst-track.lua @@ -18,4 +18,7 @@ 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 + reaper.ClearConsole() + msg('Destination track not specified, using first track as default!') end \ No newline at end of file diff --git a/4PointCutting/4Pcut_select_src-tracks.lua b/4PointCutting/4Pcut_select_src-tracks.lua index 14efa95..ad19e91 100644 --- a/4PointCutting/4Pcut_select_src-tracks.lua +++ b/4PointCutting/4Pcut_select_src-tracks.lua @@ -28,4 +28,7 @@ if retval > 0 then -- variable exists in rpp for _, track in ipairs(tracks) do reaper.SetTrackSelected(track, true) end +else + reaper.ClearConsole() + msg('Source tracks not specified, using all tracks as default!') end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_dst-track.lua b/4PointCutting/4Pcut_set_dst-track.lua index adc81af..f038a25 100644 --- a/4PointCutting/4Pcut_set_dst-track.lua +++ b/4PointCutting/4Pcut_set_dst-track.lua @@ -16,4 +16,7 @@ end if reaper.CountSelectedTracks(0) > 0 then local first_sel_track = reaper.GetTrackGUID(reaper.GetSelectedTrack(0, 0)) reaper.SetProjExtState(0, '4PointCut', 'dst_track', first_sel_track) +else + reaper.ClearConsole() + msg('No track selected!') end \ No newline at end of file diff --git a/4PointCutting/4Pcut_set_src-tracks.lua b/4PointCutting/4Pcut_set_src-tracks.lua index 952e2c2..871fa1a 100644 --- a/4PointCutting/4Pcut_set_src-tracks.lua +++ b/4PointCutting/4Pcut_set_src-tracks.lua @@ -12,7 +12,11 @@ function msg(m) end -- START HERE vvvvvvv - +if reaper.CountSelectedTracks(0) <= 0 then + reaper.ClearConsole() + msg('No track selected!') + return +end -- get list of selected tracks and make string of GUIDs local sel_tracks = '' for i = 0, reaper.CountSelectedTracks(0)-1 do From 66bca386387d28393e2f011af0aae8381f0e6056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Mon, 27 Jan 2020 13:23:42 +0100 Subject: [PATCH 04/20] 4PointCutting: Restore arranger viewport after edit --- 4PointCutting/4Pcut_execute.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 891afec..aa1900d 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -12,6 +12,8 @@ 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 @@ -26,6 +28,12 @@ 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 = '' @@ -104,6 +112,9 @@ 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) @@ -140,5 +151,7 @@ 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 \ No newline at end of file +reaper.Undo_EndBlock('4 point cut: Execute', 4) -- 4 is a flag for actions concerning items From 4238d6a104a9d63d7b65db7a3834255196fd2a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Mon, 27 Jan 2020 23:54:32 +0100 Subject: [PATCH 05/20] 4PointCutting: Added modes for every possible combination of 3 or 4 out of the 4 markers --- 4PointCutting/4Pcut_execute.lua | 72 +++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index aa1900d..0999793 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -22,6 +22,10 @@ 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 waitcount = 0 +-- 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) @@ -97,17 +101,27 @@ for i = 0, nof_markers - 1 do 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 mark_srcin_pos < 0 then - msg('Please set Source-In Marker first!') - return -end -if mark_srcout_pos < 0 then - msg('Please set Source-Out Marker first!') -end -if mark_dstin_pos < 0 then - msg('Please set Destination-In Marker first!') +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.') +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.') end -- Do stuff before actual edits... @@ -129,8 +143,25 @@ reaper.Main_OnCommand(40289, 0) -- Unselect all items reaper.Main_OnCommand(40297, 0) -- Unselect all tracks select_src_tracks() --- Set Source Time selection and Copy Items -reaper.GetSet_LoopTimeRange(true, false, mark_srcin_pos, mark_srcout_pos, false) +-- 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 +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 @@ -138,7 +169,24 @@ reaper.Main_OnCommand(40060, 0) -- copy selected items under time selection 4138 reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), false) select_dst_track_only() reaper.Main_OnCommand(40058, 0) -- paste item -reaper.SetProjectMarker(mark_dstin_id, false, mark_dstin_pos + (mark_srcout_pos - mark_srcin_pos), 0, 'DST-IN_4Pcut') +--reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWPASTE'), 0 ) -- SWS Paste +-- 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') +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) From d2b992f1f0d8e016f2a30b652408228a22f2828e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Fri, 31 Jan 2020 22:08:08 +0100 Subject: [PATCH 06/20] Now also works if project contains regions - closes #1 --- 4PointCutting/4Pcut_execute.lua | 4 +++- 4PointCutting/4Pcut_reset_markers.lua | 4 +++- 4PointCutting/4Pcut_set_DST-IN.lua | 4 +++- 4PointCutting/4Pcut_set_DST-OUT.lua | 4 +++- 4PointCutting/4Pcut_set_SRC-IN.lua | 4 +++- 4PointCutting/4Pcut_set_SRC-OUT.lua | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 0999793..f4b3c1d 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -77,7 +77,9 @@ end -- START HERE vvvvvvvvvvvvvvvvvvvvvvvvvv -- run through all markers and get position of the 4 points local nof_markers = 0 -_, nof_markers, _ = reaper.CountProjectMarkers(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 diff --git a/4PointCutting/4Pcut_reset_markers.lua b/4PointCutting/4Pcut_reset_markers.lua index bc52211..2a02467 100644 --- a/4PointCutting/4Pcut_reset_markers.lua +++ b/4PointCutting/4Pcut_reset_markers.lua @@ -8,13 +8,15 @@ -- Requires: This script goes with several other scripts that work closely together. local nof_markers = 0 +local nof_regions = 0 local id = -1 local name = '' local isregion = false local ids = {} -- check if markers exist -_, nof_markers, _ = reaper.CountProjectMarkers(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 _, isregion, _, _, name, id = reaper.EnumProjectMarkers(i) if not isregion and diff --git a/4PointCutting/4Pcut_set_DST-IN.lua b/4PointCutting/4Pcut_set_DST-IN.lua index 0fdbb55..54940ea 100644 --- a/4PointCutting/4Pcut_set_DST-IN.lua +++ b/4PointCutting/4Pcut_set_DST-IN.lua @@ -7,10 +7,12 @@ -- Requires: This script goes with several other scripts that work closely together. local nof_markers = 0 +local nof_regions = 0 local id = -1 -- check if marker already exists -_, nof_markers, _ = reaper.CountProjectMarkers(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_tmp = '' local isregion_tmp = false diff --git a/4PointCutting/4Pcut_set_DST-OUT.lua b/4PointCutting/4Pcut_set_DST-OUT.lua index 00f3b27..1f9a3a4 100644 --- a/4PointCutting/4Pcut_set_DST-OUT.lua +++ b/4PointCutting/4Pcut_set_DST-OUT.lua @@ -7,10 +7,12 @@ -- Requires: This script goes with several other scripts that work closely together. local nof_markers = 0 +local nof_regions = 0 local id = -1 -- check if marker already exists -_, nof_markers, _ = reaper.CountProjectMarkers(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_tmp = '' local isregion_tmp = false diff --git a/4PointCutting/4Pcut_set_SRC-IN.lua b/4PointCutting/4Pcut_set_SRC-IN.lua index ca7e335..e6d253e 100644 --- a/4PointCutting/4Pcut_set_SRC-IN.lua +++ b/4PointCutting/4Pcut_set_SRC-IN.lua @@ -7,10 +7,12 @@ -- Requires: This script goes with several other scripts that work closely together. local nof_markers = 0 +local nof_regions = 0 local id = -1 -- check if marker already exists -_, nof_markers, _ = reaper.CountProjectMarkers(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_tmp = '' local isregion_tmp = false diff --git a/4PointCutting/4Pcut_set_SRC-OUT.lua b/4PointCutting/4Pcut_set_SRC-OUT.lua index 8a54876..20bb028 100644 --- a/4PointCutting/4Pcut_set_SRC-OUT.lua +++ b/4PointCutting/4Pcut_set_SRC-OUT.lua @@ -7,10 +7,12 @@ -- Requires: This script goes with several other scripts that work closely together. local nof_markers = 0 +local nof_regions = 0 local id = -1 -- check if marker already exists -_, nof_markers, _ = reaper.CountProjectMarkers(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_tmp = '' local isregion_tmp = false From 765494f460a9012a6583207af47c9720021bb6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sat, 1 Feb 2020 23:17:46 +0100 Subject: [PATCH 07/20] 4PointCutting: Added crossfade after execution. closes #2 --- 4PointCutting/4Pcut_execute.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index f4b3c1d..e596635 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -5,6 +5,7 @@ -- 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 @@ -23,7 +24,7 @@ local mark_dstin_id = -1 local mark_dstout_pos = -1 local mark_dstout_id = -1 local edit_mode = 0 -local waitcount = 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; @@ -75,6 +76,8 @@ function select_dst_track_only() 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 @@ -172,6 +175,12 @@ reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), 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") +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_AWFILLGAPSQUICKXFADE'), 0 ) -- fill gaps between selected items and crossfade -- 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') From 7465bd93600a2cf135218b3ba4061777acb898d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 00:08:16 +0100 Subject: [PATCH 08/20] 4PointCutting: Only try to crossfade if SWS is present --- 4PointCutting/4Pcut_execute.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index e596635..8db6c37 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -176,12 +176,14 @@ 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") -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_AWFILLGAPSQUICKXFADE'), 0 ) -- fill gaps between selected items and crossfade --- Move dstin marker according to edit mode +if sws_present then + 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_AWFILLGAPSQUICKXFADE'), 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 From 66b60f558c0187eefac425679a4b775332192977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sat, 1 Feb 2020 23:08:24 +0000 Subject: [PATCH 09/20] 4PointCutting: Added description in README --- 4PointCutting/README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/4PointCutting/README.md b/4PointCutting/README.md index f8bce9b..d3b5f2d 100644 --- a/4PointCutting/README.md +++ b/4PointCutting/README.md @@ -1,2 +1,30 @@ # 4 Point Cutting (WORK IN PROGRESS) -Brings 4 point editing to reaper... \ No newline at end of file +This set of scripts is an attempt to bring the famous 4 point editing features known from Magix' Sequoia to reaper. +## Requirements +Crossfades between the pasted items only can be made if SWS extensions (http://standingwaterstudios.com/) are installed. The SWS "Fill Gaps" function is used for that, so the crossfade settings inside SWS are applied. +## Usage +### Basic functionality +* Set the beginning of the "source" region, from which the audio material will be copied by executing `4Pcut_set_SRC-IN` +* Set the end of the "source" region, from which the audio material will be copied by executing `4Pcut_set_SRC-OUT` +* Set the beginning of the "destination" region, to that the audio material will be copied by executing `4Pcut_set_DST-IN` +* Do the actual edit by executing `4Pcut_execute` +* Find the next source region you want to add and place source-in and source-out markers accordingly and run the execute script again. The destination marker(s) will be set automatically. + +### Edit modes +The script can be run with every combination of 3 markers. The two of them that specify a complete "region" (src-in and src-out or dst-in and dst-out) are used to determine the length of material to copy. The third marker only needs to specify one point of the other region, the length will be the same as the other region. +* `src-in`, `src-out`, `dst-in` set: Audio from the region between src-in and src-out will be copied after dst-in. dst-in will be moved to the right about the length of the copied material. +* `src-in`, `src-out`, `dst-out` set: Audio from the region between src-in and src-out will be copied before dst-out. dst-out will be set to the right about the length of the copied material +* `src-in`, `dst-in`, `dst-in` set: Audio from the src-in point with the length of the region between dst-in and dst-out will be copied after dst-in. dst-in and dst-out will be moved to the right about the length of the copied material. +* `src-out`, `dst-in`, `dst-out` set: Audio from the left of the src-out point with the length of the region between dst-in and dst-out will be copied after dst-in. dst-in and dst-out will be moved to the right about the length of the copied material. + +If all 4 markers are set, the shorter region of the 2 specifies the length to be copied. The dst-in and dst-out markers will be moved to the right about the length of the copied material. + +### Scripts +* `4Pcut_set_src-in`, `4Pcut_set_src-out`, `4Pcut_set_dst-in` and `4Pcut_set_dst_out` set markers with special names that are used to specify the source and destination regions to be edited. +* `4Pcut_reset_markers` deletes all four of the special markers, if present. +* `4Pcut_execute` executes one edit, copies the audio material from source to destination and sets the destination markers accordingly for the next edit step. +* `4Pcut_set_src-tracks` sets the currently selected tracks as the source tracks from which audio material will be copied. If unset, all tracks will be used. +* `4Pcut_set_dst-track` sets the first of the currently selected tracks as the first destination track to which audio material will be copied. If unset, track one will be used. +* `4Pcut_select_src-tracks` selects the stored source tracks set by `4Pcut_set_src-tracks`. +* `4Pcut_select_dst-track` selects the stored destination track set by `4Pcut_set_dst-track`. +* `4Pcut_reset_src-dst-tracks` resets the source tracks to "all" and the destination track to track one. From 11af6dda0aab4698d4f2bc593c0dff15b4a93284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 00:17:55 +0100 Subject: [PATCH 10/20] 4PointCutting: Added screenshots --- 4PointCutting/screenshots/3markers.PNG | Bin 0 -> 43423 bytes 4PointCutting/screenshots/3markers_1edit.PNG | Bin 0 -> 43649 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 4PointCutting/screenshots/3markers.PNG create mode 100644 4PointCutting/screenshots/3markers_1edit.PNG diff --git a/4PointCutting/screenshots/3markers.PNG b/4PointCutting/screenshots/3markers.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a1388ee66f4a03be228956fb71fe50b4f3315e31 GIT binary patch literal 43423 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 BT-yKu literal 0 HcmV?d00001 diff --git a/4PointCutting/screenshots/3markers_1edit.PNG b/4PointCutting/screenshots/3markers_1edit.PNG new file mode 100644 index 0000000000000000000000000000000000000000..424c0bc44567ebe7c061971a104dd4ddb1b5f9c0 GIT binary patch literal 43649 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 Date: Sun, 2 Feb 2020 00:21:41 +0100 Subject: [PATCH 11/20] 4PointCutting: Add crossfade not only on first destination track but on all. --- 4PointCutting/4Pcut_execute.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 8db6c37..02eda41 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -177,6 +177,13 @@ 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 From c9c84de9f2c0390d54d2d09b0d0a5f6f81fae238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sat, 1 Feb 2020 23:26:31 +0000 Subject: [PATCH 12/20] 4PointCutting: Added screenshots to README --- 4PointCutting/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/4PointCutting/README.md b/4PointCutting/README.md index d3b5f2d..02a3344 100644 --- a/4PointCutting/README.md +++ b/4PointCutting/README.md @@ -28,3 +28,9 @@ If all 4 markers are set, the shorter region of the 2 specifies the length to be * `4Pcut_select_src-tracks` selects the stored source tracks set by `4Pcut_set_src-tracks`. * `4Pcut_select_dst-track` selects the stored destination track set by `4Pcut_set_dst-track`. * `4Pcut_reset_src-dst-tracks` resets the source tracks to "all" and the destination track to track one. + +## Screenshots +Markers set: +![](https://files.eleton-audio.de/gitea/Ludwig/Reaper-Scripts/raw/branch/4PointCutting/4PointCutting/screenshots/3markers.PNG) +After execution: +![](https://files.eleton-audio.de/gitea/Ludwig/Reaper-Scripts/raw/branch/4PointCutting/4PointCutting/screenshots/3markers_1edit.PNG) \ No newline at end of file From f7734e9511b29ee42e3bb88d34dd778e7117de2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 00:29:59 +0100 Subject: [PATCH 13/20] 4PointCutting: Really abort execution when markers don't specify a valid region (missing return statement) --- 4PointCutting/4Pcut_execute.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 02eda41..0e56d13 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -125,8 +125,10 @@ if edit_mode <= 0 then 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... From 903086d383327b32df182b880d60c98f3eb75b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 01:56:55 +0100 Subject: [PATCH 14/20] 4PointCutting: Replaced "Fill Gaps" with true "Crossfade" --- 4PointCutting/4Pcut_execute.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 0e56d13..c7ebedc 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -190,7 +190,7 @@ if sws_present then 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_AWFILLGAPSQUICKXFADE'), 0 ) -- fill gaps between selected items and crossfade + 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 From ef30edcf2fa46611f15b2a0cb48c12c9ebb459db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 02:02:14 +0100 Subject: [PATCH 15/20] 4PointCutting: Switched to SWS paste, somehow this improves reliability... --- 4PointCutting/4Pcut_execute.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index c7ebedc..428399c 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -175,8 +175,8 @@ reaper.Main_OnCommand(40060, 0) -- copy selected items under time selection 4138 -- Move edit cursor to Dest-In and Paste reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), false) select_dst_track_only() -reaper.Main_OnCommand(40058, 0) -- paste item ---reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWPASTE'), 0 ) -- SWS Paste +--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 From 8deb166f31e4fb40829ef42182e9bab67b5b4729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 02:16:11 +0100 Subject: [PATCH 16/20] 4PointCutting: Changed to "GoToMarker()" from "MoveEditCursor()" to prevent from occasionaly audio playback during execution --- 4PointCutting/4Pcut_execute.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 428399c..19ea2c7 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -156,6 +156,7 @@ if edit_mode == 1 then -- src-in, src-out and dst-in defined 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 @@ -173,7 +174,7 @@ reaper.Main_OnCommand(40718, 0) -- select items on selected tracks under time se reaper.Main_OnCommand(40060, 0) -- copy selected items under time selection 41383 -- Move edit cursor to Dest-In and Paste -reaper.MoveEditCursor(mark_dstin_pos - reaper.GetCursorPosition(), false) +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 @@ -197,6 +198,7 @@ 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') From eb305bc83647d2eb586e045559b56ef744fd953e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 01:19:32 +0000 Subject: [PATCH 17/20] 4PointCutting: Updated README --- 4PointCutting/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4PointCutting/README.md b/4PointCutting/README.md index 02a3344..082e6d7 100644 --- a/4PointCutting/README.md +++ b/4PointCutting/README.md @@ -1,7 +1,7 @@ # 4 Point Cutting (WORK IN PROGRESS) This set of scripts is an attempt to bring the famous 4 point editing features known from Magix' Sequoia to reaper. ## Requirements -Crossfades between the pasted items only can be made if SWS extensions (http://standingwaterstudios.com/) are installed. The SWS "Fill Gaps" function is used for that, so the crossfade settings inside SWS are applied. +This script does not work properly without SWS extensions (get them for free from http://standingwaterstudios.com/). ## Usage ### Basic functionality * Set the beginning of the "source" region, from which the audio material will be copied by executing `4Pcut_set_SRC-IN` From 6438d7c8da49454a3464c64f9f91f8bda23580e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sun, 2 Feb 2020 02:28:18 +0100 Subject: [PATCH 18/20] 4PointCutting: Make SWS extension neccessary for script. Abort if not present. --- 4PointCutting/4Pcut_execute.lua | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 19ea2c7..d1defd1 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -129,6 +129,9 @@ elseif (edit_mode == 1 or edit_mode == 2 or edit_mode == 5) and (mark_srcin_pos 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 +elseif not sws_present then + msg('SWS extensions are not installed but needed! Aborting.') + return end -- Do stuff before actual edits... @@ -178,22 +181,21 @@ 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 + +-- Crossfade +local selected_items_count = reaper.CountSelectedMediaItems(0) +for i = 0, selected_items_count - 1 do -- select tracks with selected items... + local item = reaper.GetSelectedMediaItem(0, i) + local track = reaper.GetMediaItem_Track(item) + reaper.SetTrackSelected(track, true) end - -- Move dstin marker according to edit mode +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 ) -- Crossfade adjacent selected items + +-- 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 From 98174656819c0d87344fc02bb3a253052fa2150a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Tue, 22 Sep 2020 21:09:02 +0200 Subject: [PATCH 19/20] 4PointCutting: Trim content behind pasted items even if according edit setting is off. closes #5 --- 4PointCutting/4Pcut_execute.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index d1defd1..9f51168 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -182,6 +182,9 @@ select_dst_track_only() --reaper.Main_OnCommand(40058, 0) -- paste item reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWPASTE'), 0 ) -- SWS Paste +-- Remove content behind selected items (avoid overlapping). Only really needed if "Trim content behind media items when editing" is off. +reaper.Main_OnCommand( 40930, 0 ) -- Remove content (trim) behind items + -- Crossfade local selected_items_count = reaper.CountSelectedMediaItems(0) for i = 0, selected_items_count - 1 do -- select tracks with selected items... From a5072fc596bd4b05b2959e314f02dda1040573ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Tue, 22 Sep 2020 21:10:58 +0200 Subject: [PATCH 20/20] 4PointCutting: fix track alignment of pasted items if first source tracks are empty in time selection. closes #4 --- 4PointCutting/4Pcut_execute.lua | 62 ++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/4PointCutting/4Pcut_execute.lua b/4PointCutting/4Pcut_execute.lua index 9f51168..4d64fd9 100644 --- a/4PointCutting/4Pcut_execute.lua +++ b/4PointCutting/4Pcut_execute.lua @@ -5,7 +5,7 @@ -- 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: SWS extensions. http://standingwaterstudios.com -- Requires: This script goes with several other scripts that work closely together. local stored_cursorPos = 0 @@ -23,6 +23,7 @@ local mark_dstin_pos = -1 local mark_dstin_id = -1 local mark_dstout_pos = -1 local mark_dstout_id = -1 +local dst_track_offset = 0 -- if the uppermost item is not on the first sourcetrack, this offset needs to be applied to the dst-track selection 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; @@ -39,6 +40,35 @@ function round(num, numDecimalPlaces) return math.floor(num * mult + 0.5) / mult end +-- Calculate offset between first source track and uppermost source item (how many +-- tracks are empty in source selection on top). This needs to be applied to destination +-- track selection, otherwise the items will be pasted shifted upwards. +-- This function depends on the source tracks AND items to be already selected, +-- it does not care about any markers or stored sourcetracks! +function calculate_track_offset() + local first_sel_track = 9999 + local uppermost_item_track = 9999 + + -- get number of first selected track + for i = 0, reaper.CountSelectedTracks(0)-1 do + local nof_track = reaper.GetMediaTrackInfo_Value(reaper.GetSelectedTrack(0, i), "IP_TRACKNUMBER") + if nof_track < first_sel_track then + first_sel_track = nof_track + end + end + + -- get tracknumber of first selected item + for i = 0, reaper.CountSelectedMediaItems(0)-1 do + local trackno_item = reaper.GetMediaTrackInfo_Value(reaper.GetMediaItemTrack(reaper.GetSelectedMediaItem(0, i)), "IP_TRACKNUMBER") + if trackno_item < uppermost_item_track then + uppermost_item_track = trackno_item + end + end + + -- calculate offset + dst_track_offset = uppermost_item_track - first_sel_track +end + -- Selects the source tracks, or, if not stored in rpp, selects all tracks function select_src_tracks() local tracks_str = '' @@ -64,15 +94,36 @@ function select_src_tracks() end -- Select the destination tracks, or, if not stored in rpp, the first track +-- Also a offset must be specified which will be applied to the tracknumber to select function select_dst_track_only() local track_str = '' local retval + local raw_dst_track + + -- Get "raw" track, without offset 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)) + raw_dst_track = reaper.BR_GetMediaTrackByGUID(0, track_str) else --default to first track - reaper.SetOnlyTrackSelected(reaper.GetTrack(0, 0)) + raw_dst_track = reaper.GetTrack(0, 0) end + + if dst_track_offset <= 0 then + -- no offset to respect, easy + reaper.SetOnlyTrackSelected(raw_dst_track) + else + local trackno_dst_track = reaper.GetMediaTrackInfo_Value(raw_dst_track, "IP_TRACKNUMBER") + dst_track_offset + -- Run trough all tracks, select the one with the matching tracknumber and return + for i = 0, reaper.CountTracks(0)-1 do + local nof_track = reaper.GetMediaTrackInfo_Value(reaper.GetTrack(0, i), "IP_TRACKNUMBER") + if nof_track == trackno_dst_track then + reaper.SetOnlyTrackSelected(reaper.GetTrack(0, i)) + return + end + end + end + -- In theory should never be reached, use raw track as fallback, probably something is wrong with the offset: + reaper.SetOnlyTrackSelected(raw_dst_track) end -- START HERE vvvvvvvvvvvvvvvvvvvvvvvvvv @@ -176,9 +227,12 @@ end 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 +-- Calculate track offset between first selected item and first dst-track +calculate_track_offset() + -- Move edit cursor to Dest-In and Paste reaper.GoToMarker(0, mark_dstin_id, false) -select_dst_track_only() +select_dst_track_only() --reaper.Main_OnCommand(40058, 0) -- paste item reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWPASTE'), 0 ) -- SWS Paste