[Solved] Problem to create a function for close empty note_columns

Hi :slight_smile:

I’ve been trying to build a simple function that checks if the last column of note is empty in selected track, then close it. So the function closes all empty note columns.The problem is that the function is very heavy with several “for … do”:

The function (this is the idea):

function gtc_note_column_close_empty( song, sti )
  song = renoise.song()
  sti = song.selected_track_index

  for ptt = 1, #song.sequencer.pattern_sequence do --for all patterns
    for lns = 1, song.patterns[ptt].number_of_lines do --for all lines of pattern
      for nc = 12, 2, - 1 do --for all note_columns in track
        if song.patterns[ptt].tracks[sti].lines[lns].note_columns[nc].is_empty == true then
          song.tracks[sti].visible_note_columns = nc - 1
        end
      end
    end
  end
end

Is there any much more effective code to do this?Maybe it has something wrong in this function?This function is very slow and hangs Renoise.

Also I want to build another function for effect columns, which should be very similar.

Any ideas?

Maybe it has something wrong in this function?

Very quickly looking Raul I would say that there is :slight_smile:

[Edit:] Something a bit more like:

function vslowscanner(song, sti)
  song = renoise.song()
  sti = song.selected_track_index

  for nc = 12, 2, -1 do  
    for ptt = 1, #song.sequencer.pattern_sequence do
      for lns = 1, song.patterns[ptt].number_of_lines do
        if song.patterns[ptt].tracks[sti].lines[lns].note_columns[nc].is_empty == false then         
          song.tracks[sti].visible_note_columns = nc
          return     
        end
      end
    end
  end
  song.tracks[sti].visible_note_columns = 1
end

(going to be awful slow (prepare for the infamous ‘terminate script’ dialog roughly every 10 seconds!))

Just a thought: Didn’t Ledger/Joule have a similar idea here? → https://forum.renoise.com/t/new-tool-2-7-3-1-set-track-width-to-active-columns/31078

The routine I used in that revision for ledgers tool should indeed be among the fastest for exactly this task (scanning which note column is the most “far right” in use, or for accessing multiple note columns per line in general). This is because it only accesses the renoise.song() object once for every patternline, instead of 12 times.

The pattern matching used in the code should show the principle, I hope (line 79-81 in main.lua are most interesting).

https://forum.renoise.com/t/new-tool-2-7-3-1-set-track-width-to-active-columns/31078

PS. I cannot help you with the specific implementation for your tool, though.

Thanks 4Tey and Joule!

I was thinking this was going to be a drastic code optimization exercise.

Finally, I have stolen much of the code of the Ledger/Joule tool.So I can use 2 separate buttons to shoot:

For close empty note_columns inside selected track:

--close empty note columns in selected track
function gtc_note_column_close_empty_individual( song, sti )
  song = renoise.song()
  sti = renoise.song().selected_track_index

  if not (renoise.song():track(sti).type == renoise.Track.TRACK_TYPE_SEQUENCER) then
    return
  end

  local sub = string.sub
  local reverse = string.reverse
  local match = string.match
  local max = math.max
  local max_note_column = 1
  local floor = math.floor
  local find = string.find

  for _, pattern in ipairs( song.patterns ) do
    local patterntrack = pattern:track( sti )
    if not patterntrack.is_empty then
      local lines = patterntrack:lines_in_range( 1, pattern.number_of_lines )
      for _, line in ipairs( lines ) do
        if not line.is_empty then

          local line_str = sub( tostring( line ), 0, 214 )
          line_str = reverse( line_str )
          local first_match = match( line_str, "%d.[1-G]" )
          max_note_column = ( first_match and max( max_note_column, 12 - floor( find( line_str, first_match ) / 18 ) ) ) or max_note_column

        end
      end
    end
  end
  song:track( sti ).visible_note_columns = max_note_column
end

For close empty note_columns in all the song:

--close empty note columns in entire song
function gtc_note_column_close_empty( song )
  song = renoise.song()
  for sti = 1, song.sequencer_track_count do
    local sub = string.sub
    local reverse = string.reverse
    local match = string.match
    local find = string.find
    local max = math.max
    local floor = math.floor
    local max_note_column = 1
    local has_note_columns = song:track( sti ).type == renoise.Track.TRACK_TYPE_SEQUENCER
  
    for _, pattern in ipairs( song.patterns ) do
      local patterntrack = pattern:track( sti )
      if not patterntrack.is_empty then
        local lines = patterntrack:lines_in_range( 1, pattern.number_of_lines )
        for _, line in ipairs( lines ) do
          if not line.is_empty then
            local line_str = tostring( line )
            
            if has_note_columns then
              local ncol_line_str = sub( line_str, 0, 214 )
              ncol_line_str = reverse( ncol_line_str )
              local ncol_first_match = match( ncol_line_str, "%d.[1-G]" )
              max_note_column = ( ncol_first_match and math.max(max_note_column, 12 - floor( find( ncol_line_str, ncol_first_match ) / 18 ) ) ) or max_note_column
            end
            
          end
        end
      end
    end
    if has_note_columns then
      song:track( sti ).visible_note_columns = max_note_column
    end
  end
end

I suppose it is valid for any range of lines according to each pattern…

local line_str = sub( tostring( line ), 0, 214 )
line_str = reverse( line_str )
local first_match = match( line_str, "%d.[1-G]" )
max_note_column = ( first_match and max( max_note_column, 12 - floor( find( line_str, first_match ) / 18 ) ) ) or max_note_column

Why these numbers 214, and /18 are used?This allows you to check several note_columns at a time?Mathematics is magic here!!! :smiley:

A brief overview:

  • max_note_column is storing the far right note column that is in use (non-empty).

  • string.match always returns the character position of the very first match. This is why the string is reversed before searching it, allowing to search “backward” in the string and thereby determine the highest note column in use.

  • the “/18” is because each note column occupies 18 characters in a tostring(patternline). “—…0000 |”. What the line really does is “converting” a character match position in the patternline string, to a note_column_index.

  • sub.string with 214 is just used to strip the effect columns in the patternline string. We’re searching note columns and nothing else.

A brief overview:

  • max_note_column is storing the far right note column that is in use (non-empty).

  • string.match always returns the character position of the very first match. This is why the string is reversed before searching it, allowing to search “backward” in the string and thereby determine the highest note column in use.

  • the “/18” is because each note column occupies 18 characters in a tostring(patternline). “—…0000 |”. What the line really does is “converting” a character match position in the patternline string, to a note_column_index.

  • sub.string with 214 is just used to strip the effect columns in the patternline string. We’re searching note columns and nothing else.

Thank you very much! :smiley: