[Solved] Help LUA: function to create a Group with two Tracks, one col

A question a little convoluted: an order that meets the following: How select always the first track inside the group,regardless of the number of tracks inside the group and regardless of the current selection in the group?

In the index, the group always isbehind the tracksthat comprise it. The group has right and left limit?

Per example:

  1. song:track(song.selected_track_index) is the track selected
  2. song:track(song.selected_track_index + 1) serve to select the next track or group (to right)
  3. song:track(song.selected_track_index - 1) serve to select the previous track or group (to left)

But these codes not serve…

Imagine a group with 5 tracks, selected the track 4. Imagine a group with 5 tracks, selected the track 2. Imagine a group with 5 tracks, selected the group.What would a code to always select the first track, regardless of all these random cases?

Yeah, referencing song.selected_track_index is a bit cringe-worthy here. It looks nicer (for more purposes) to store the absolute first octave track index and the group track index in variables that have a larger scope. These can then be used for whatever.

– Set the selected track to prev/next relative to the current track. Takes

– care of skipping over hidden tracks and wrapping around at the edges.

renoise.song():select_previous_track()

renoise.song():select_next_track()

With select_previous_track() I can not do anything neither.And jump directly to the left track outside the group?

I would absolutely stay away from those in this case.

If you need to keep track of your octave tracks (and group track index), you should do so by, upon creation, storing those values in variables that can later be reused.

This is the way of numbering in the index:

T 1 T 2 --------G 6 -------T 7 T 8… Master 9 Sfx 10… (index = 10)
T 3 T 4 T 5

T 1 T 2 --------G 9 --------------------- T1 0 T 11… Master 12 Sfx 13…(index = 13)
T 3 T 4 T 5 T 6 T 7 T 8

T 1 T 2 --------G 13 --------------------------------------- T 14 T 15… Master 16 Sfx 17…(index = 17)

T 3 T 4 T 5 T 6 T 7 T 8 T 9 T 10 T 11 T 12

  • Blue, random selection.
  • The selection is always within the group.
  • The only thing is true here is that T2 is ever before T3 in all cases. T2 = Original Track, Gx = Group Octaves.
  • How always select the T3? (wherein the amount of tracks within the group is variable).
  • It may be the case that T1 does not exist.

EDIT:I’ll try to implement it before creating the group, but I’m having problems in the selection as well.

By storing what index T3 has when you create it and use that for later.

Beware that as soon as you delete any previous track, such reference will become wrong and will need to get updated.

Solved!!! :w00t: :w00t: :w00t:

Finally I opted for a bungled solution.In order to select the first track (the T3) at the end of the process,is essential whenever the first track (T3) is empty. :slight_smile: So, I added an empty track, which is then removedautomaticallyin the new function delete_tracks_empty.This code works perfectly!!!:

local group_settings = {
ten_octaves = {
  name = "Octaves",
  color = { 0x80,0x80,0x80 },
  color_blend = 27,
  collapsed = false,
  tracks = {
  { name = "empty" }, -- to select first track always
  { name = "0 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x70,0x70,0x70 }, color_blend = 10 },
  { name = "1 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x40,0x40,0x40 }, color_blend = 10 },
  { name = "2 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x70,0x70,0x70 }, color_blend = 10 },
  { name = "3 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x40,0x40,0x40 }, color_blend = 10 },
  { name = "4 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x70,0x70,0x70 }, color_blend = 10 },
  { name = "5 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x40,0x40,0x40 }, color_blend = 10 },
  { name = "6 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x70,0x70,0x70 }, color_blend = 10 },
  { name = "7 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x40,0x40,0x40 }, color_blend = 10 },
  { name = "8 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x70,0x70,0x70 }, color_blend = 10 },
  { name = "9 Oct", volume_column_visible = true, delay_column_visible = true, collapsed = true, color = { 0x40,0x40,0x40 }, color_blend = 10 },
  },
  },
}
local column_names = {
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
}

function insert_track(track_index, group_index, track_setting)

  renoise.song():insert_track_at(track_index)
  local track = renoise.song():track(track_index)
  track.visible_effect_columns, track.visible_note_columns = 0, 12, false -- track.volume_column_visible
  for parameter_name, parameter_value in pairs(track_setting) do
   track[parameter_name] = parameter_value
  end
  for note_column = 1, 12 do
    track:set_column_name(note_column, column_names[note_column])
  end
  renoise.song():add_track_to_group(track_index, group_index)

end

function insert_gt(group_setting)

  local song = renoise.song()
  local i, group_index, group_setting = 1, song.selected_track_index + 1, group_settings[group_setting]
  song:insert_group_at(group_index)
  for parameter_name, parameter_value in pairs(group_setting) do
    if not (parameter_name == "tracks") then
      song:track(group_index)[parameter_name] = parameter_value
    end
  end
  for _, track_setting in ipairs(group_setting.tracks) do
    local group_index = group_index + i
    i = i + 1
    insert_track(song.selected_track_index, group_index, track_setting)
  end
  song.tracks[song.selected_track_index + 1].group_parent.collapsed = true -- collapse FX in Group
end

function explode_pitches(track_index, first_octave_track_index)

  local song = renoise.song()
  local track = song:track(song.selected_track_index)
  local pattern_iterator = song.pattern_iterator:note_columns_in_track(track_index, true)
  local notes = { }
  local sort_per_column = function(a,b)
      if a.column < b.column then return true
      elseif a.column > b.column then return false
      elseif a.pattern < b.pattern then return true
      elseif a.pattern > b.pattern then return false
      elseif a.line < b.line then return true
      elseif a.line > b.line then return false
      end
    end
    
  for pos, note_column in pattern_iterator do
    if not note_column.is_empty then
      table.insert(notes, { note_column = note_column, pattern = pos.pattern, track = pos.track, column = pos.column, line = pos.line })
    end
  end
  
  table.sort(notes, sort_per_column)

  for i, note in ipairs(notes) do
    if not (note.note_column.note_value == 120) then
      local dest_track = first_octave_track_index + math.floor(note.note_column.note_value/12)
      local dest_column = (note.note_column.note_value % 12) + 1
      song:pattern(note.pattern):track(dest_track):line(note.line):note_column(dest_column):copy_from(song:pattern(note.pattern):track(note.track):line(note.line):note_column(note.column))
      if notes[i+1] then
        if (notes[i].column == notes[i+1].column) and (song:pattern(notes[i+1].pattern):track(dest_track):line(notes[i+1].line):note_column(dest_column).note_value == 121) then
          local next_note = song:pattern(notes[i+1].pattern):track(dest_track):line(notes[i+1].line):note_column(dest_column)
          next_note.note_value = 120
          next_note.delay_value = notes[i+1].note_column.delay_value
        end
      end
    end
  end
end

function delete_tracks_empty()
  local song = renoise.song()
  local tindex = song.selected_track_index
  song:track(tindex).collapsed = true -- original track
  song:track(tindex).color_blend = 10
  song:track(tindex).color = { 0xFF,0x00,0x00 }
  song.tracks[tindex]:mute()

  local first_octave_track = tindex + 1
  for group_index = first_octave_track + 10, first_octave_track, - 1 do
    local was_empty = false
    for _, pattern in ipairs(song.patterns) do
      if not pattern:track(group_index).is_empty then
        was_empty = true
      end
    end
    if not was_empty then
      song:delete_track_at(group_index)
    end
  end
  song:track(tindex + 1).collapsed = false -- select first track
end

function rebuild_menu()
  local song, menu_entry = renoise.song(), "Pattern Editor:Track:Explode Pitches To Octaves"

  if renoise.tool():has_menu_entry(menu_entry) then
    renoise.tool():remove_menu_entry(menu_entry)  
  end

  if (song.selected_track.type == renoise.Track.TRACK_TYPE_SEQUENCER) then
    renoise.tool():add_menu_entry {
    name = menu_entry,
    invoke = function() insert_gt("ten_octaves") explode_pitches(song.selected_track_index, song.selected_track_index + 2) delete_tracks_empty()
             end }
  end
end

function start()
  renoise.song().selected_track_observable:add_notifier(rebuild_menu)
  rebuild_menu()
end

renoise.tool().app_new_document_observable:add_notifier(start)

I do not like how are these lines:

local tindex = song.selected_track_index
  song:track(tindex).collapsed = true -- original track
  song:track(tindex).color_blend = 10
  song:track(tindex).color = { 0xFF,0x00,0x00 }

How you could arrange better? Something like the first lines of code above.

joule, do you know this code?:


– renoise.GroupTrack (inherits from renoise.Track)


-------- Functions

– All member tracks of this group (including subgroups and their tracks).

renoise.song().tracks[].members[]

-> [read-only, array of member tracks]

– Collapsed/expanded visual appearance of whole group.

renoise.song().tracks[].group_collapsed

-> [boolean]

Does this code how it works? :

renoise.song().tracks[].members[]

-> [read-only, array of member tracks]

members??? What can be done about this?

Oher question in LUA, a example:

T 1 T 2 --------G 6 -------T 7 T 8… Master 9 Sfx 10… (index = 10)
T 3 T 4 T 5

Is it possible to copy the All DSP Chain of Track T2 in the Group G6?

– Insert a new device at the given position. “device_path” must be one of

– renoise.song().tracks[].available_devices.

renoise.song().tracks[]:insert_device_at(device_path, device_index)

-> [newly created renoise.AudioDevice object]

– Delete an existing device in a track. The mixer device at index 1 can not

– be deleted from a track.

renoise.song().tracks[]:delete_device_at(device_index)

– Swap the positions of two devices in the device chain. The mixer device at

– index 1 can not be swapped or moved.

renoise.song().tracks[]:swap_devices_at(device_index1, device_index2)

– Access to a single device by index. Use properties ‘devices’ to iterate

– over all devices and to query the device count.

renoise.song().tracks:device(index)

-> [renoise.AudioDevice object]

– Selected in the track DSP chain editor. Can be nil.

renoise.song().selected_track_device, _observable

-> [read-only, renoise.AudioDevice object or nil]

renoise.song().selected_track_device_index

-> [number, index or 0 (when no device is selected)]

Moving the device chain is not very straight forward. You might get some help looking into this tool: https://forum.renoise.com/t/new-tool-2-8-move-device-chain/34475

Hi joule. Thanks for the link!

You have made a lot of tools! I will try to study their link tool.My intention is to copy, not move.Something more advanced would be to copy the DSP chain and automation, from the Track T3 to G6 Group.This would be super, but I see very complicated.

I also wonder if in future versions of Renoise (v3.2 … v.4), these tools created if continue to work correctly.Some of them cost much to create them.

I think I’ll leave the tool as it is in the code of above comment #65:https://forum.renoise.com/t/solved-help-lua-function-to-create-a-group-with-two-tracks-one-col/46138

If there is any DSP chain or Automation in Original Track,must be added manually after.So the tool is not excessively complicated.

Is possible that I change some detail,as copy the name of the original track and paste in the group name.I am also thinking of adding two modes: “explode” (the current code) and “convert” (deleting also the original track).

I am also thinking of adding two modes: “explode” (the current code) and “convert” (deleting also the original track).

Advice:

Removing a track is one of the most basic tasks, and most trackers are probably familiar with what shortcut to use. I would suggest it to be good practice not to clutter the interface with an additional menu entry in such case. The user will instinctively assume that menu entries have relevant and specific purposes (unless their titles are very similar).

Advice:

Removing a track is one of the most basic tasks, and most trackers are probably familiar with what shortcut to use. I would suggest it to be good practice not to clutter the interface with an additional menu entry in such case. The user will instinctively assume that menu entries have relevant and specific purposes (unless their titles are very similar).

Thanks joule.I keep that in mind.

On the other hand, I found a strange behavior in Renoise.I had not realized until now: in Pattern Editor or DSP pane, the Mute and the Solo do not run with the undo command Ctrl-Z. Per example:

  1. Mute or Solo a track or group with the mouse, in Pattern Editor or DSP pane.
  2. Ctrl-Z to undo. Does nothing! …I guess there are some reason.

Mmm some details annoy creating some tools with LUA.

Hi joule.Finally, I’ll leave the code as you say, with one simple choice.

I found 5 new bugs in the code.I think it was a blunder not see before, are small details:

Note | Instrument | Volume | Panning | Delay | Effect

Bug 1 (lost instrument parameter):

=================

C-0 00 55 50 530I20

… 00

=================

Bug 2 (lost volume parameter):

=================

C-0 00 55 50 530I20

… 30

=================

Bug 3 (lost panning parameter):

=================

C-0 00 55 50 530I20

… 70

=================

Bug 4 (lostdelayparameter):

=================

C-0 00 55 50 53 0I20

… 3E

=================

Bug 5 (lost effect parameter), effect in note-column:

=================

C-0 00 55 50 53 0I20

… 0I30

=================

Apparently all are related. In each bug an error appears in the Terminal because there is not associated note in the same line.If the code solves these cases, also serve to review old songs.In these rare cases, lost parameters could relate to the last note that appears above (in bold, C-0 ), including between patterns.This seems more difficult to solve.

Can you fix it? This follows yourcommentary #49(special cases forgotten) :blush:

EDIT:It remains to be if it’s worth transferring the 8 Effects Columns of the Original Track at 8 Effects Columns in Group, and I do not know if it works the same way…It is also a case forgotten. The code I use now is this:commentary #65

I will have to look into that later since I’m a bit busy with other stuff! … It only affects C-0? That has a note value of “0”, so most probably something strange is happening when doing modulus on it to find dest_track/column. Something like division by zero :slight_smile:

I’d guess it can be fixed by inserting an if statement above that catches this case.

…It only affects C-0? …

I’d guess it can be fixed by inserting an if statement above that catches this case.

No, it affects all notes in all octaves.What “C-0” was an example for you to see (sorry if I’ve confused).Simply, is a parameter lost whichever in a line: fails (the code does not contemplate).I supposed that a reference is needed to place the “parameters lost”, for example, the last note above (note+octave).

The code is so far, it works correctly (is not an error code, is something missing). Really, it’s like lack an order to fix all these cases. Yes, probably with an if.Something like a sweep of all lines in all note columns that do not include a Note or a Note-OFF. When it finds the first lost parameter, add a note-OFF and ceases to convert the rest, obtaining a error in the Terminal.

Do not worry about the time.No rush. I would like the tool to operate as fine as possible.

…These days I’m testing the code with actual songs of other users.If I find rarer cases, I commented to you.

EDIT: You can use this song for testing:6770 ulneiz-Piano-Group-v3_12-OCTAVES.xrns This song has rare situations (lost parameters).

Hi joule!

You have been able to advance this issue? (concerning the comment #73).I used this script several times, and I find it very useful.I wish it worked fine and perfect it.

For me it is very great to sort the notes by octaves :walkman:

I’ve tried other old songs, and it seems that the error only occurs if “lost parameters” are added after recording live with a MIDI keyboard…

Thanks in advance!

Finally, this whole topic is now resolved. Thank you very much to joule for all your help!

I have written all the code again to sort the pitch of notes per octaves.Exhausted to resolve this! :unsure:

This tool is embedded in my future tool of “Insert Groups & Tracks per Colors” with a only window version. Soon I will share…

Regards!

I am proud to announce my new tool: GT16-Colors.

You can download it here:https://forum.renoise.com/t/new-tool-3-1-gt16-colors-v1-2a1-updated-12-june-2017/46473

This tool is somehow related to this topic. Integrate advanced tool “SPNO”, direct legacy of this topic.Download, use and enjoyment!