Crash Renoise Everytime By Not Knowing What Im Doing

Hi! I’m able to crash Renoise now, continuously, repeatable every time, with a script. I was trying to combine multiple different functions from inside the Paketti tool compilation, as I was trying to accomplish a certain set of functions run one after the other, to accomplish certain things. I noticed that dblue had helped immensely with a pattern expander function, and decided to use that. What I got, was a crash.

Click to view contents
function resize_pattern(pattern, new_length, patternresize)  
 -- We need a valid pattern object  
 if (pattern == nil) then'Need a valid pattern object!')  
 -- Rounding function  
 local function round(value)  
 return math.floor(value + 0.5)  
 -- Shortcut to the song object  
 local rs =  
 -- Get the current pattern length  
 local src_length = pattern.number_of_lines   
 -- Make sure new_length is within valid limits  
 local dst_length = math.min(512, math.max(1, new_length))  
 -- If the new length is the same as the old length, then we have nothing to do.  
 if (dst_length == src_length) then  
 -- Set conversation ratio  
 local ratio = dst_length / src_length  
 -- Change pattern length  
 if patternresize==1 then   
 pattern.number_of_lines = dst_length  
 -- Source  
 local src_track = nil  
 local src_line = nil  
 local src_note_column = nil  
 local src_effect_column = nil  
 -- Insert a new track as a temporary work area  
 -- Destination  
 local dst_track = pattern:track(1)  
 local dst_line_index = 0  
 local dst_delay = 0  
 local dst_line = nil  
 local dst_note_column = nil  
 local dst_effect_column = nil  
 -- Misc  
 local tmp_line_index = 0  
 local tmp_line_delay = 0  
 local delay_column_used = false   
 local track = nil  
 -- Iterate through each track  
 for src_track_index = 2, #rs.tracks, 1 do  
 track = rs:track(src_track_index)  
 -- Set source track  
 src_track = pattern:track(src_track_index)  
 -- Reset delay check  
 delay_column_used = false  
 -- Iterate through source lines  
 for src_line_index = 0, src_length - 1, 1 do  
 -- Set source line  
 src_line = src_track:line(src_line_index + 1)  
 -- Only process source line if it contains data  
 if (not src_line.is_empty) then  
 -- Store temporary line index and delay  
 tmp_line_index = math.floor(src_line_index * ratio)  
 tmp_line_delay = math.floor(((src_line_index * ratio) - tmp_line_index) * 256)  
 -- Process note columns  
 for note_column_index = 1, track.visible_note_columns, 1 do  
 -- Set source note column  
 src_note_column = src_line:note_column(note_column_index)  
 -- Only process note column if it contains data   
 if (not src_note_column.is_empty) then  
 -- Calculate destination line and delay  
 dst_line_index = tmp_line_index  
 dst_delay = math.ceil(tmp_line_delay + (src_note_column.delay_value * ratio))  
 -- Wrap note to next line if necessary  
 while (dst_delay >= 256) do  
 dst_delay = dst_delay - 256  
 dst_line_index = dst_line_index + 1  
 -- Keep track of whether the delay column is used  
 -- so that we can make it visible later if necessary.  
 if (dst_delay > 0) then  
 delay_column_used = true  
 dst_line = dst_track:line(dst_line_index + 1)  
 dst_note_column = dst_line:note_column(note_column_index)  
 -- Note prioritisation   
 if (dst_note_column.is_empty) then  
 -- Destination is empty. Safe to copy  
 dst_note_column.delay_value = dst_delay   
 -- Destination contains data. Try to prioritise...  
 -- If destination contains a note-off...  
 if (dst_note_column.note_value == 120) then  
 -- Source note takes priority  
 dst_note_column.delay_value = dst_delay  
 -- If the source is louder than destination...  
 if (src_note_column.volume_value > dst_note_column.volume_value) then  
 -- Louder source note takes priority  
 dst_note_column.delay_value = dst_delay  
 -- If source note is less delayed than destination...  
 elseif (src_note_column.delay_value < dst_note_column.delay_value) then  
 -- Less delayed source note takes priority  
 dst_note_column.delay_value = dst_delay   
 end -- End: Note prioritisation   
 end -- End: Only process note column if it contains data   
 end -- End: Process note columns  
 -- Process effect columns   
 for effect_column_index = 1, track.visible_effect_columns, 1 do  
 src_effect_column = src_line:effect_column(effect_column_index)  
 if (not src_effect_column.is_empty) then  
 dst_effect_column = dst_track:line(round(src_line_index * ratio) + 1):effect_column(effect_column_index)  
 if (dst_effect_column.is_empty) then  
 end -- End: Only process source line if it contains data  
 end -- End: Iterate through source lines  
 -- If there is automation to process...  
 if (#src_track.automation > 0) then  
 -- Copy processed lines from temporary track back to original track  
 -- We can't simply use copy_from here, since it will erase the automation  
 for line_index = 1, dst_length, 1 do  
 dst_line = dst_track:line(line_index)  
 src_line = src_track:line(line_index)  
 -- Process automation  
 for _, automation in ipairs(src_track.automation) do  
 local points = {}  
 for _, point in ipairs(automation.points) do  
 if (point.time <= src_length) then  
 table.insert(points, { time = math.min(dst_length - 1, math.max(0, round((point.time - 1) * ratio))), value = point.value })  
 for _, point in ipairs(points) do  
 if (not automation:has_point_at(point.time + 1)) then  
 automation:add_point_at(point.time + 1, point.value)  
 -- No automation to process. We can save time and just copy_from  
 -- Clear temporary track for re-use  
 -- Show the delay column if any note delays have been used  
 if (rs:track(src_track_index).type == 1) then  
 if (delay_column_used) then  
 rs:track(src_track_index).delay_column_visible = true  
 end -- End: Iterate through each track  
 -- Remove temporary track  


What I’m trying to do is simple:
create a shortcut that:
writes current BPM / LPB setting to Master Track
clones current track to current pattern sequence
multiplies LPB by 2
writes BPM/LPB to cloned pattern Master Track
resizes cloned pattern by 2
expands pattern content by 2.

before utilizing a possibly legacy dblue expand script (pattern resizer), i was able to write lpb, multiply lpb, clone ptn, resize ptn length, write lpb. that’s quite allright, but then i decided to try and use what other things and tools ive added to paketti over the year or so, and came across these issues.

I always laugh at that typo, hah. Thanks to Erik (sharevari) for pointing it out a while ago. :P

I can’t see anything obvious at the moment in your crash log.

There shouldn’t be anything legacy about that function/script, either, as far as I know.

Apart from a very tiny change I made (the addition of the local rounding function) to make the resize_pattern() function totally self contained for usage in your tool, and your addition of the optional patternresize parameter, the source code is otherwise completely identical to the 2.8 API 3 version of my Pattern Resizer tool which is obviously working quite ok.

One thing, though: My resize_pattern() function does insert a new track to use as a temporary work area during the expanding/shrinking/etc. Do you possibly have some notifiers listening for tracks being added/removed, and you’re responding to that somehow? Maybe doing something that is somehow clashing with the other functionality in your clone and expand function?

Also, have you tried to simply run the resize_pattern() function directly on the pattern itself, to make sure that nothing weird is happening there? Would be nice to rule that out.

it says that the crash is on Audio…

i think it’s related to that add-track thing you do. i’m not sure what to do about that.

If it was related to that, then I would also expect it to happen when using my Pattern Resizer tool on its own. Can you give that a try? (I’m sure you must have already, but please try again just to be sure)

when i run just the pattern resizing doubler of yours i.e.
renoise.tool():add_keybinding {name=“Pattern Editor:Paketti:dblue Expand + Resize Pattern”, invoke =function()
local pattern =
resize_pattern(pattern, pattern.number_of_lines * 2,1) end}

it works without crashing. which is quite weird.

ok, further details, if you clonePTN and then resize and then writebpm, the cloneptn+patternresize somehow talk to eachother in such a way that it causes a crash.

the cloneptn is simply this:

function clonePTN()  
local currline=rs.selected_line_index  
local n_patterns = #rs.patterns  
local src_pat_i = rs.selected_pattern_index  
local src_pat = rs:pattern(src_pat_i)  
rs.selected_pattern_index = n_patterns + 1  
renoise.tool():add_keybinding {name = "Global:Paketti:Clone Current Pattern to Current Sequence", invoke = function() clonePTN() end}  

yes, i can:)

And what’s the exact code behind your write_bpm() function?

Quite hard to debug this without the exact code you’re working with now, and based on watching a damn youtube video :P

ok :)

edit:oops, here, added the get_master_track_index

function get_master_track_index()  
&nbsp; for k,v in ripairs(  
&nbsp; &nbsp; do if v.type == renoise.Track.TRACK_TYPE_MASTER then return k end &nbsp;  
&nbsp; end  
function write_bpm()  
 if < 256 then -- safety check  
 local column_index =  
 local[get_master_track_index()].visible_effect_columns = 2   
 if <= 1 then column_index = 2 end[get_master_track_index()].lines[1].effect_columns[1].number_string = "ZT"[get_master_track_index()].lines[1].effect_columns[1].amount_value = t.bpm[get_master_track_index()].lines[1].effect_columns[2].number_string = "ZL"[get_master_track_index()].lines[1].effect_columns[2].amount_value = t.lpb  

hi dblue, i decided to ditch using the pattern resizer code like this, and instead go for protman’s “expand selection” code. i got it to work, and it works pretty decently.

renoise.tool():add_keybinding {name="Global:Paketti:Clone and Expand Pattern to LPB*2", invoke=function()  
local number=nil  
local numbertwo=nil  
local nol=nil*2  
if number == 1 then number = 2 else end  
if number > 128 then number=128  
else end  

so now it writes current bpm+lpb to current pattern, clones pattern, lpb*2, writes bpm+lpb to cloned pattern, selects all in whole pattern, resizes pattern by *2, expands selection notes by *2, unmarks selection.

so you press one shortcut to go from LPB4 4 row pattern to LPB8 8 row pattern, and retain the content. since this doesn’t use your pattern resizing magic, the delay values are obviously wrecked, and effect_column content is not replicated across the new resolution, but it’s good enough, saves a lot of time.