Work in progress: Piano roll


(frenetic_friend) #1

The topic of piano roll was raised on the forums more than once. So, that’s what I came up to after few days of trials.

It is still very laggy and buggy, but not hopeless I think. There are more features to implement.

Actually, I thought I can start a topic where I can show progress and ask technical questions too. Only after I uploaded demo video, I noticed that it is unadvised to do so. Well, still what do you think about it?


Piano Roll
[Suggestion] Use ALT + drag up/down with mouse for transpose notes
Piano Roll
Allow Free Movement of Active Row Hightlight/Cursor
(joule) #2

Awesome!

Some very small ideas:

  1. Checkbox for auditioning notes (via OSC server). The convention seems to be that notes are usually auditioned when they are inserted OR when their pitch changes.
  2. Notes in the same color as track colors. Even multi-track display/editing shouldn’t be too difficult implementing.

(danoise) #3

The moment you picked the “cut” tool and dragged part of a note upwards, I was like YEAAA.

You clearly laid out a very good foundation. Congrats!


(frenetic_friend) #4

Thank you!

Awesome!

Some very small ideas:

  1. Checkbox for auditioning notes (via OSC server). The convention seems to be that notes are usually auditioned when they are inserted OR when their pitch changes.
  2. Notes in the same color as track colors. Even multi-track display/editing shouldn’t be too difficult implementing.
  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.

  2. Ok, colors are not a problem. As for multi-track editing - maybe yes. But there are many higher priority goals.

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


(Ledger) #5

Amazing work!

bookmarked


(Circe) #6

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


(Raul (ulneiz)) #7

@frenetic_friend. I love this kind of surprises!

Looks great!!!

Courage with work! These kinds of tools are quite costly to implement. But it seems that you have it very advanced.I sense that this topic is going to fill a lot…


(TheBellows) #8

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!


(Raul (ulneiz)) #9

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 ^_^.


(Djeroek) #10

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


(joule) #11
  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’).


(Raul (ulneiz)) #12

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


(frenetic_friend) #13

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.


(M. Navas) #14

Looks promising. Looking forward to trying it out myself.

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


(encryptedmind) #15

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.


(frenetic_friend) #16

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.


(Ledger) #17
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.


(frenetic_friend) #18

Should add some speed boost.

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


(joule) #19
  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.


(Ledger) #20

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…