Work in progress: Piano roll

Looks very nice, i wouldn’t use it for the main compositing, but it could be very useful for tweaking patterns. :slight_smile:

Some thoughts:

-There should be a way to move the blocks outside the grid translating into numbers in delay column. Ctrl + drag would make sense as the ctrl key is the key for fine adjustments.

-Wouldn’t it be cool if you could also drag the note to set it’s off command? I suggest something like shift + drag, or just simply by click dragging the right edge of the note.

I haven’t really cared much for piano rolls, but this could actually be quite useful.

Great work!

I haven’t really cared much for piano rolls, but this could actually be quite useful.

You do not care about pianorolls until you see one in action. Mr Airman,and many more,will be very happy to see this when he returns ^_^.

1 Like

Cool stuff! :yeah:

It is still very laggy and buggy, but not hopeless I think.

what aspects are laggy, updating the piano roll tool with the note-events out of the pattern editor while playing back a song?

Perhaps some of the tips in this thread can help? https://forum.renoise.com/t/renoise-tools-speed-optimization-initiative/45510

  1. This was on my to do list. I already tried vvoois’s osc example script. It didn’t work. Server rejects. Can’t it be done easier with fewer code? It’s just simple note on/off.

I don’t recommend anything else than OSC for any kind of auditioning. I did a “play and stop” scheme once, but OSC is really the simple and safe way to go.
The server is set up in preferences. Try both UDP and TCP, in case one of them is buggy. For the script, I recommend the Duplex.OscClient class.

I so lack right-click and mouse wheel support. As well as resizeable bitmaps or semitransparent buttons (e.g. to visualize selection area)

Indeed. And resize gadget in bottom right corner :frowning:

I think you could make a cheap selection area by overlaying either a ‘dithered’ or a semi-transparent bitmap (repeated inside a ‘cropping rack’).

…And resize gadget in bottom right corner

I had thought exactly the same thing. In fact, it’s the first thing I thought. The possibility of modifying the size of the window is missing.This tool has very advanced things. It gathers many things that do not usually appear in other tools.

1 Like

USEFULL a lot !, May be to add a Listbox with simply or commons piano chords to insert too?

I thought about visualising scales. But this is not the primary goal either. First of all I have to polish note placement so that altering notes wouldn’t occasionally delete neighbours.

-There should be a way to move the blocks outside the grid translating into numbers in delay column.

Yes, it should be implemented too. But not first on the list either.

By the way, my first attempt at coding useful tool for Renoise was couple of years ago. It was “repeat note”. Then I had to deal a lot with delay column. Maybe I should present this tool again.

Wouldn’t it be cool if you could also drag the note to set it’s off command? I suggest something like shift + drag, or just simply by click dragging the right edge of the note.

Yes, dragging the edge of both ends is a must.

what aspects are laggy, updating the piano roll tool with the note-events out of the pattern editor while playing back a song?

Perhaps some of the tips in this thread can help? https://forum.renoise.com/t/renoise-tools-speed-optimization-initiative/45510

It equally lags in play mode or not. And processor is not overloaded at all. So it has to do with updating values from XYpad maybe.

Looks promising. Looking forward to trying it out myself.

I’d also like to see note auditioning and coloring. Keep up the good work!

Wow, great work, seems you are a Lua expert to begin with:). If the piano roll works well then I think making it like FL Studio piano roll features would be a general good direction.

1 Like

what aspects are laggy, updating the piano roll tool with the note-events out of the pattern editor while playing back a song?

I’ve found the place in code which make dragging notes lag. It’s when note positions and length is gathered from track. Maybe I can show it

Click to view contents
noteTone = {}
		noteLength = {}
		noteLine = {}
		noteColumn = {}
		
		lineValues = song.selected_pattern.tracks[trackId].lines
		
		local columns = song.tracks[trackId].visible_note_columns
		for c = 1, columns do
			for s = 1, steps do
				local note = lineValues[s].note_columns[c].note_value
				if note < 120 then --120 is off, 121 is empty
					table.insert(noteTone, note)
					table.insert(noteLine, s)
					table.insert(noteColumn, c)
				end
			end	
		end

This runs every time something is changed in track. And it lags even with small number of rows and columns which is strange. Apparently I should make iterations less frequent.

Maybe I should make track change only on mouse release or it will not be convenient for user?

Wow, great work, seems you are a Lua expert to begin with:). If the piano roll works well then I think making it like FL Studio piano roll features would be a general good direction.

Actually I’m not Lua expert. This tool and the one I tried to make couple of years ago, were my only experience. I’m more experienced in c#.

As for features, I’d like to add, is selection and dragging multiple notes, drawing line of notes with fixed length.

But I’m more eager to add some unusual features like pitchbend visually shown and edited on piano roll. Although I don’t know how to visualize it, not beeing able to draw diagonal lines or stretching images.

One more thing that is first on my list after the problem with lags is solved, is a feature which normally doesn’t belong to piano rolls. So that you could change track playback position with a click in play mode. Independent from global play position. It shouldn’t be that hard.

noteTone = {}
noteLength = {}
noteLine = {}
noteColumn = {}
		
lineValues = song.selected_pattern.tracks[trackId].lines
		
local columns = song.tracks[trackId].visible_note_columns

for c = 1, columns do
for s = 1, steps do
local note = lineValues[s].note_columns[c].note_value
if note < 120 then --120 is off, 121 is empty
table.insert(noteTone, note)
table.insert(noteLine, s)
table.insert(noteColumn, c)
end
end	
end

For accessing some song values there is a faster way than the standard table indexing:

-- Access to a single line by index. Line must be [1-MAX_NUMBER_OF_LINES]).
-- This is a !lot! more efficient than calling the property: lines[index] to
-- randomly access lines.
renoise.song().patterns[].tracks[]:line(index)
 -> [renoise.PatternLine]

It is a method call so it uses the colon operator and curved parenthesis. You also lose the s , so

tracks becomes :track ()

lines becomes :line ()

columns becomes :column ()

etc.

So for your code above it becomes:

(see changes lines 7,9,13)

noteTone = {}
    noteLength = {}
    noteLine = {}
    noteColumn = {}
    
    lineValues = song.selected_pattern:track(trackId).lines --.tracks[] changed to :track() method
    
    local columns = song:track(trackId).visible_note_columns --.tracks[] changed to :track() method

    for c = 1, columns do
      for s = 1, steps do
        local note = lineValues[s]:note_column(c).note_value --.note_columns[] changed to :column() method
        
        if note < 120 then --120 is off, 121 is empty
          table.insert(noteTone, note)
          table.insert(noteLine, s)
          table.insert(noteColumn, c)
        end
      end  
    end

Should add some speed boost.

1 Like

Should add some speed boost.

Sorry, it didn’t help, but thanks. I’ll use this method just in case.

1 Like
  1. Here is another optimization, maybe not massive in most cases, but worth using as a rule IMO. table.insert is a table access in itself, which can be ‘cached’ (localized).
local table_insert = table.insert

for c = 1, columns do
 for s = 1, steps do
 local note = lineValues[s]:note_column(c).note_value --.note_columns[] changed to :column() method
 
 if note < 120 then --120 is off, 121 is empty
  table_insert(noteTone, note)
  table_insert(noteLine, s)
  table_insert(noteColumn, c)
 end
 end 
end
  1. Are you sure that this section is the culprit?

You are iterating 12 note columns, which is pretty heavy. There is a scheme that can be used to optimize this a lot, by using string functions on tostring(line) to extract the note values - thereby reducing the song() access to one access per line.

Sorry, it didn’t help, but thanks. I’ll use this method just in case.

Definitely worth doing as a rule in scripts, a shame it didn`t make much difference here though.

  1. Are you sure that this section is the culprit?

You are iterating 12 note columns, which is pretty heavy. There is a scheme that can be used to optimize this a lot, by using string functions on tostring(line) to extract the note values - thereby reducing the song() access to one access per line.

Hey joule, I`m just finally getting around to looking at your optimization stuff (and your mods to my Set Track Widths To Active Columns tool :blush: , better late than never eh :yeah: )

Maybe I`ll try and translate the method to a working example here…

  1. Are you sure that this section is the culprit?

Yes, I checked

You are iterating 12 note columns, which is pretty heavy. There is a scheme that can be used to optimize this a lot, by using string functions on tostring(line) to extract the note values - thereby reducing the song() access to one access per line.

Why 12?

As for ‘tostring’, are you sure that it is faster to get key, sign and octave from string and then transform them to number?

Why 12?

As for ‘tostring’, are you sure that it is faster to get key, sign and octave from string and then transform them to number?

My mistake. I didn’t notice that you don’t iterate all columns.

Yes, As soon as you’re iterating more than one column, there is a way to do it faster with string.sub et c.

EDIT: an example can be seen in this tool: https://forum.renoise.com/t/new-tool-2-7-3-1-set-track-width-to-active-columns/31078

PS. Btw, I just remembered… if you’re creating an indexed table, it’s even faster to do something like “table[#table+1] = new_value” instead of using table.insert.

Amazing :slight_smile:

  1. Are you sure that this section is the culprit?

Wow, you was right in your suspicions. And I was right before, when I thought that the problem is in XYpad.

In fact, there is no lag at all when “mouse warping” is enabled in preferences.

But, when it’s turned on, mouse cursor jumps to snapback position on button release

(Are you getting “too many updates”? I guess you’ll have to filter it all to only make a ‘big bang’ on relevant changes)

There was also a quirk when it comes to snapback that it will bang the value observable two times (for x and y). You’ll probably have to make some “timer gate” there to optimize that.

I’ve made changes, so track cells are not itterated when note is dragged, and I’m filtering first and last value of xypad. But it isn’t what mattered. Enabling “mouse warping” removed lag. But now

mouse cursor jumps to snapback position on button release

How to deal with this? I don’t suppose that cursor can be controlled from code

Nope…

My experience is that mouse warping has to be off for the xypad exploit to work. My mouse cursor moves horribly slow otherwise. There is some cause to the lag that you need to fix (mouse warping on is not a good solution). It’s difficult to guess the cause…

(Does the value_observable bang differently depending on mouse warp setting? It shouldn’t IMO… do a bit of print ‘debugging’ to compare what’s happening on and off respectively)