Lua API bug -- swap tracks

It seems when you try to swap two sub groups within a group, if the first sub group is at the left border, one of the groups gets thrown out of the main group.

In the following example we are swapping Grp 1 with Grp 2. You would expect Grp 2 to remain in the Main Group, but it gets ejected:

(note: it works fine if Grp 1 is just a single track and not a sub-group)

renoise.song():swap_tracks_at(4, 7)

test song:

swap grps bug.xrns (3.9 KB)

BEFORE SWAP

AFTER SWAP

@ledger: thanks for reporting

No probs,

In the middle of a hugely convoluted work-around for this on a script at the moment. It should work but at the expense of efficiency.

In fact the swap function was already part of a workaround itself until I hit the bug :slight_smile: I’m extending the left-hand edge of groups to incorporate the next-left-track. As the current add_track_to_group() method adds to the rightmost position in the group you have to swap the new track all the way back along the group track-by-track to preserve order. Then I hit this bug, so now I am removing all member tracks from group and then re-adding them in reverse order. Needs some extra arithmetic for the indexes as if the new track to add is a group itself, you are adding more than one extra index to the group, so not as simple as it first sounds…

Would be great if there was an optional member_index to specify the position within the group to add a track. So if you wanted to add a new track as first member of group, member_index = 1

renoise.song():add_track_to_group(track_index, group_index) , member_index

Adding a workaround for the workaround is the moment you should stop and think…

Will this work once the issue is fixed? And will I even understand what I’m doing in 3 months time?

renoise.song():add_track_to_group

Hm, I would probably just use tracks then. You are able compute this stuff manually too?

(those nice little touches are what I like to add to xLib ^_^)

Adding a workaround for the workaround is the moment you should stop and think…
Will this work once the issue is fixed? And will I even understand what I’m doing in 3 months time?

Too late, I`m committed now! :slight_smile:
copious comments will be necessary!

If the bug is fixed, it can all get tidied up a bit anyway…

renoise.song():add_track_to_group

Hm, I would probably just use tracks then. You are able compute this stuff manually too?
(those nice little touches are what I like to add to xLib ^_^)

Not sure what you mean? “I would probably just use tracks then.”

copious comments will be necessary!

Haha, indeed!

What I meant was, is it not possible for you to just insert a new track anywhere?

The index decides should if it’s part of a group or not.

Gee. I haven’t worked with group tracks more than once or twice. May have to refresh my memory here a bit.

What I meant was, is it not possible for you to just insert a new track anywhere?
The index decides should if it’s part of a group or not.

To put an already present track (in this case left of the group). You seem to have to use:

renoise.song():swap_tracks_at(index1, index2)

Which ejects the track already in the group. A possible workaround could be to duplicate the track already in the group then delete the extra one that is ejected. I will have to look into that as it could be best work-around yet!

Alternatively:

renoise.song():add_track_to_group(track_index, group_index)

Which has the problem of adding at the right all the time.

Insert track that you mention:

renoise.song():insert_track_at(index)

Only inserts a new empty track. It will only insert at second position forward in the group aswell (member no. 2 onwards), so you are back possibly to the swap bug if a sub-group is at member 1 (scenario needs double checking). However I am still needing to insert an already present track anyway.

This could also be a work-around similar to above. If it`s not effected by the swap bug though:

-Add dummy track at member 2

-Swap with member 1

-Swap dummy track with new track that is left of the group

-delete dummy track that has now left the group

@Ledger, This seemed like a real headache. Short story (like you said):

  1. Anything added to a group will be placed far right

  2. If a group is part of a swap with what’s far left, the track will slide out of the parent group.

However, I think I found a slightly simpler workaround than “re-creating” the group structure. To make a swap with what’s far left:

  1. Insert an empty group to the parent group.

  2. Use renoise.song():add_to_group() to add the obnoxious track to the new group

  3. Use the same function again to move the group to the parent group

  4. Delete the temporary group.

A shuffle should have taken place.

EDIT: I saw that you’re probably on it now.

EDIT2: To simplify the code and make it work in all cases, I think it’s probably best to do a bubble-sort-esque thing with the dummy group far right - iterating starting from the track you finally want far left.

A headache indeed!

After firing so many errors my brain departed and I ended up in infinite monkey theorem mode!

thanks for the extra brainstorming! I’ll post something up here that works when I’m done.

:smashed: more problems with swap track

Trying to swap a track from the outside left of a group with the first member of that group, ejects the first member of the group:

both tracks end up swapped but outside the group…

Ok managed to get something working (alpha-ish)

Choose group you want to extend from the popup, then nudge with buttons.

Bonus buttons bypass or enable all the DSPs in the selected group track.

https://forum.renoise.com/t/new-tool-3-1-group-nudge-sep-2018/49540

Shortcut Group Nudge

Menu: Tools: Ledger`s Scripts: Group Nudge


and here`s the magic function, just pass in the group index of the group that you want to nudge left:

It required juggling two blank “dummy tracks” to get around the swapping problems stated in this thread.

--extend left border of group leftwards by one track
---------------------------------------  
function extend_group_left(group_index)  
---------------------------------------
  
  local song = renoise.song()
  local group_track = song:track(group_index)

  --get the index of the track to the left of the group. This is the track we want to add to the group
  local left_of_grp_idx = (group_index - #group_track.members - 1) 
  
  --if left_of_grp_idx == 0 then there are no more tracks to the left so return early 
  if left_of_grp_idx == 0 then 
    return
  end
  
  --if group has no members already, then it is a simple add track to group operation and
  --no re-organisation is needed
  if #group_track.members == 0 then
    song:add_track_to_group(left_of_grp_idx,group_index)
    return
  end
  
  --1) Add 2 dummy tracks into group
  ----------------------------------
  --NOTE We need to insert 2 dummy tracks to account for bugs with the renoise swap tracks behaviour within groups
  --see: https://forum.renoise.com/t/lua-api-bug-swap-tracks/49534
  
  --set member_idx to the first member track of the group
  local member_idx = left_of_grp_idx + 1

  --loop group members to find insert point for dummy tracks (after first legitimate member; i.e. not a track in a further sub-group)
  for i = 1,#group_track.members do
    --check if member is not in a sub group by checking its parent
    if rawequal(song:track(member_idx).group_parent,group_track) == true then
      break
    end
    --if here then member was in a sub- group so increment member_idx until we get to a legitimate track
    member_idx = member_idx + 1
  end
  
  --again due to insert_track behaviour we need to insert the dummy tracks after the first present and legitimate member of the group
  --so + 1
  local insert_point = member_idx + 1
  
  --insert 2 dummy tracks at member_idx 
  local dummy_trk_2 = song:insert_track_at(insert_point)
  local dummy_trk_1 = song:insert_track_at(insert_point)
  
  --name the tracks for bug hunting i.e. if they are not deleted we will see them in pattern ed
  dummy_trk_1.name = "Dummy Track 1"
  dummy_trk_2.name = "Dummy Track 2"
  
  --2) Swap Dummy tracks to members 1 and 2 of group (this works re. the swap bug as we are not swapping two groups)
  song:swap_tracks_at(member_idx,member_idx+1)
  song:swap_tracks_at(member_idx+1,member_idx+2)
  
  --3) Preparation done, so bring the track we want into the group
  --Swap dummy member 2 with target track outside group (left_of_grp_idx was found near beginning of function)
  --note: if we were to swap dummy member 1 then both tracks get ejected from group
  song:swap_tracks_at(left_of_grp_idx,(left_of_grp_idx + 2))
 
  --4) Tidy up: delete dummy tracks by looping objects 
  --(as we are deleting tracks it is safer to loop and find the dummy track objects specifically as
  --we might lose wanted song tracks if we were calculating indexes and a mistake made)
  --As indexes can change when a track is deleted, it is simpler to use 2 loops
  for i = 1,#song.tracks do
    if rawequal(song:track(i),dummy_trk_1) then
      --delete dummy 1
      renoise.song():delete_track_at(i)
      break
    end
  end
  
  for i = 1,#song.tracks do
    if rawequal(song:track(i),dummy_trk_2) then
      --delete dummy 2
      renoise.song():delete_track_at(i)
      break
    end
  end
end

Worth pointing out aswell another issue (maybe annoyance) with renoise group track dragging behaviour:

In the following situation you can`t drag track 1 into Grp 2 as the first member. You have to drag it behind Grp 1 to become the second member and then swap 1 with Grp 1 with another drag.

Not sure if by design or accidental omission? but it would be more comfortable if you could just drag it in one go.

8236 cant drag group.PNG