I also took a quick look. Raul - I have to say, for a realtime script, you are actually being quite wasteful…
if song:pattern( spi ):track( sti ):line( stpl ):note_column( 1 ).note_string ~= '---' then -- do something end if song:pattern( spi ):track( sti ):line( stpl ):note_column( 1 ).note_string == 'OFF' then -- do something end -- etc...
There is nothing “wrong” here per se, but several things you can do better.
As per my third advice in the lua optimization thread, it’s good idea to store references to objects that you are going to call repeatedly.First of all, it’s very simple to avoid several function calls by storing a reference to the line you’re working on:
local ln = song:pattern( spi ):track( sti ):line( stpl )
This way, you avoid the three API functions you are calling - pattern(), track() and line() - each time you need to access a note column.
And since you are using the line above a total of 48 times, this is 48*3 == 144 function calls avoided, with one simple change.It makes the code a lot easier to read too
Another improvement is to use the if … else syntax to simplify comparisons:
if (ln:note_column( 1 ).note_string ~= '---') then -- do something elseif (ln:note_column( 1 ).note_string == 'OFF') then -- do something else end
Or better still, using the previous technique and storing a reference to the note-column (additionalcalls avoided)
local col = ln:note_column( 1 ) if (col.note_string ~= '---') then -- do something elseif (col.note_string == 'OFF') then -- do something else end
Using if…else is more efficient, since the second statement - looking for the (“OFF”) - will never be evaluated if the first part was found to be true.
Now, with such a simple example there might not be a big impact. But imagine that your code was more complex than this? Skipping parts as early as possible can be a HUGE performance booster.
And both are general principles which can be applied to any programminglanguage
I never used the timer, so I don’t have much experience with that.To me, idle_notifier is the natural choice, as it simply runs when Renoise has time for it.
I explain a little my current way of making code.
- My first objective is to test if something works.If it works, it does not matter whether the code is heavier or not, it just works.
- Point 1 forces me to study their parts, because it allows me to see what I can do or not with them (If I do the “compressed code”, I do not see some parts).This usually happens to me because at first I do not know if I will be able to build a concrete code. I am in the testing phase, and trial and error.
- After checking if the code works, I start to optimize it.I have not been with LUA for a long time, but I recognize that I have undergone an evolution, and more with the Renoise API.
Last night, I did an optimization phase using these two things:
--change_buttons
function change_buttons( song, spi, sti, stpl, i )
song = renoise.song()
spi, sti, stpl = song.selected_pattern_index, song.selected_track_index, song.transport.playback_pos.line
if song.selected_track.type == renoise.Track.TRACK_TYPE_SEQUENCER then
for i = 1, 12 do
-- note column i
if song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string ~= '---' then
vb.views["TNC_NC_"..i..""].text = song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string
vb.views["TNC_NC_"..i..""].color = tnc_tr_color()--{ 0x00,0x70,0x00 }
end
if song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string == 'OFF' then
vb.views["TNC_NC_"..i..""].color = { 0x40,0x00,0x00 }
end
vb.views["TN_NC_NM_"..i..""].text = string.format(" %s", song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string )
end
vb.views["TNC_TXT_LNE"].text = string.format( "%.3d", stpl - 1 ) --for read number of line
end
end
I’m calling 12 equal buttons, so I can use “for … do”.I could also use a “local” to save calls for:
song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string
Other Optimization:
--default values
function tnc_df( tx, cl, i )
tx = '---'
cl = { 0x20,0x00,0x00 }
for i = 1, 12 do
vb.views["TNC_NC_"..i..""].text = tx
vb.views["TNC_NC_"..i..""].color = cl
end
end
Other, if use song.selected_line instead of song.transport.playback_pos.line ( =stpl ) inside the
song:pattern( spi ):track( sti ):line( stpl ):note_column( i ).note_string
I can use:
song.selected_line:note_column( i ).note_string
This is in phase of code optimization. But the fact is that both the previous code and the “compressed code”, work the same, they are asking for the same thing.I have tried both situations and Renoise works exactly the same.If Renoise returns “a error”, it will continue to return, maybe less, but there it is.The subject is how to skip it.
I have read the last comment of 4Tey, and seems to read my mind.It seems that in the pattern jump to the next pattern, the request is faster perhaps in analyzing the line than in changing pattern, thus written errors of notes appear, maybe.The code seems logical and correct, only that does not prevent Renoise’s erratic behavior.
Based on theory alone, it should work perfectly just the way it is.Now I have no idea how to skip this subtle error!!!
Regarding using idle_notifier or a timer, the idle_notifier work about 100ms aprox. (I have understood). Then it is slow to read the update of each line.It happens that the duration of a single line is less than those 100 ms, even to a not very fast reproduction (below BPM 300 and LPB 8).
So I prefer to use a timer.But if the fast timer returns errors, I think it does not depend on the timer itself, but on the code under the hood of Renoise.
So now I’m dead point.How can I avoid these errors, if the code is apparently correct.
…
Another thing.At least to change things from the viewbuilder,I think that an observable fortransport.playback_pos.line and selected_line / selected_line_index would be very feasible.I wish it were possible.If the speed is very high, it might be appropriate to put an internal limiter to the observable, and at slower speed, that works in real time, to avoid having to invent code to solve such simple things.With a notice to the programmer in the documentation of the risks of using an observable in real time to follow the line or the playback, would be solved.I can think of a lot of useful tools thanks to this. Would be wonderful!!!
When I have a little time,I will share a v1.0b2 of the tool to see if we can find a way to make it work perfectly.It would be a good example recently. Most old tools that are related to following the line at all times, do not workor are outdated (not supported Renoise 3.1).
Thanks for all the help, lately I’m learning those more advanced tricks that allow me to think differently.