Go Back   Cockos Incorporated Forums > REAPER Forums > REAPER Pre-Release Discussion

Reply
 
Thread Tools Display Modes
Old 09-20-2023, 11:19 AM   #1
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default 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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 09-20-2023, 12:20 PM   #2
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

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.
Sexan is online now   Reply With Quote
Old 09-20-2023, 12:50 PM   #3
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 09-20-2023, 01:03 PM   #4
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 09-20-2023, 02:30 PM   #5
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

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
Sexan is online now   Reply With Quote
Old 09-21-2023, 09:52 AM   #6
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

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?
mpl is offline   Reply With Quote
Old 09-21-2023, 10:55 AM   #7
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

How can you index by fx-guid?
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 09-21-2023, 12:34 PM   #8
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

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.
Sexan is online now   Reply With Quote
Old 09-24-2023, 07:52 AM   #9
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

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.
mpl is offline   Reply With Quote
Old 09-24-2023, 09:19 AM   #10
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Quote:
Originally Posted by Sexan View Post
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.
mpl is offline   Reply With Quote
Old 09-24-2023, 10:02 AM   #11
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

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.
Sexan is online now   Reply With Quote
Old 09-24-2023, 10:09 AM   #12
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

Quote:
Originally Posted by mpl View Post
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.
Sexan is online now   Reply With Quote
Old 09-24-2023, 10:17 AM   #13
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

Some FR:
Rename FX (any in general)
Save Container as chain
Sexan is online now   Reply With Quote
Old 09-24-2023, 11:06 AM   #14
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Quote:
Originally Posted by Sexan View Post
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()
mpl is offline   Reply With Quote
Old 09-24-2023, 11:22 AM   #15
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

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.
mpl is offline   Reply With Quote
Old 09-24-2023, 11:35 AM   #16
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

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.
Sexan is online now   Reply With Quote
Old 09-24-2023, 07:16 PM   #17
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

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()
Justin is offline   Reply With Quote
Old 09-24-2023, 07:42 PM   #18
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

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.
Justin is offline   Reply With Quote
Old 09-24-2023, 07:44 PM   #19
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 4,812
Default

^^ great !
__________________
🙏🏻
deeb is offline   Reply With Quote
Old 09-25-2023, 02:01 AM   #20
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by Justin View Post
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?
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 09-25-2023, 05:11 AM   #21
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
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
Justin is offline   Reply With Quote
Old 09-25-2023, 01:06 PM   #22
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by Justin View Post
yes of course, please feel free to and to rename/edit as desired
Thnx
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 10-04-2023, 01:34 AM   #23
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by Justin View Post
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...
Edgemeal is offline   Reply With Quote
Old 11-12-2023, 03:37 AM   #24
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

Quote:
Originally Posted by Justin View Post
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)
Suzuki is offline   Reply With Quote
Old 11-12-2023, 03:55 AM   #25
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

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
Suzuki is offline   Reply With Quote
Old 11-12-2023, 05:34 PM   #26
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

Added some code to the post above ( https://forum.cockos.com/showthread....70#post2714770 )


also posted some helper code to auto-map container FX parameters to the top level: https://forum.cockos.com/showpost.ph...09&postcount=4
Justin is offline   Reply With Quote
Old 11-13-2023, 05:35 AM   #27
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

For Take FX
https://forum.cockos.com/showpost.ph...28&postcount=7
Suzuki is offline   Reply With Quote
Old 11-18-2023, 11:54 AM   #28
Buy One
Human being with feelings
 
Buy One's Avatar
 
Join Date: Sep 2019
Posts: 1,134
Default

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?
__________________
https://github.com/Buy-One/REAPER-scripts (175)
REAPER is a DAW whose user guide file is larger than its installation file
Buy One is online now   Reply With Quote
Old 11-18-2023, 10:32 PM   #29
cool
Human being with feelings
 
Join Date: Dec 2017
Location: Sunny Siberian Islands
Posts: 957
Default

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?
cool is offline   Reply With Quote
Old 11-18-2023, 10:49 PM   #30
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

Quote:
Originally Posted by cool View Post
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
Suzuki is offline   Reply With Quote
Old 11-18-2023, 11:05 PM   #31
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

Quote:
Originally Posted by Buy One View Post
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.
Suzuki is offline   Reply With Quote
Old 11-18-2023, 11:14 PM   #32
cool
Human being with feelings
 
Join Date: Dec 2017
Location: Sunny Siberian Islands
Posts: 957
Default

Quote:
Originally Posted by Suzuki View Post
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
cool is offline   Reply With Quote
Old 11-19-2023, 02:23 AM   #33
Buy One
Human being with feelings
 
Buy One's Avatar
 
Join Date: Sep 2019
Posts: 1,134
Default

Quote:
Originally Posted by Suzuki View Post
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.
__________________
https://github.com/Buy-One/REAPER-scripts (175)
REAPER is a DAW whose user guide file is larger than its installation file
Buy One is online now   Reply With Quote
Old 11-19-2023, 02:26 AM   #34
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 4,593
Default

If you manage to make some universal way to link parameters in containers (and nested ones) let me know...
Sexan is online now   Reply With Quote
Old 11-25-2023, 05:33 AM   #35
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 765
Default

Uploaded parameter link script and map parameters to the root container script using the new v7.06+ API to my repo.
Suzuki is offline   Reply With Quote
Old 11-26-2023, 08:01 AM   #36
Loulou92
Human being with feelings
 
Loulou92's Avatar
 
Join Date: Sep 2015
Location: Paris
Posts: 544
Default

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.
Loulou92 is offline   Reply With Quote
Old 11-26-2023, 01:45 PM   #37
Reflected
Human being with feelings
 
Reflected's Avatar
 
Join Date: Jul 2009
Posts: 3,294
Default

Quote:
Originally Posted by Suzuki View Post
Uploaded parameter link script and map parameters to the root container script using the new v7.06+ API to my repo.
Sweeetttttttttttttt!!!!

Thanks Suzuki!
Reflected is offline   Reply With Quote
Old 12-04-2023, 07:52 AM   #38
tdspk
Human being with feelings
 
Join Date: Aug 2023
Posts: 50
Default

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.
tdspk is offline   Reply With Quote
Old 12-10-2023, 05:46 PM   #39
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

Quote:
Originally Posted by tdspk View Post
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
Justin is offline   Reply With Quote
Old 12-13-2023, 05:28 AM   #40
tdspk
Human being with feelings
 
Join Date: Aug 2023
Posts: 50
Default

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.
tdspk is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 09:34 AM.


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