Is there some api shortcut for "getInstrumentOfTrack()"?

Assuming each track only is used by one instrument, is there a api shorthand / native code for getting the instrument of a track? Iterating over all the pattern lines until a first instrument number appears, that seems to be very costly.

Since there is the options “Auto capture instrument from pattern”, this seems to be already implemented…

The instrument autocapture option works for multiple instruments within the same track and appears to work “by proximity” from top to bottom.

You can do a pretty quick search of the first index of the instrument using the text string of the line, and jumping all the empty lines before with a iterator for-do, keeping in mind only the visible note columns.

Sure, and good point with visible note columns, thx.

But I would like to have that said functionality as API function, because I would guess that it’s way faster than any lua code.

EDIT: So tracks[].visible_note_columns will contain only the visible columns?

Yes, returns you the index of visible note columns. If you have 3 columns, it will return the number 3.

You can also speed up the search by skipping the empty track patterns.

Skipping all that is empty the search can be quite fast.

You can cut the length of the text string for each line based on the number of visible note columns (calculate the number of characters). You can isolate the values referring to the index of each instrument, from left to right, and return the value of the index with a “return” within the iteration.

hm but the patterniterator only returns a note_column object, not a visible_note_column object. Kinda annoying…

renoise.song().tracks[].visible_note_columns, _observable
  -> [number, 0 OR 1-12, depending on the track type]
>>> print(renoise.song():pattern(1):track(1):line(1))
C-400......0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | ---........0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000

I guess this way is faster than using tables from all note_column ()

The most extreme case is 512 lines x 1000 patterns, if there is only one instrument index at the end of the song.

Too lazy for that, used patterniterator. Is the patterniterator also iterating empty PatternTracks? If so, why? Maybe not…

I don’t usually use that.

local function search_instrument_index_per_track()
  local x=os.clock()
  local song=renoise.song()
  local sti=song.selected_track_index --or the track index that you prefer
  local vnc=song.selected_track.visible_note_columns
  --search inside all patterns (from top to bottom)
  for pat=1,#song.patterns do
    --skip empty patterns
    if (not song:pattern(pat).is_empty) then
      local pat_=song:pattern(pat)
      --search inside all visible lines of pattern
      for lne=1,pat_.number_of_lines do
        --skip empty pattern-track
        local trk_=pat_:track(sti)
        if (not trk_.is_empty) then
          --skip empty lines
          local lne_obj=trk_:line(lne)
          if (not lne_obj.is_empty) then
            --convert object to string
            local lne_string=tostring(lne_obj)
            --each note column has 18 characters, interest characters 4 and 5 of each.
            for char=4,18*vnc,18 do
              if (string.sub(lne_string,char,char+1)~="..") then
                print(string.format("search_instrument_index_per_track: %.2f ms\n",(os.clock()- x)*1000)) 
                --return tonumber(string.sub(lne_string,char,char+1),16)
                return string.sub(lne_string,char,char+1)
              end
            end
          end
        end
      end
    end
  end
end
print(search_instrument_index_per_track())

I just wrote this function for fun right now. You can try it on TestPad.lua. You can use this function adapted to any other index.

About the speed

This function returns the two-character value (string or number, with tostring), corresponding to the index of the first instrument that it detects from top to bottom.

In a song of 16 patterns of 64 lines each with 12 columns of visible notes, if you write a note at the end, it takes 0.98 ms with my CPU.
In practically any real practical case that you use this function, the delay time will be even shorter.

It would be interesting to see an equivalent function using pattern_iterator to check which one is faster.

Note: with a little more code it is possible to put all the detected instrument index of a track into a table.

2 Likes

Hm, ok… My recent tool has an option to find all sending instrument chains in a signal flow path… I am searching then each included track for the for appearance of an instrument number, which obviously can be result in a quite costly / slow experience with a project having a lot of patterns.

Currently using the pattern-iterator thing, but it doesn’t skip completely empty tracks (or does it @taktik ? I guess not, due some logical reasons…). Will try now your approach, Raul, testing if that gives any speed benefit… But I guess, if Renoise would provide here a shortcut, the same code used for “auto selected instrument of track”, it would be faster by eons…

-- Captures the current instrument (selects the instrument) from the current
-- note column at the current cursor pos. Changes the selected instrument
-- accordingly, but does not return the result. When no instrument is present at
-- the current cursor pos, nothing will be done.
renoise.song():capture_instrument_from_pattern()

-- Tries to captures the nearest instrument from the current pattern track,
-- starting to look at the cursor pos, then advancing until an instrument is
-- found. Changes the selected instrument accordingly, but does not return
-- the result. When no instruments (notes) are present in the current pattern
-- track, nothing will be done.
renoise.song():capture_nearest_instrument_from_pattern()

Can you prove this? Maybe it will help…

Ah, thanks for this info! Checking for empty track already gives a huge speedup. Sadly can’t try those methods, since it only finds in the currently selected track, but not any given track index… Maybe I could temporarily switch the selected track, which is kind of an ugly workaround… Give me some minutes.

EDIT: Nah, I would also have to temporarily switch to pattern pos 0, and remember the selected instrument. I guess that will look ugly, won’t try.

Wow, what an ugly looking method, why there is no continue in lua? if if if if for if for ififif end end end end end end end

function getInstrumentOfTrack(track)
  local trackIndex = EQHelper:getTrackIndex(track)
  for patternIndex = 1, #sng.patterns do
    local pattern = sng:pattern(patternIndex)
    if (not pattern.is_empty) then
      local _track = pattern:track(trackIndex)
      if (not _track.is_empty) then
        for lineIndex = 1, pattern.number_of_lines do
          local patternLine = _track:line(lineIndex)
          if (not patternLine.is_empty) then
            
            for colIndex = 1, track.visible_note_columns do
              local noteColumn = patternLine:note_column(colIndex)
              if (noteColumn.instrument_value ~= 255) then
               return sng:instrument(noteColumn.instrument_value + 1)
              end
            end
            
          end
        end
      end
    end
  end
  
  return nil
end

track.is_empty does not seem to work with hidden / inactive columns. If there are hidden notes, it will be not empty…

Hey ffx

Maybe installing my tool along side yours would help (or implementing similar):

To save the time penalty with the scanning it automatically puts the instrument number in the first line of every track with a note in. So only needs to do a big scan once.

capture

Additionally (and the other way around), i like to have a track selected in which the currently selected instrument is used in.
So it looks something like this :

function on_selected_instr_changed(args)

  local song = renoise.song()
  local ii = song.selected_instrument_index
  local pi = song.selected_pattern_index

  for pos,line in song.pattern_iterator:lines_in_pattern(pi) do
      if not line.is_empty then
        for _,note_column in ipairs(line.note_columns) do
          if note_column.instrument_value == ii - 1 then
            renoise.song().selected_track_index = pos["track"]
            return
          end
        end
      end
  end
  
end

renoise.song().selected_instrument_observable:add_notifier(on_selected_instr_changed)

This basically traverses the current pattern by line and checks if the instrument_value in each note_column matches the currently selected instrument index. if one matches, its track will be selected.
(Note that instrument_value starts from 00).