|
|
|
06-07-2012, 04:21 AM
|
#1
|
Human being with feelings
Join Date: Mar 2010
Posts: 4,713
|
Copy and Paste ReaScript functions
Currently to copy/paste items in a script we have to chain built-in actions.
Could we have something like the following:
Code:
void CopyMediaItem(MediaItem* item, double starttime, double endtime)
void PasteMediaItem(MediaTrack* tr, double starttime)
... and have these not update the arrange view when called (as the "SplitMediaItem" function is now).
This way, we could make scripts which feel more like actions and less like macros, and could be faster as well. We wouldn't need to select a track first, move the edit cursor or worry about the edit cursor moving on paste (depending on user's preferences)
|
|
|
06-18-2012, 02:51 AM
|
#2
|
Human being with feelings
Join Date: Mar 2010
Posts: 4,713
|
Nobody?
|
|
|
03-21-2019, 04:28 AM
|
#3
|
Human being with feelings
Join Date: Feb 2017
Location: Belgrade, Serbia
Posts: 338
|
Is this really still unavailable?
|
|
|
03-21-2019, 09:03 AM
|
#4
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Create new item with API and apply source item chunk to it.
|
|
|
03-21-2019, 09:41 AM
|
#5
|
Human being with feelings
Join Date: Feb 2017
Location: Belgrade, Serbia
Posts: 338
|
That's exactly what I did.
Thanks anyway.
Here's a LUA reascript function for everyone else.
Code:
function CopyMediaItem (itemToCopy,destinationTrack,position)
reaper.PreventUIRefresh( 1 )
local original_position = reaper.GetMediaItemInfo_Value( itemToCopy, "D_POSITION" )
reaper.SetMediaItemInfo_Value( itemToCopy, "D_POSITION" , position )
local retval, chunk = reaper.GetItemStateChunk( itemToCopy, "", false )
local temp_item = reaper.CreateNewMIDIItemInProj( destinationTrack, 3, 0.1, false )
reaper.SetMediaItemInfo_Value( itemToCopy, "D_POSITION" , original_position )
reaper.SetItemStateChunk( temp_item, chunk, false )
reaper.PreventUIRefresh( -1 )
end
And this is how you use it:
Code:
CopyMediaItem(myItem,myTrack,1.5)
|
|
|
03-21-2019, 10:46 AM
|
#6
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
Is it ok, if I add that function to my Ultraschall-API?
|
|
|
03-21-2019, 10:55 AM
|
#7
|
Human being with feelings
Join Date: Feb 2017
Location: Belgrade, Serbia
Posts: 338
|
Yes of course.
|
|
|
03-21-2019, 01:15 PM
|
#8
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Quote:
Originally Posted by nikolalkc
That's exactly what I did.
Thanks anyway.
Here's a LUA reascript function for everyone else.
Code:
function CopyMediaItem (itemToCopy,destinationTrack,position)
reaper.PreventUIRefresh( 1 )
local original_position = reaper.GetMediaItemInfo_Value( itemToCopy, "D_POSITION" )
reaper.SetMediaItemInfo_Value( itemToCopy, "D_POSITION" , position )
local retval, chunk = reaper.GetItemStateChunk( itemToCopy, "", false )
local temp_item = reaper.CreateNewMIDIItemInProj( destinationTrack, 3, 0.1, false )
reaper.SetMediaItemInfo_Value( itemToCopy, "D_POSITION" , original_position )
reaper.SetItemStateChunk( temp_item, chunk, false )
reaper.PreventUIRefresh( -1 )
end
And this is how you use it:
Code:
CopyMediaItem(myItem,myTrack,1.5)
|
I would also recommend to replace GUID in new item chunk by generated one.
|
|
|
03-22-2019, 01:05 AM
|
#10
|
Human being with feelings
Join Date: Feb 2017
Location: Belgrade, Serbia
Posts: 338
|
Quote:
Originally Posted by mpl
I would also recommend to replace GUID in new item chunk by generated one.
|
Does this mean that in my case original item and copied item have the same GUID?
What's the danger of not changing it in item chunk?
|
|
|
03-22-2019, 02:31 AM
|
#11
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,902
|
@niko
Imcompatibility with all other actions / scripts which need unique GUID to work.
|
|
|
03-22-2019, 05:54 AM
|
#12
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
Quote:
Originally Posted by nikolalkc
Does this mean that in my case original item and copied item have the same GUID?
What's the danger of not changing it in item chunk?
|
The GUID and the IGUID are unique identifiers, that help Reaper and extensions/scripts to differentiate between two MediaItems, who share otherwise the same attributes/characteristics.
So changing them both is a very good idea. Helps Reaper as well, when saving and reloading a project.
|
|
|
12-13-2020, 12:43 AM
|
#13
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
Trying to use Nikola function to MIDI copy, and have independent IGUID. So tried to join with X-Raym function to gsub inside the chunk of the item. But the chunk that is getting back for some reason is lacking info.
Code:
function CopyMediaItem(item, track, position)
reaper.SetMediaItemInfo_Value( item, "D_POSITION" , position )
local retval, chunk = reaper.GetItemStateChunk( item, "", false )
local new_item = reaper.CreateNewMIDIItemInProj( track, 3, 0.1 )
local new_item_guid = reaper.BR_GetMediaItemGUID(new_item)
new_item_chunk = chunk:gsub('IGUID ({.+})', 'IGUID ' .. new_item_guid)
reaper.SetItemStateChunk( new_item, new_item_chunk , false )
end
Do I need to change that 'IGUID ({.+})'? I think it is altering all the chunk after IGUID instead of just that part
|
|
|
12-13-2020, 01:22 AM
|
#14
|
Human being with feelings
Join Date: Dec 2017
Posts: 152
|
https://github.com/bfut/ReaScripts/b...ted%20item.lua
bfut_GetSetItemChunkValue() (GPLv3)
bfut_ResetAllChunkGuids()(GPLv3)
Perhaps this is relevant. Note, these assume that there are no conflicts.
If you end up using these, I'd be interested how it works out and which OS you use.
edit: I'd love if either reaper or sws would implement string split for Lua.
Last edited by tufb; 12-13-2020 at 08:21 AM.
|
|
|
12-13-2020, 05:01 PM
|
#15
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
hmm this is usefull, trying to understand how could I add this, I more or less solved my problem using the code this:
Code:
function CopyMediaItem(item, track, position)
reaper.SetMediaItemInfo_Value( item, "D_POSITION" , position )
local retval, chunk = reaper.GetItemStateChunk( item, "", false )
local new_item = reaper.CreateNewMIDIItemInProj( track, 3, 0.1 )
local new_item_guid = reaper.BR_GetMediaItemGUID(new_item)
reaper.SetItemStateChunk( new_item, chunk, false )
reaper.Main_OnCommand(41613, 0) -- Item: Remove active take from MIDI source data pool (AKA un-pool, un-ghost, make unique)
end
but IDK if this can have not seen consequences
|
|
|
12-13-2020, 05:50 PM
|
#16
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,902
|
@daniellumertz
Better use the native copy and paste funciton inside your script,
So that you are sure it will behave as intented (generating new GUIS for items, takes and everything which need GUID, also taking care of several other things like auto cross fades, items follow envelope, ripple editing state...)
|
|
|
12-13-2020, 06:46 PM
|
#17
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
Quote:
Originally Posted by X-Raym
@daniellumertz
Better use the native copy and paste funciton inside your script,
So that you are sure it will behave as intented (generating new GUIS for items, takes and everything which need GUID, also taking care of several other things like auto cross fades, items follow envelope, ripple editing state...)
|
The problem is that It must not copy envelopes ( independent if the user have items follow envelopes on ) and because of ripple editing, independent if it is on the paste should not trigger it, is a very specific case hehe. Thanks
|
|
|
12-14-2020, 02:42 AM
|
#18
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,902
|
@daniellumertz
The trick is just to toggle off these off within the script,
and then toggle it back.
Then your copy paste will be transparent :P
|
|
|
12-14-2020, 11:01 AM
|
#19
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
this is a way also! heheh thanks! time to think which way should I took with the script, not for only that but other things hahaha decisions decisions .....
|
|
|
12-18-2020, 11:54 PM
|
#20
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
Quote:
Originally Posted by tufb
https://github.com/bfut/ReaScripts/b...ted%20item.lua
bfut_GetSetItemChunkValue() (GPLv3)
bfut_ResetAllChunkGuids()(GPLv3)
Perhaps this is relevant. Note, these assume that there are no conflicts.
If you end up using these, I'd be interested how it works out and which OS you use.
edit: I'd love if either reaper or sws would implement string split for Lua.
|
Tested bfut_ResetAllChunkGuids() and worked nice here for changing GUID and IGUID thankss! windows 10 here can test in a mac I have to see if it works too
just wondering why in the script exemple you use bfut_GetSetItemChunkValue() to change IGUID inseted of bfut_ResetAllChunkGuids()
edit: also why the while loop in the function?
Last edited by daniellumertz; 12-19-2020 at 12:16 AM.
|
|
|
12-19-2020, 10:54 AM
|
#21
|
Human being with feelings
Join Date: Dec 2017
Posts: 152
|
Cheers, that's good news. Thanks for testing. Mac would be interesting, as I can't test that. I never had a bug report related to my replacement scripts, but, you know.
IGUID is a unique field. All the other ID fields are related to FX, takes etc., and in general not unique fields in an item chunk, hence the while to replace all occurences. MIDI takes are a special case, where pooled/ghost sheets share a single ID across items.
Last edited by tufb; 12-19-2020 at 11:15 AM.
|
|
|
05-16-2021, 11:00 PM
|
#22
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
Quote:
Originally Posted by X-Raym
@daniellumertz
Better use the native copy and paste funciton inside your script,
So that you are sure it will behave as intented (generating new GUIS for items, takes and everything which need GUID, also taking care of several other things like auto cross fades, items follow envelope, ripple editing state...)
|
Ok I am considering doing a function to use the MainOnCommand and bypass all trim, ripple edit options that might be on. But meanwhile I did this function that might be helpfull,
Code:
function print(...)
for k,v in ipairs({...}) do
reaper.ShowConsoleMsg(tostring(v))
end
reaper.ShowConsoleMsg("\n")
end
function bfut_ResetAllChunkGuids(item_chunk, key) -- (I changed a little but it is from here: https://github.com/bfut/ReaScripts/blob/main/Items%20Editing/bfut_Replace%20item%20under%20mouse%20cursor%20with%20selected%20item.lua
item_chunk = item_chunk:gsub('%s('..key..')%s+.-[\r]-[%\n]', "\ntemp%1 "..reaper.genGuid("").."\n", 1)
return item_chunk:gsub('temp'..key, key), true
end
function ChangeChunkPosition(item_chunk, newpos)
local new_chunk = item_chunk:gsub("POSITION [%d%.]+","POSITION "..tostring(newpos))
return new_chunk
end
function LoadSelectedItems(list) -- Not used it is here in case you need
reaper.Main_OnCommand(40289, 0)--Item: Unselect all items
if #list ~= 0 then
for i = 1, #list do
local bol = reaper.ValidatePtr( list[i] ,"MediaItem*" )
if bol then
reaper.SetMediaItemSelected( list[i], true )
end
end
end
end
function SaveSelectedItems() -- Not used it is here in case you need
local list = {}
local num = reaper.CountSelectedMediaItems(0)
if num ~= 0 then
for i= 0, num-1 do
list[i+1] = reaper.GetSelectedMediaItem( 0, i )
end
end
--reaper.Main_OnCommand(40289, 0)--Item: Unselect all items
return list
end
function CopyTakeInfo(take_copy, take_paste) -- Copy every info you can with reaper.SetMediaItemTakeInfo_Value()
local names = [[
D_STARTOFFS
D_VOL
D_PAN
D_PANLAW
D_PLAYRATE
D_PITCH
B_PPITCH
I_CHANMODE
I_PITCHMODE
I_CUSTOMCOLOR
IP_TAKENUMBER
]] -- You can add or remove items from this list to be copied or not. Here is all of them
local info = {}
for info in string.gmatch(names,"%S+") do
local val = reaper.GetMediaItemTakeInfo_Value(take_copy, info)
reaper.SetMediaItemTakeInfo_Value(take_paste, info, val)
end
end
function CopyMediaNotMIDI(item, track, position) -- Fork From Xraym https://github.com/ReaTeam/ReaScripts-Templates/blob/master/Items%20Creations/X-Raym_Copy%20media%20item.lua
local new_item = reaper.AddMediaItemToTrack(track)
local new_item_guid = reaper.BR_GetMediaItemGUID(new_item)
local retval, item_chunk = reaper.GetItemStateChunk(item, '')
local new_item_chunk = bfut_ResetAllChunkGuids(item_chunk, "IGUID")
local new_item_chunk = bfut_ResetAllChunkGuids(new_item_chunk, "GUID")
reaper.SetItemStateChunk(new_item, new_item_chunk)
-- Set some extra info PUT THIS BAC
local vol = reaper.GetMediaItemInfo_Value(item, "D_VOL")
reaper.SetMediaItemInfo_Value(new_item, "D_VOL", vol)
local off = reaper.GetMediaItemInfo_Value(item, "D_SNAPOFFSET")
reaper.SetMediaItemInfo_Value(new_item, "D_SNAPOFFSET", off)
CopyTakeInfo(reaper.GetMediaItemTake(item, 0), reaper.GetMediaItemTake(new_item, 0))
reaper.SetMediaItemInfo_Value(new_item, "D_POSITION", position)
return new_item
end
function CopyMIDI(item, track, position)-- Copy an MIDI Item to Track at position. Be awere that it will change the item selection to the new item so use SaveSelectedItems() before calling it and then LoadSelectedItems(items_list)
local retval, chunk = reaper.GetItemStateChunk( item, "", false )
local chunk = bfut_ResetAllChunkGuids(chunk, "IGUID")
local chunk = bfut_ResetAllChunkGuids(chunk, "GUID")
local chunk = bfut_ResetAllChunkGuids(chunk, "POOLEDEVTS")
local chunk = ChangeChunkPosition(chunk, position)
local new_item = reaper.CreateNewMIDIItemInProj( track, 3, 0.1 )
reaper.SetItemStateChunk( new_item, chunk, false )
return new_item
end
function CopyMediaItem(item, track, position, selectcopy) -- It will change your item selection to the new item if you don't want this use You can put the SaveSelectedItems() and LoadSelectedItems().
local selectcopy = selectcopy or false -- when selectcopy is true the copied item will be selected
local ismidi = reaper.TakeIsMIDI(reaper.GetMediaItemTake(item, 0))
local new_item = nil
if ismidi == true then
new_item = CopyMIDI(item, track, position)
else
new_item = CopyMediaNotMIDI(item, track, position)
end
reaper.UpdateItemInProject(new_item)
if selectcopy then
reaper.Main_OnCommand(40289, 0)--Item: Unselect all items
reaper.SetMediaItemSelected( new_item, true )
end
return new_item
end
--Exemple Copy Items to Selected Track
local count_sel_items = reaper.CountSelectedMediaItems(0)
local count_sel_tracks = reaper.CountSelectedTracks(0)
if count_sel_tracks > 0 and count_sel_items > 0 then
--Saves some info
reaper.Undo_BeginBlock()
reaper.PreventUIRefresh( 1 )
--local items_list = SaveSelectedItems()
--The actual thing
for items_i = 0,count_sel_items-1 do
local item = reaper.GetSelectedMediaItem(0, items_i)
local pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
for i = 0, count_sel_tracks-1 do
local track_loop = reaper.GetSelectedTrack(0, i)
CopyMediaItem(item, track_loop, pos)
reaper.UpdateArrange()
end
--LoadSelectedItems(items_list)
end
--Load things up
reaper.PreventUIRefresh( -1 )
reaper.Undo_EndBlock('Copy Items to Selected Tracks', -1)
end
I use part of yours code in templates github and tufb to adjust the GUID and IGUID. I think it is working . at least in my tests.
Thanks
Edit: removed a bug converning FX and GUID, I think I should update to reapack right?
EDIT: One more change code is better now with some options to be reused
EDIT EDIT EDIT: I tired of editing code is in reapack https://github.com/daniellumertz/Dan...d%20Tracks.lua
Last edited by daniellumertz; 05-17-2021 at 01:05 AM.
|
|
|
05-16-2021, 11:48 PM
|
#23
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
hm what the effects of having two items with same FXID ?
|
|
|
06-22-2021, 06:00 AM
|
#24
|
Human being with feelings
Join Date: Apr 2011
Posts: 3,458
|
I do not know but I think they should not.
Anyway, GUIDs are auto-generated by Reaper if they are missing. I made this function:
Code:
local function CopyMediaItemToTrack( item, track, position )
local _, chunk = reaper.GetItemStateChunk( item, "", false )
chunk = chunk:gsub("{.-}", "") -- Reaper auto-generates all GUIDs
local new_item = reaper.AddMediaItemToTrack( track )
reaper.PreventUIRefresh( 1 )
reaper.SetItemStateChunk( new_item, chunk, false )
reaper.SetMediaItemInfo_Value( new_item, "D_POSITION" , position )
reaper.PreventUIRefresh( -1 )
return new_item
end
It would be nice to have it as native API though:
Code:
MediaItem CopyMediaItemToTrack( MediaItem item, Track tr, number position )
Last edited by amagalma; 06-22-2021 at 06:09 AM.
|
|
|
06-23-2021, 10:17 AM
|
#25
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
LOL, much easier. Just some lines of code. I don't know Why it took me that giant piece of code. thanks Amagalma, will update some scripts of mine to use this
|
|
|
02-15-2024, 03:32 PM
|
#26
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 2,011
|
Just complemeting the explanation above, testing here removing all the guids characters will return {00000000-0000-0000-0000-000000000000} and removing all the guid with its brackets will return the current guid or in its absence, generate a new guid. Which is the case with applying a chunk missing guids to an empty item which only have IGUID identifier.
Just worries me that this part of amagalma snippet chunk:gsub("{.-}", "") can erase information from the user, less likely track names contaning {}. But also item ext states with serialized tables. Bellow is my proposal for CopyMediaItemToTrack:
Code:
function print(...)
local t = {}
for i, v in ipairs( { ... } ) do
t[i] = tostring( v )
end
reaper.ShowConsoleMsg( table.concat( t, " " ) .. "\n" )
end
-- Items
function enumSelectedItems(proj)
local cnt = reaper.CountSelectedMediaItems(0)
local i = -1
return function ()
i = i + 1
local item = reaper.GetSelectedMediaItem(proj, i) -- get current selected item
return item
end
end
function literalize(str)
return str:gsub(
"[%(%)%.%%%+%-%*%?%[%]%^%$]",
function(c)
return "%" .. c
end
)
end
---Reset all `key` identifiers in a chunk
---@param chunk string item/track/envelope chunk
---@param key string identifier key Items:(GUID, IGUID, POOLEDEVTS, FXID) Tracks:(TRACKID, FXID) Envelopes:(EGUID)
---@param new_guid string? optional. Default value is reaper.genGuid(''). If just '' the guid will be the current guid or if no current guid for that Identifier it will generate one. If just '{}' the guid will be {00000000-0000-0000-0000-000000000000}.
---@return string chunk return chunk with new guids
function ResetChunkIndentifier(chunk, key, new_guid)
local pattern = '\n'..key..'%s?{.-}\n'
for sub in chunk:gmatch(pattern) do -- Need to run gsub in a loop for a new reaper.genGuid('') for every occurance.
local guid_line = '\n'..key..' '..(new_guid or reaper.genGuid(''))..'\n'
local sub_pattern = literalize(sub)
chunk = chunk:gsub(sub_pattern,guid_line, 1) -- Need to be sure gsub is working in the actual line matched at gmatch, just using a gsub with the current GUID could result changing stored information at extstates
end
return chunk
end
---comment
---@param item item* item to be copied
---@param track track* track to copy to
---@param position number position in seconds to copy to
---@param selected boolean? optional boolean if is selected or not, if nil copy with current state (selecter or not)
---@param pooled_copy boolean? optional if true will make a pooled copy if nil or false will make a independent copy
---@return item
local function CopyMediaItemToTrack(item, track, position, selected, pooled_copy)
local _, chunk = reaper.GetItemStateChunk( item, "", false )
chunk = ResetChunkIndentifier(chunk, 'GUID', '')
chunk = ResetChunkIndentifier(chunk, 'IGUID', '')
if not pooled_copy then
chunk = ResetChunkIndentifier(chunk, 'POOLEDEVTS', '')
end
chunk = ResetChunkIndentifier(chunk, 'FXID', '')
local new_item = reaper.AddMediaItemToTrack( track )
reaper.SetItemStateChunk( new_item, chunk, false )
reaper.SetMediaItemInfo_Value( new_item, "D_POSITION" , position )
if selected ~= nil then
reaper.SetMediaItemInfo_Value( new_item, "B_UISEL" , selected and 1 or 0 )
end
return new_item
end
local proj = 0
local sel_items = {}
for item in enumSelectedItems(proj) do
sel_items[#sel_items+1] = item
end
for _, item in ipairs(sel_items) do
local track = reaper.GetMediaItemTrack(item)
CopyMediaItemToTrack(item, track, 1, false )
end
Last edited by daniellumertz; 02-18-2024 at 01:27 PM.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 05:48 PM.
|