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.
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.
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.
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()
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…
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.
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).