New Tool (2.8, 3.0): Flexible Pattern Resizer

Hi. I was looking at this (since you suggested I could just modify it so that keyboard shortcuts do *2(double) and *0.5 (halve) to the pattern content).
Got two buttons to work in the Gui, and they do as you would expect (32 -> 64… or 64 -> 32, and processing).

[details=“Click to view contents”] ```
vb:button {
height = 32,
text = ‘Double’,
notifier = function()
valuebox_length.value = adjust_pattern_length(2/1)
resize_pattern(valuebox_length.value)
end
},
vb:button {
height = 32,
text = ‘Halve’,
notifier = function()
valuebox_length.value = adjust_pattern_length(1/2)
resize_pattern(valuebox_length.value)
end
},

Emboldened by this, I thought, if it's this easy to do, a keyboard shortcut will be roughly as difficult.. Well, not quite ![:)](https://files.renoise.com/forum/emoticons/default/smile.gif)  

renoise.tool():add_keybinding { name=“Pattern Editor:Pattern:Halve”,
invoke = function()
local valuebox_length = nil
valuebox_length.value = adjust_pattern_length(1/2)
resize_pattern(valuebox_length.value)
end }

renoise.tool():add_keybinding { name=“Pattern Editor:Pattern:Double”,
invoke = function()
local valuebox_length = nil
valuebox_length.value = adjust_pattern_length(2/1)
resize_pattern(valuebox_length.value)
end }

  
End up getting a   
  
*** main.lua:298: attempt to index local 'valuebox_length' (a nil value)  
*** stack traceback:  
*** main.lua:298: in function <main.lua:296>  
  
How should the keybinding code be modified so that I can just stop thinking about alt-g and alt-f in schismtracker and just use them in renoise? ![:)](https://files.renoise.com/forum/emoticons/default/smile.gif)

Woo, got it working!
renoise.tool():add_keybinding { name=“Pattern Editor:Pattern:Halve”, invoke = function()
resize_pattern(adjust_pattern_length(1/2))
end }
renoise.tool():add_keybinding { name=“Pattern Editor:Pattern:Double”, invoke = function()
resize_pattern(adjust_pattern_length(2/1))
end }

thanks dBlue.

Would you please update this for 2.8? Thank you.

edit: ok, so I installed the current version and changed ApiVersion to 3. it seems to be working properly.

could you please update dblue?
pleeeeeeeeaaaase? :unsure:

Check the first post.

It simply slipped my mind, like many things these days.

awesome awesome! no worries, thanks sir!

This is great! If it hasn’t been said yet, it’d be good to have it be capable of changing a selection’s length independent of the pattern; this way you could stretch “live-played” elements to fit for any bpm.

also: I think percentages would be pretty helpful in a context like that.

Hey dblue,

there is one bug in the PatternResizer tool: If a automation point is on the very last position of a pattern (so the same position as the first in the next pattern), this point will be erased while a pattern shrink.

there is one bug in the PatternResizer tool

Nicely spotted. Looks like a pretty simple fix, but I’ll try to give it a bit more testing today.

Thanks, here maybe another one, or some priority thing:

If I shrink this track from 128 to 64 bars:

Attachment 5512 not found.

it looks like this after shrinking:

Attachment 5513 not found.

So instead of taking the F#4 for the second note, it takes the third and offsets it. Surely this is coded right, but wouldn’t be the F#4 expected instead, since it has a higher rhythmical priority? Even > uneven?

Thanks, here maybe another one, or some priority thing: (…)

In situations where two notes would collide in the smaller sized pattern, and one note must therefore be deleted due to space constraints, it will first give priority to notes that are louder (70 vs 40 in your example), or, if both volumes are the same, then it will give priority to the note which ends up with the least amount of note delay.

There are of course many other ways to handle this kind of thing, and some extra options in the tool itself would be great.

Ideally, the tool would not simply throw away those “in between” notes in the first place, but would instead create new note columns for them whenever possible.

As usual, this is all just crap that’s been saved in my todo.txt somewhere for a long time :wink:

Ideally, the tool would not simply throw away those “in between” notes in the first place, but would instead create new note columns for them whenever possible.

That would satisfy everybody! +1

Version 1.06 now available for Renoise 2.8 and 3.0

No major new features. Just fixed this automation bug reported by Jurek.

Downloads in the original post.

Awesome tool, Thanks dblue!

Hey I didn’t know that Renoise can expand/shrink by itself. Why nobody told me? Apple + F8 / Apple + F9…

This is great!

This is great!

But attention, better use this tool instead renoise internal for now, since the internal has bug. This tool is already fixed.

EDIT:

dblue, I hope that you don’t mind if I place a little extended version of your pattern resizer tool here:
Attachment 6440 not found. (UNOFFICIAL TEST VERSION)

Basically I added two more shortcuts, “resize x2” and “resize x0.5”. These are meant as replacement shortcuts for the Renoise’s internal expanding/shrinking (Command + F8 / Command + F9), since those are buggy.

It also retains cursor position while playing at least. And auto-fixes LPB.

EDIT: Added dblue’s fixes from below.

Edit2: will add a better lpb autofix soon, that actually works with multiple times usage :stuck_out_tongue:

Arg, sorry still throws sometimes an error, if expanding from last pattern line…? I don’t geddit, how set start_at properly… start_at starts with 1,renoise.song().selected_line_index with 0?

I don’t mind too much if you make edits, but if you do plan to release it publicly then please make it very obvious that it’s a modified version by you, and not the original version by me. People should be aware which exact version they are using, just to avoid confusion. If you want to incorporate my pattern resizing functions into your own tool, that’s also totally fine as long as proper credit is given :slight_smile:

Regarding your line index bug, the pattern lines are indexed starting from 1 in the Lua API, not from 0.

To compensate for that in your calculations, first subtract 1 from the selected index, then multiply or divide it, then add 1 back to the result.

-- Expand
local sli = ((renoise.song().selected_line_index - 1) * 2) + 1

-- Shrink
local sli = ((renoise.song().selected_line_index - 1) / 2) + 1

You’re also missing quite a bunch of sanity/safety checks in your modified code, so it’s very easy to expand/shrink everything to some invalid LPB, invalid line index, and so on. Exactly how you prefer to handle this is up to you, but you can simply wrap your calculations with math.min() and math.max() to apply some crude range limiting.

local sli = math.max(1, math.min(renoise.song().selected_pattern.number_of_lines, ((renoise.song().selected_line_index - 1) * 2) + 1 ))

I took the liberty of modifying your functions to include these changes.

renoise.tool():add_keybinding {
  name = "Pattern Editor:Pattern:Resize x2",
  invoke = function()
  
    -- Reference to song
    local rs = renoise.song()
  
    -- Resize pattern
    resize_pattern(rs.selected_pattern, adjust_pattern_length(2))
    
    -- Adjust selected line index
    local sli = rs.selected_line_index
    local max_lines = rs.selected_pattern.number_of_lines
    local new_sli = math.max(1, math.min(max_lines, ((sli - 1) * 2) + 1 ))
    rs.selected_line_index = new_sli
    
    -- Adjust LPB
    local t = rs.transport
    t.lpb = math.max(1, math.min(256, t.lpb * 2))
    
    -- Move transport to the new position and resume/stop playback
    local playing = t.playing
    t:start_at(new_sli)
    if (not playing) then t:stop() end
    
  end 
}

renoise.tool():add_keybinding {
  name = "Pattern Editor:Pattern:Resize x0.5",
  invoke = function()
  
    -- Reference to song
    local rs = renoise.song()
   
    -- Adjust selected line index
    local sli = rs.selected_line_index
    local max_lines = rs.selected_pattern.number_of_lines
    local new_sli = math.max(1, math.min(max_lines, ((sli - 1) / 2) + 1 ))
    rs.selected_line_index = new_sli
    
    -- Adjust LPB
    local t = rs.transport   
    t.lpb = math.max(1, math.min(256, t.lpb / 2))
    
    -- Move transport to the new position and resume/stop playback
    local playing = t.playing
    t:start_at(new_sli)
    if (not playing) then t:stop() end
    
    -- Resize pattern
    resize_pattern(rs.selected_pattern, adjust_pattern_length(1/2))
    
  end 
}

There are other things you might consider, like preventing the entire expand/shrink operation if the LPB or other values would theoretically go out of bounds, but I leave that up to you.

All in all, these are pretty good additions, so I will likely include some variation of them in my original tool… if I ever get around to updating the damn thing!