|
|
|
09-20-2023, 11:19 AM
|
#1
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
FXContainers Api/scripts discussion thread.
This thread shall focus on how to code FXContainers with the api available.
It's for sharing code-snippets and discussing the api.
It's not for discussing FXContainers themselves and not for script requests!
Let's keep this focused on the development of FXContainer-api.
|
|
|
09-20-2023, 12:20 PM
|
#2
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
For now I will just say it would need to be simplified a lot. While working on router script which heavily utilizes this API things are getting more and more complicated than they need to be.
First step should be for Reaper hold and calculate diffs and we should have some kind of api to enumerate containers and use their guid rest would be all reaper calculation:
Code:
reaper.EnumerateFXCointainers(track) -- returns all containers in the track by guid
container = reaper.GetContainer(guid)
reaper.AddFxToContainer(container guid ,idx)
reaper.MoveFxToContainer(container guid ,idx, bool move)
ATM iterating them is hard and you need to keep track of everything.Working with nested containers is 10 times more harder (very few users will actually get what to do from API description).
If you want to add stuff to them then DIFF is not the same as iterating them. IDs of containers change if their parent changed the fx count so makes things even more harder.
So it would be nice to have some simplified form of API and multiples API for manipulating with them since IDs change, Diff change etc etc
BTW Multiple users asked me how I've done it since they failed and I also had help from 3 users to figure out the diffs and inserting stuff to them.
Minimal code for working with all container in the track is above 50loc
My little pov
Last edited by Sexan; 09-20-2023 at 12:33 PM.
|
|
|
09-20-2023, 12:50 PM
|
#3
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
I totally agree with Sexan. I tried to write convenience FXContainer-functions for Ultraschall-Api and I failed.
The first layer, where the FXContainer is just in a FXChain is easy, but FXContainers inside FXContainers are terrible to address.
I adore the efforts of the devs and what they added to Reaper since it's dawn.
But the FXContainer-api is the most horrible api I've ever seen.
I personally would prefer something like the TrackFX/TakeFX-functions, but for Containers.
Like TrackFX_AddByName and TakeFX_AddByName a FXContainer_AddByName etc. etc.
I also agree with Sexan that such FXContainer-functions shouldn't work with terrible indexing, but a guid instead.
You get the guid of an FXContainer and use it as parameter for FXContainer_AddByName(string containerguid, string fxname)
It's a lot more work but would be more consistent with how TrackFX/TakeFX already work.
As it currently is, it's unusable. I can't even say, if it's actually feature complete or if we could give requests/feedback on them, since the api is incomprehensible.
|
|
|
09-20-2023, 01:03 PM
|
#4
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
One example:
I tried to code a function to get the name of the fx in a FXContainer.
I managed to get the first fx's name but when I tried to iterate to the second, I failed.
I only got "" as result, because the indexing doesn't work like add +1 for the next fx in the container.
I couldn't figure out, what to add to the index to get to the second fx.
I failed already at FXContainer in FXContainer. So I didn't get further to more levels of nested containers.
|
|
|
09-20-2023, 02:30 PM
|
#5
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
One thing for example that is problematic is moving multiple items in the loop in some container.
ATM very hard since depending of container position when first item is moved container gets new ID and other items wont move anywhere.
You need to recalculate the new container ID and new DIFF for every next item (one of the things I'm doing).
Same thing for moving items outside of XY container
|
|
|
09-21-2023, 09:52 AM
|
#6
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Why not using FX GUID for reference? I deal with id of containers (even multilevel) just fine. Any real example (ideally rpp with reaplugns + task) what is hard to do?
|
|
|
09-21-2023, 10:55 AM
|
#7
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
How can you index by fx-guid?
|
|
|
09-21-2023, 12:34 PM
|
#8
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
1. Move multiple fx out of nested container (let it be from level 3 to lvl2)
2. Move fx from container 1 to container 2 and fx from container 2 to container 1
Last edited by Sexan; 09-21-2023 at 12:53 PM.
|
|
|
09-24-2023, 07:52 AM
|
#9
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Sorry, I have previously code that worked ok, but now I had to inspect it since I notice it didn`t worked correctly.
I pinged Justin, maybe he will enlight us for easier way, here is what I get so far (today`s revision, hopefully it works ok and I didn`t messed up with a tree structure indexing):
Code:
--------------------------------------------------------------------------
function mpl_BuildFXTree_iscontainer(tr, i)local ret, container_count = reaper.TrackFX_GetNamedConfigParm( tr, i, 'container_count') if ret==true then return tonumber(container_count) end end
--------------------------------------------------------------------------
function mpl_BuildFXTree_adddata(tr, tree, i, add)
local fxid = i
local GUID = reaper.TrackFX_GetFXGUID( tr, fxid|0x2000000 )
if not GUID then return end
local retval, buf = reaper.TrackFX_GetFXName( tr, fxid|0x2000000 )
local isopen = reaper.TrackFX_GetOpen( tr, fxid|0x2000000 )
local container_count = mpl_BuildFXTree_iscontainer(tr, fxid|0x2000000)
if not add then
tree[i] = {
fxname = buf,
isopen=isopen,
GUID=GUID,
fxid = i
}
else
tree[i].GUID=GUID
tree[i].fxname = buf
tree[i].fxid = i
end
end
------------------------------------------------------------------------------
function mpl_BuildFXTree_recursive(tr, tree, i)
local container_count = mpl_BuildFXTree_iscontainer(tr, i|0x2000000)
if not tonumber(container_count) then return end
container_count = tonumber(container_count)
tree[i]= {iscont = true}
mpl_BuildFXTree_adddata(tr, tree, i, true)
tree[i].shift = (tree.fxcnt + 1)
tree[i].parentcontainerID = tree.fxid
if not tree[i].fxcnt then
local child_fxid = tree.fxcnt * (1 + container_count) + container_count
for id in pairs(tree) do if tonumber(id) then tree[i].fxcnt = child_fxid end end
end
for child = 1, container_count do
local child_fxid = child * (tree.fxcnt + 1) + i
tree[i][child_fxid] = {}
mpl_BuildFXTree_adddata(tr, tree[i], child_fxid)
tree[i][child_fxid].parentcontainerID = tree[i].fxid
mpl_BuildFXTree_recursive(tr, tree[i], child_fxid)
end
end
--------------------------------------------------------------------------
function mpl_BuildFXTree(tr)
-- table with referencing ID tree
local tree = {}
local cnt = reaper.TrackFX_GetCount( tr)
tree.fxcnt= cnt
for i = 1, cnt do
mpl_BuildFXTree_adddata (tr, tree, i)
tree[i].fxcnt = cnt
tree[i].parentcontainerID = 0
mpl_BuildFXTree_recursive(tr, tree, i)
end
local tree_exploded = mpl_ExplodeFXTree(tree)
return tree, tree_exploded
end
--------------------------------------------------------------------------
function mpl_ExplodeFXTree_recursive(exploded_tree, tree)
for fxid in pairs(tree) do
if tonumber(fxid) then
local idx = #exploded_tree + 1
exploded_tree[idx] = tree[fxid]
exploded_tree[idx].level = tree.level + 1
--exploded_tree[idx].parentcontainerID = fxid
exploded_tree[idx].fxcnt = nil -- clean
if tree[fxid].iscont == true then
mpl_ExplodeFXTree_recursive(exploded_tree, tree[fxid])
end
end
end
end
--------------------------------------------------------------------------
function mpl_ExplodeFXTree(tree)
local exploded_tree = {}
for fxid in pairs(tree) do
if tonumber(fxid) then
local idx = #exploded_tree + 1
exploded_tree[idx] = tree[fxid]
exploded_tree[idx].fxcnt = nil -- clean
exploded_tree[idx].level = 1
if exploded_tree[fxid].iscont == true then
mpl_ExplodeFXTree_recursive(exploded_tree, tree[fxid])
exploded_tree[idx].level = level
end
end
end
return exploded_tree
end
--------------------------------------------------------------------------
function mpl_EnumerateFXCointainers(tr)
local tree_src, tree_exploded = mpl_BuildFXTree(tr)
local GUID = {}
for i = 1, #tree_exploded do
if tree_exploded[i].iscont == true then
GUID[#GUID+1] = {GUID=tree_exploded[i].GUID,
fxID = tree_exploded[i].fxid,
fxname = tree_exploded[i].fxname,
}
end
end
t = tree_src
return GUID
end
--------------------------------------------------------------------------
function mpl_GetContainer(tr,GUID)
local tree_src, tree_exploded = mpl_BuildFXTree(tr)
for i = 1, #tree_exploded do
if tree_exploded[i].iscont == true and tree_exploded[i].GUID==GUID then return true, tree_exploded[i].fxid, tree_exploded[i].shift end
end
end
--------------------------------------------------------------------------
function mpl_MoveFxToContainer(tr, container_guid,src_fx)
local ret, container, container_shift = mpl_GetContainer(tr, container_guid)
if ret then
src_fx = (src_fx + 1 ) | 0x2000000
dest_fx = (container + container_shift) | 0x2000000
reaper.TrackFX_CopyToTrack( tr, src_fx, tr, dest_fx, true )
end
end
--------------------------------------------------------------------------
function main()
local tr = reaper.GetSelectedTrack(0,0)
if not tr then return end
-- test 0
--tree_src, tree_exploded = mpl_BuildFXTree(tr)
-- test 1
--GUID_t = mpl_EnumerateFXCointainers(tr)
--ret, container, container_shift = mpl_GetContainer(tr,GUID_t[1].GUID)
-- test2
--GUID_t = mpl_EnumerateFXCointainers(tr)
--mpl_MoveFxToContainer(tr, GUID_t[1].GUID, 0) -- add first fx to first container
end
--------------------------------------------------------------------------
main()
In case Justin will not put something easier, I`ll implement wht Sexan said.
upd: added EnumerateFXCointainers, it return table with GUIDs, names and ids
upd2: added GetContainer
upd3: added mpl_MoveFxToContainer, probably it require some clever check to not accidentally move fx which is already is inside container to that container or to container to upper level, didn`t really checked. But you can just move it to first level, recalculate tree and put it where needed. I don`t really undestand difference with AddFxToContainer. You can insert FX into first slot (see docs), then move it.
Last edited by mpl; 09-24-2023 at 10:53 AM.
|
|
|
09-24-2023, 09:19 AM
|
#10
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Quote:
Originally Posted by Sexan
1. Move multiple fx out of nested container (let it be from level 3 to lvl2)
2. Move fx from container 1 to container 2 and fx from container 2 to container 1
|
if the code above works for you, I can build some of these examples. The only thing I need is a "multiple" word definition. We don`t have "selected" flag for FX to somehow enumerate then, or you can just bring focused FX and if it is at level 3, collect all the GUIDs, move them out of everything and the add one by one into container level upper (probably you`ll need to mpl_BuildFXTree() after each move to recalculate FX tree).
Ah, note, that returned fxids in my tree are indexed in the fx-container area (1-based and without 0x2000000), probably for the cleanup reasons (so others can also use it) it can be improved.
Last edited by mpl; 09-24-2023 at 09:35 AM.
|
|
|
09-24-2023, 10:02 AM
|
#11
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
I've have build whole router which takes care of pretty much everything you can possibly do regarding moving anything to anywhere with restrictions not moving containers into its childs etc etc (gui script so you can move anything and needed to handle that). Was a challenge but almost ready to release.
Last edited by Sexan; 09-24-2023 at 10:13 AM.
|
|
|
09-24-2023, 10:09 AM
|
#12
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
Quote:
Originally Posted by mpl
The only thing I need is a "multiple" word definition.
|
Loop that will move out 2+ items out of container or in to a container (single item move is ok, more is complicated in nested situation).
This is doable (done it) but data/table needs to be updated after every move operation and track container guid get new ID and DIFF.
Anyway everything is doable but in general not easy to for any "casual" scripter that wants to do something little "more"
Last edited by Sexan; 09-24-2023 at 10:14 AM.
|
|
|
09-24-2023, 10:17 AM
|
#13
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
Some FR:
Rename FX (any in general)
Save Container as chain
|
|
|
09-24-2023, 11:06 AM
|
#14
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Quote:
Originally Posted by Sexan
Loop that will move out 2+ items out of container or in to a container (single item move is ok, more is complicated in nested situation).
|
Code:
--------------------------------------------------------------------------
function mpl_BuildFXTree_iscontainer(tr, i)local ret, container_count = reaper.TrackFX_GetNamedConfigParm( tr, i, 'container_count') if ret==true then return tonumber(container_count) end end
--------------------------------------------------------------------------
function mpl_BuildFXTree_adddata(tr, tree, i, add)
local fxid = i
local GUID = reaper.TrackFX_GetFXGUID( tr, fxid|0x2000000 )
if not GUID then return end
local retval, buf = reaper.TrackFX_GetFXName( tr, fxid|0x2000000 )
local isopen = reaper.TrackFX_GetOpen( tr, fxid|0x2000000 )
local container_count = mpl_BuildFXTree_iscontainer(tr, fxid|0x2000000)
if not add then
tree[i] = {
fxname = buf,
isopen=isopen,
GUID=GUID,
fxid = i
}
else
tree[i].GUID=GUID
tree[i].fxname = buf
tree[i].fxid = i
end
end
------------------------------------------------------------------------------
function mpl_BuildFXTree_recursive(tr, tree, i)
local container_count = mpl_BuildFXTree_iscontainer(tr, i|0x2000000)
if not tonumber(container_count) then return end
container_count = tonumber(container_count)
tree[i]= {iscont = true}
mpl_BuildFXTree_adddata(tr, tree, i, true)
tree[i].shift = (tree.fxcnt + 1)
tree[i].parentcontainerID = tree.fxid
if not tree[i].fxcnt then
local child_fxid = tree.fxcnt * (1 + container_count) + container_count
for id in pairs(tree) do if tonumber(id) then tree[i].fxcnt = child_fxid end end
end
for child = 1, container_count do
local child_fxid = child * (tree.fxcnt + 1) + i
tree[i][child_fxid] = {}
mpl_BuildFXTree_adddata(tr, tree[i], child_fxid)
tree[i][child_fxid].parentcontainerID = tree[i].fxid
mpl_BuildFXTree_recursive(tr, tree[i], child_fxid)
end
end
--------------------------------------------------------------------------
function mpl_BuildFXTree(tr)
-- table with referencing ID tree
local tree = {}
local cnt = reaper.TrackFX_GetCount( tr)
tree.fxcnt= cnt
for i = 1, cnt do
mpl_BuildFXTree_adddata (tr, tree, i)
tree[i].fxcnt = cnt
tree[i].parentcontainerID = 0
mpl_BuildFXTree_recursive(tr, tree, i)
end
local tree_exploded = mpl_ExplodeFXTree(tree)
return tree, tree_exploded
end
--------------------------------------------------------------------------
function mpl_ExplodeFXTree_recursive(exploded_tree, tree)
for fxid in pairs(tree) do
if tonumber(fxid) then
local idx = #exploded_tree + 1
exploded_tree[idx] = tree[fxid]
exploded_tree[idx].level = tree.level + 1
--exploded_tree[idx].parentcontainerID = fxid
exploded_tree[idx].fxcnt = nil -- clean
if tree[fxid].iscont == true then
mpl_ExplodeFXTree_recursive(exploded_tree, tree[fxid])
end
end
end
end
--------------------------------------------------------------------------
function mpl_ExplodeFXTree(tree)
local exploded_tree = {}
for fxid in pairs(tree) do
if tonumber(fxid) then
local idx = #exploded_tree + 1
exploded_tree[idx] = tree[fxid]
exploded_tree[idx].fxcnt = nil -- clean
exploded_tree[idx].level = 1
if exploded_tree[fxid].iscont == true then
mpl_ExplodeFXTree_recursive(exploded_tree, tree[fxid])
exploded_tree[idx].level = level
end
end
end
return exploded_tree
end
--------------------------------------------------------------------------
function mpl_EnumerateFXCointainers(tr)
local tree_src, tree_exploded = mpl_BuildFXTree(tr)
local GUID = {}
for i = 1, #tree_exploded do
if tree_exploded[i].iscont == true then
GUID[#GUID+1] = {GUID=tree_exploded[i].GUID,
fxID = tree_exploded[i].fxid,
fxname = tree_exploded[i].fxname,
}
end
end
t = tree_src
return GUID
end
--------------------------------------------------------------------------
function mpl_GetFXbyGUID_ContainerExt(tr,GUID,container_only)
local tree_src, tree_exploded = mpl_BuildFXTree(tr)
for i = 1, #tree_exploded do
if (not container_only or (container_only and tree_exploded[i].iscont == true)) and tree_exploded[i].GUID==GUID then return true, tree_exploded[i].fxid, tree_exploded[i].shift end
end
end
--------------------------------------------------------------------------
function mpl_MoveFxToContainer(tr, container_guid,src_fx)
local ret, container, container_shift = mpl_GetFXbyGUID_ContainerExt(tr, container_guid, true)
if ret then
src_fx = (src_fx + 1 ) | 0x2000000
dest_fx = (container + container_shift) | 0x2000000
reaper.TrackFX_CopyToTrack( tr, src_fx, tr, dest_fx, true )
end
end
--------------------------------------------------------------------------
function main()
local tr = reaper.GetSelectedTrack(0,0)
if not tr then return end
-- test 0
-- test 1
--GUID_t = mpl_EnumerateFXCointainers(tr)
--ret, container, container_shift = mpl_GetFXbyGUID_ContainerExt(tr,GUID_t[1].GUID, true)
-- test2
--GUID_t = mpl_EnumerateFXCointainers(tr)
--mpl_MoveFxToContainer(tr, GUID_t[1].GUID, 0) -- add first fx to first container
-- test3
tree_src, tree_exploded = mpl_BuildFXTree(tr)
GUID2Move = {}
for i = 1, #tree_exploded do
if tree_exploded[i].level == 3 then
local parentcontainerID = tree_exploded[i].parentcontainerID
local GUID = reaper.TrackFX_GetFXGUID( tr, parentcontainerID|0x2000000 )
ret, container, container_shift = mpl_GetFXbyGUID_ContainerExt(tr,GUID, true)
GUID2Move[#GUID2Move+1] = { GUIDsrc=tree_exploded[i].GUID,
GUIDdest = GUID,
}
end
end
for i = 1, #GUID2Move do
GUIDsrc = GUID2Move[i].GUIDsrc
GUIDdest = GUID2Move[i].GUIDdest
ret, fxid_src = mpl_GetFXbyGUID_ContainerExt(tr, GUIDsrc)
ret, fxid_dest, shift = mpl_GetFXbyGUID_ContainerExt(tr, GUIDdest)
reaper.TrackFX_CopyToTrack( tr, fxid_src|0x2000000, tr, fxid_dest|0x2000000, true )
end
end
--------------------------------------------------------------------------
main()
|
|
|
09-24-2023, 11:22 AM
|
#15
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Maybe we need simply a more easier way to get calculated container child IDs?
like
Code:
retval, container_subitemID= reaper.TrackFX_GetNamedConfigParm( track, fx, 'container_subitemID.X')
-- do something with direct subitem ID
retval, container_addFXIDfirst= reaper.TrackFX_GetNamedConfigParm( track, fx, 'container_addFXIDfirst')
reaper.TrackFX_AddByName( track, fxname, false, container_addFXIDfirst)
retval, container_addFXIDlast= reaper.TrackFX_GetNamedConfigParm( track, fx, 'container_addFXIDlast')
reaper.TrackFX_AddByName( track, fxname, false, container_addFXIDlast)
+ native GetFXbyGUID without seeking whole tree and collect GUIDs
because even if me or Sexan or Mespotine will make a solution, it still will require to recalculate tree after each change, so it would be nice to have direct access to subitem indexes (I guess it still will be recalculated internally but it would be way more optimized than doing it from reascript)
Last edited by mpl; 09-24-2023 at 11:27 AM.
|
|
|
09-24-2023, 11:35 AM
|
#16
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
I'm just calling the iteration function again to update and return same container
Code:
Get_Or_Uptate() -- Generates table with data
container = tbl[x]
id = 0x2000000 + container.ID + (container.DIFF * i)
reaper.MoveFx(track,id)
container = Get_Or_Uptate(container.guid)
do next etc
So I maximally optimized that function with outside locals etc
Last edited by Sexan; 09-24-2023 at 11:44 AM.
|
|
|
09-24-2023, 07:16 PM
|
#17
|
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 15,746
|
this is how I'd go about recursively building that tree (based on mpl's code or whatnot):
Code:
------------------------------------------------------------------------------
function BuildFXTree_item(tr, fxid, scale)
local retval, buf = reaper.TrackFX_GetFXName( tr, fxid )
local ccok, container_count = reaper.TrackFX_GetNamedConfigParm( tr, fxid, 'container_count')
local ret = {
fxname = buf,
isopen = reaper.TrackFX_GetOpen( tr, fxid ),
GUID = reaper.TrackFX_GetFXGUID( tr, fxid ),
addr_fxid = fxid,
}
if ccok then
ret.children = { }
local newscale = scale * (tonumber(container_count)+1)
for child = 1, tonumber(container_count) do
ret.children[child] = BuildFXTree_item(tr, fxid + scale * child, newscale)
end
end
return ret
end
--------------------------------------------------------------------------
function BuildFXTree(tr)
-- table with referencing ID tree
tree = {}
local cnt = reaper.TrackFX_GetCount(tr)
for i = 1, cnt do
tree[i] = BuildFXTree_item(tr, 0x2000000+i, cnt+1)
end
end
--------------------------------------------------------------------------
function main()
local tr = reaper.GetSelectedTrack(0,0)
if not tr then return end
BuildFXTree(tr)
end
main()
|
|
|
09-24-2023, 07:42 PM
|
#18
|
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 15,746
|
Here's a helper if you want to get the ID from any path (variable number of arguments, all 1-based):
Code:
function get_fx_id_from_container_path(tr, idx1, ...)
local sc,rv = reaper.TrackFX_GetCount(tr)+1, 0x2000000 + idx1
for i,v in ipairs({...}) do
local ccok, cc = reaper.TrackFX_GetNamedConfigParm(tr, rv, 'container_count')
if ccok ~= true then return nil end
rv = rv + sc * v
sc = sc * (1+tonumber(cc))
end
return rv
end
track = reaper.GetTrack(0,0);
id = get_fx_id_from_container_path(track, 1, 1) -- first item of first item (which must be a container)
ok, name = reaper.TrackFX_GetFXName(track,id)
(will return nil if you try to query a subitem of a non-container or anything out of bounds)
For posterity, here is the inverse of this function (generates a list of indices from the ID):
Code:
function get_container_path_from_fx_id(tr, fxidx) -- returns a list of 1-based IDs from a fx-address
if fxidx & 0x2000000 then
local ret = { }
local n = reaper.TrackFX_GetCount(tr)
local curidx = (fxidx - 0x2000000) % (n+1)
local remain = math.floor((fxidx - 0x2000000) / (n+1))
if curidx < 1 then return nil end -- bad address
local addr, addr_sc = curidx + 0x2000000, n + 1
while true do
local ccok, cc = reaper.TrackFX_GetNamedConfigParm(tr, addr, 'container_count')
if not ccok then return nil end -- not a container
ret[#ret+1] = curidx
n = tonumber(cc)
if remain <= n then if remain > 0 then ret[#ret+1] = remain end return ret end
curidx = remain % (n+1)
remain = math.floor(remain / (n+1))
if curidx < 1 then return nil end -- bad address
addr = addr + addr_sc * curidx
addr_sc = addr_sc * (n+1)
end
end
return { fxid+1 }
end
Last edited by Justin; 11-12-2023 at 04:35 PM.
|
|
|
09-24-2023, 07:44 PM
|
#19
|
Human being with feelings
Join Date: Feb 2017
Posts: 4,820
|
^^ great !
__________________
🙏🏻
|
|
|
09-25-2023, 02:01 AM
|
#20
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
Quote:
Originally Posted by Justin
Here's a helper if you want to get the ID from any path (variable number of arguments, all 1-based):
Code:
function get_fx_id_from_container_path(tr, idx1, ...)
local sc,rv = reaper.TrackFX_GetCount(tr)+1, 0x2000000 + idx1
for i,v in ipairs({...}) do
local ccok, cc = reaper.TrackFX_GetNamedConfigParm(tr, rv, 'container_count')
if ccok ~= true then return nil end
rv = rv + sc * v
sc = sc * (1+tonumber(cc))
end
return rv
end
track = reaper.GetTrack(0,0);
id = get_fx_id_from_container_path(track, 1, 1) -- first item of first item (which must be a container)
ok, name = reaper.TrackFX_GetFXName(track,id)
(will return nil if you try to query a subitem of a non-container or anything out of bounds)
|
Would it be ok, if I add it to Ultraschall-Api under MIT-license?
|
|
|
09-25-2023, 05:11 AM
|
#21
|
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 15,746
|
Quote:
Originally Posted by Meo-Ada Mespotine
Would it be ok, if I add it to Ultraschall-Api under MIT-license?
|
yes of course, please feel free to and to rename/edit as desired
|
|
|
09-25-2023, 01:06 PM
|
#22
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,630
|
Quote:
Originally Posted by Justin
yes of course, please feel free to and to rename/edit as desired
|
Thnx
|
|
|
10-04-2023, 01:34 AM
|
#23
|
Human being with feelings
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,921
|
Quote:
Originally Posted by Justin
this is how I'd go about recursively building that tree (based on mpl's code or whatnot):
|
Thank You! I was going dizzy trying to get fxIds inside containers inside containers...
|
|
|
11-12-2023, 03:37 AM
|
#24
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
Quote:
Originally Posted by Justin
Here's a helper if you want to get the ID from any path (variable number of arguments, all 1-based):
Code:
function get_fx_id_from_container_path(tr, idx1, ...)
local sc,rv = reaper.TrackFX_GetCount(tr)+1, 0x2000000 + idx1
for i,v in ipairs({...}) do
local ccok, cc = reaper.TrackFX_GetNamedConfigParm(tr, rv, 'container_count')
if ccok ~= true then return nil end
rv = rv + sc * v
sc = sc * (1+tonumber(cc))
end
return rv
end
track = reaper.GetTrack(0,0);
id = get_fx_id_from_container_path(track, 1, 1) -- first item of first item (which must be a container)
ok, name = reaper.TrackFX_GetFXName(track,id)
(will return nil if you try to query a subitem of a non-container or anything out of bounds)
|
This is a godsend. Thank you so much!
"This can be extended to sub-containers using TrackFX_GetNamedConfigParm with container_count and similar logic'*" in the doc means that you need to count container_count like you count r.TrackFX_GetCount when caluclating xth_layer_fx_count, and it basically works like the example below.
Code:
Root -> first layer -> second layer -> third layer
root_fx_pos = 1
first_layer_fx_pos = 2 (ReaSynth)
first_layer_container_pos = 3
second_layer_fx_pos = 5 (ReaComp)
second_layer_container_pos = 8
third_layer_fx_pos = 1 (ReaDelay)
root_container_id = 0x2000000 + root_fx_pos
root_fx_count = reaper.TrackFX_GetCount(track)+1
rv, root_cc = reaper.TrackFX_GetNamedConfigParm(track, root_container_id, 'container_count')
first_layer_fx_count = root_fx_count * (tonumber(root_cc)+1)
first_layer_container_id = root_container_id + (root_fx_count * first_layer_container_pos)
rv, first_layer_cc = reaper.TrackFX_GetNamedConfigParm(track, first_layer_container_id, 'container_count')
second_layer_fx_count = first_layer_fx_count * (tonumber(first_layer_cc)+1)
first_layer_fx_id = root_container_id + (root_fx_count * first_layer_fx_pos)
first_layer_container_id = root_container_id + (root_fx_count * first_layer_container_pos)
second_layer_fx_id = first_layer_container_id + (first_layer_fx_count * second_layer_fx_pos)
second_layer_container_id = first_layer_container_id + (first_layer_fx_count * second_layer_container_pos)
third_layer_fx_id = second_layer_container_id + (second_layer_fx_count * third_layer_fx_pos)
To put it a little more abstractly, it would be like this.
Code:
root_container_id = 0x2000000 + root_fx_pos
xth_layer_fx_id = (x-1)th_layer_container_id + ((x-1)th_layer_fx_count * xth_layer_fx_pos)
root_fx_count = reaper.TrackFX_GetCount(track)+1
rv, xth_layer_cc = reaper.TrackFX_GetNamedConfigParm(track, xth_container_id, 'container_count')
xth_layer_fx_count = (x-1)th_layer_fx_count * (tonumber((x-1)_layer_cc)+1)
|
|
|
11-12-2023, 03:55 AM
|
#25
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
I modded this for my personal need when a new table exists.
Code:
function get_fx_id_from_container_path(tr, idx1, ...) -- 1based
local sc, rv = r.TrackFX_GetCount(tr) + 1, 0x2000000 + idx1
local vararg = {}
for i, v in ipairs({ ... }) do
local ccok, cc = r.TrackFX_GetNamedConfigParm(tr, rv, 'container_count')
vararg[i] = v
if ccok ~= true then return nil end
rv = rv + sc * v
sc = sc * (1 + tonumber(cc))
end
local new_sc, new_rv
if DrumMachinePath then -- if Drum Machine is nested
new_vararg = {}
for i = 1,#DrumMachinePath do
new_vararg[i] = DrumMachinePath[i]
end
new_vararg[#new_vararg + 1] = idx1
for i = 1, #vararg do
new_vararg[#new_vararg + 1] = vararg[i]
end
local new_sc, new_rv = r.TrackFX_GetCount(track)+1, 0x2000000 + new_vararg[1]
for i = 2, #new_vararg do
local new_v = new_vararg[i]
local new_ccok, new_cc = r.TrackFX_GetNamedConfigParm(track, new_rv, 'container_count')
new_ccok = tostring(new_ccok)
new_rv = new_rv + new_sc * new_v
new_sc = new_sc * (1+tonumber(new_cc))
end
return new_rv
else
return rv
end
end
|
|
|
11-13-2023, 05:35 AM
|
#27
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
|
|
|
11-18-2023, 11:54 AM
|
#28
|
Human being with feelings
Join Date: Sep 2019
Posts: 1,146
|
I pored over the code examples but due to thickness couldn't figure out the logic.
Does this all mean that we only need to add 0x2000000 once when container in the 1st level chain has been found and for calculations related to all its sub-containers it's not needed?
When accounting for the FX count in the parent container, does FX count in all grandparent containers have to be accounted for as well?
|
|
|
11-18-2023, 10:32 PM
|
#29
|
Human being with feelings
Join Date: Dec 2017
Location: Sunny Siberian Islands
Posts: 962
|
Is there a way to create a plugin in a container, along with the given parameters?
What I mean. Now I can put the plugin into a container, but it will have default settings. This code is simple and it works:
Code:
local track = reaper.GetSelectedTrack(0, 0)
if not track then return end
reaper.TrackFX_AddByName(track, 'Container', false, 1)
local position_of_FX_in_container = select(2, reaper.TrackFX_GetNamedConfigParm(track, 0, 'container_count')) + 1
local parent_FX_count = reaper.TrackFX_GetCount(track)
local position_of_container = 1
local insert_position = 0x2000000 + position_of_FX_in_container * (parent_FX_count + 1) + position_of_container
reaper.TrackFX_AddByName(track, 'ReaEQ', false, insert_position)
But if I try to give the plugin parameters via "TrackFX_SetParamNormalized", they are not applied. This code does not work as intended: the plugin is still created with default parameters.
Code:
local track = reaper.GetSelectedTrack(0, 0)
if not track then return end
reaper.TrackFX_AddByName(track, 'Container', false, 1)
local position_of_FX_in_container = select(2, reaper.TrackFX_GetNamedConfigParm(track, 0, 'container_count')) + 1
local parent_FX_count = reaper.TrackFX_GetCount(track)
local position_of_container = 1
local insert_position = 0x2000000 + position_of_FX_in_container * (parent_FX_count + 1) + position_of_container
local ReaEQ_param = reaper.TrackFX_AddByName( track, 'ReaEQ', false, insert_position )
reaper.TrackFX_SetParamNormalized( track, ReaEQ_param, 3, 0.25) -- freq
reaper.TrackFX_SetParamNormalized( track, ReaEQ_param, 4, 0.25) -- gain
Is there a way to solve this problem?
|
|
|
11-18-2023, 10:49 PM
|
#30
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
Quote:
Originally Posted by cool
Is there a way to create a plugin in a container, along with the given parameters?
What I mean. Now I can put the plugin into a container, but it will have default settings. This code is simple and it works:
Code:
local track = reaper.GetSelectedTrack(0, 0)
if not track then return end
reaper.TrackFX_AddByName(track, 'Container', false, 1)
local position_of_FX_in_container = select(2, reaper.TrackFX_GetNamedConfigParm(track, 0, 'container_count')) + 1
local parent_FX_count = reaper.TrackFX_GetCount(track)
local position_of_container = 1
local insert_position = 0x2000000 + position_of_FX_in_container * (parent_FX_count + 1) + position_of_container
reaper.TrackFX_AddByName(track, 'ReaEQ', false, insert_position)
But if I try to give the plugin parameters via "TrackFX_SetParamNormalized", they are not applied. This code does not work as intended: the plugin is still created with default parameters.
Code:
local track = reaper.GetSelectedTrack(0, 0)
if not track then return end
reaper.TrackFX_AddByName(track, 'Container', false, 1)
local position_of_FX_in_container = select(2, reaper.TrackFX_GetNamedConfigParm(track, 0, 'container_count')) + 1
local parent_FX_count = reaper.TrackFX_GetCount(track)
local position_of_container = 1
local insert_position = 0x2000000 + position_of_FX_in_container * (parent_FX_count + 1) + position_of_container
local ReaEQ_param = reaper.TrackFX_AddByName( track, 'ReaEQ', false, insert_position )
reaper.TrackFX_SetParamNormalized( track, ReaEQ_param, 3, 0.25) -- freq
reaper.TrackFX_SetParamNormalized( track, ReaEQ_param, 4, 0.25) -- gain
Is there a way to solve this problem?
|
Maybe you want to do it like this? insert_position is fx id here.
Code:
local track = reaper.GetSelectedTrack(0, 0)
if not track then return end
reaper.TrackFX_AddByName(track, 'Container', false, 1)
local position_of_FX_in_container = select(2, reaper.TrackFX_GetNamedConfigParm(track, 0, 'container_count')) + 1
local parent_FX_count = reaper.TrackFX_GetCount(track)
local position_of_container = 1
local insert_position = 0x2000000 + position_of_FX_in_container * (parent_FX_count + 1) + position_of_container
local ReaEQ_param = reaper.TrackFX_AddByName( track, 'ReaEQ', false, insert_position )
reaper.TrackFX_SetParamNormalized( track, insert_position, 3, 0.25) -- freq
reaper.TrackFX_SetParamNormalized( track, insert_position, 4, 0.25) -- gain
|
|
|
11-18-2023, 11:05 PM
|
#31
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
Quote:
Originally Posted by Buy One
I pored over the code examples but due to thickness couldn't figure out the logic.
Does this all mean that we only need to add 0x2000000 once when container in the 1st level chain has been found and for calculations related to all its sub-containers it's not needed?
When accounting for the FX count in the parent container, does FX count in all grandparent containers have to be accounted for as well?
|
0x2000000 is one time thingy in the root, and it just adds up based on it.
You don't need to consider FX inside grandchildren when counting FX in root position, but the deeper you go, the more you'll take parent fx count into consideration naturally because again they add up based on the previous level calculation.
|
|
|
11-18-2023, 11:14 PM
|
#32
|
Human being with feelings
Join Date: Dec 2017
Location: Sunny Siberian Islands
Posts: 962
|
Quote:
Originally Posted by Suzuki
Maybe you want to do it like this? insert_position is fx id here.
|
Ha! It turned out to be very simple. Thank you! I'm dumb
|
|
|
11-19-2023, 02:23 AM
|
#33
|
Human being with feelings
Join Date: Sep 2019
Posts: 1,146
|
Quote:
Originally Posted by Suzuki
0x2000000 is one time thingy in the root, and it just adds up based on it.
You don't need to consider FX inside grandchildren when counting FX in root position, but the deeper you go, the more you'll take parent fx count into consideration naturally because again they add up based on the previous level calculation.
|
Thank you.
Looking at Justin's code I finally realized my mistake, instead of multiplying FX counts of all (grand)parent container FX chains i was adding them.
|
|
|
11-19-2023, 02:26 AM
|
#34
|
Human being with feelings
Join Date: Jun 2009
Location: Croatia
Posts: 4,689
|
If you manage to make some universal way to link parameters in containers (and nested ones) let me know...
|
|
|
11-25-2023, 05:33 AM
|
#35
|
Human being with feelings
Join Date: Jul 2022
Location: Japan
Posts: 812
|
Uploaded parameter link script and map parameters to the root container script using the new v7.06+ API to my repo.
|
|
|
11-26-2023, 08:01 AM
|
#36
|
Human being with feelings
Join Date: Sep 2015
Location: Paris
Posts: 544
|
For musician end-users, this whole thing looks like a nightmare. It would be great if there was no perceivable difference between FX and nested FX when it comes to automation etc. It should be experienced as the same thing.
|
|
|
11-26-2023, 01:45 PM
|
#37
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,295
|
Quote:
Originally Posted by Suzuki
Uploaded parameter link script and map parameters to the root container script using the new v7.06+ API to my repo.
|
Sweeetttttttttttttt!!!!
Thanks Suzuki!
|
|
|
12-04-2023, 07:52 AM
|
#38
|
Human being with feelings
Join Date: Aug 2023
Posts: 56
|
Hey friends,
I'd like to find out the "depth" of an fx container, like in this graphic:
https://ibb.co/CnfpVhX
I tried to find out the formula based on he API documentation and came up with this for one layer:
Code:
rv, track_nr, item, take, fx, param_id = reaper.GetTouchedOrFocusedFX(0)
track = reaper.GetTrack(0, track_nr)
rv, parent = reaper.TrackFX_GetNamedConfigParm(track, fx, "parent_container")
parent = tonumber(parent) - 0x2000000
track_fx_count = reaper.TrackFX_GetCount(track)
-- get last touched FX param
fx = fx - 0x2000000
index = (fx - (parent + 1)) / (track_fx_count + 1)
depth = fx - (index * (track_fx_count+1) + parent)
Unfortunately, it does not work with recursive trees and I can't wrap my head around it. Any ideas? Maybe it would be great to have a property in TrackFX_GetNamedParmConfig in that at some point.
Thanks!
Last edited by tdspk; 12-04-2023 at 08:00 AM.
|
|
|
12-10-2023, 05:46 PM
|
#39
|
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 15,746
|
Quote:
Originally Posted by tdspk
I'd like to find out the "depth" of an fx container, like in this graphic
|
If you want to find the depth of the FX, you could do something like:
Code:
level = 0
while true do
rv, parent = reaper.TrackFX_GetNamedConfigParm(track, fx, "parent_container")
if not rv then break end
level = level + 1
fx = parent
end
|
|
|
12-13-2023, 05:28 AM
|
#40
|
Human being with feelings
Join Date: Aug 2023
Posts: 56
|
Thanks Justin!
Meanwhile I solved it differently:
Code:
...
-- get the container ids for link parent and link child
rv, c_id_parent = GetNamedConfigParm(target, data_fx, "parent_container", is_item)
rv, c_id_child = GetNamedConfigParm(target, fx, "parent_container", is_item)
parent_fx = data_fx
parent_param = data_param
map_param = param_id
-- check which one is higher in the hiearchy
if (c_id_child > c_id_parent) then
-- child id needs to be overwritten with container maps
target_container = c_id_parent
map_target = fx
map_param = param_id
elseif (c_id_child < c_id_parent) then
-- parent id needs to be overwritten with container maps
target_container = c_id_child
map_target = data_fx
map_param = data_param
child = fx
else
-- nothing to do
target_container = -1
child = fx
end...
I was linking from one container to another (either from parent to child or from child to parent). I solved it by just comparing the ids and exposing container params accordingly (from top to bottom / bottom to top).
When they are on the same level (same parent container) I can stop iterating.
https://github.com/tdspk/ReaScripts/...k%20parent.lua
Thanks!
Last edited by tdspk; 12-13-2023 at 05:29 AM.
Reason: added the loop end condition and source.
|
|
|
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 03:53 AM.
|