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  
 renoise.app():show_status('Need a valid pattern object!')  
 return  
 end  
  
 -- Rounding function  
 local function round(value)  
 return math.floor(value + 0.5)  
 end  
  
 -- Shortcut to the song object  
 local rs = renoise.song()  
  
 -- 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  
 return  
 end  
  
 -- Set conversation ratio  
 local ratio = dst_length / src_length  
  
 -- Change pattern length  
 if patternresize==1 then   
 pattern.number_of_lines = dst_length  
end  
  
 -- 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  
 rs:insert_track_at(1)  
  
 -- 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  
 end  
  
 -- 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  
 end  
 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:copy_from(src_note_column)  
 dst_note_column.delay_value = dst_delay   
  
 else  
 -- 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:copy_from(src_note_column)  
 dst_note_column.delay_value = dst_delay  
  
 else  
  
 -- 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:copy_from(src_note_column)  
 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:copy_from(src_note_column)  
 dst_note_column.delay_value = dst_delay   
  
 end  
  
 end   
  
 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  
 dst_effect_column:copy_from(src_effect_column)  
 end  
 end  
 end  
  
 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)  
 src_line:copy_from(dst_line)  
 end  
  
 -- 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 })  
 end  
 automation:remove_point_at(point.time)  
 end  
 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)  
 end  
 end  
 end  
  
 else  
  
 -- No automation to process. We can save time and just copy_from  
 src_track:copy_from(dst_track)  
  
 end  
  
 -- Clear temporary track for re-use  
 dst_track:clear()  
  
 -- 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  
  
 end -- End: Iterate through each track  
  
 -- Remove temporary track  
 rs:delete_track_at(1)  
end  
  

[media]
http://www.youtube.com/watch?v=5hRHEHFk3T4
[/media]

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 = renoise.song().selected_pattern
resize_pattern(pattern, pattern.number_of_lines * 2,1) end}

it works without crashing. which is quite weird.
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 rs=renoise.song()  
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  
rs.patterns[rs.selected_pattern_index].number_of_lines=renoise.song().patterns[rs.selected_pattern_index-1].number_of_lines  
rs.selected_pattern:copy_from(src_pat)  
rs.selected_line_index=currline  
end  
  
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(renoise.song().tracks)  
&nbsp; &nbsp; do if v.type == renoise.Track.TRACK_TYPE_MASTER then return k end &nbsp;  
&nbsp; end  
end  
function write_bpm()  
 if renoise.song().transport.bpm < 256 then -- safety check  
 local column_index = renoise.song().selected_effect_column_index  
 local t=renoise.song().transport  
 renoise.song().tracks[get_master_track_index()].visible_effect_columns = 2   
  
 if renoise.song().selected_effect_column_index <= 1 then column_index = 2 end  
  
 renoise.song().selected_pattern.tracks[get_master_track_index()].lines[1].effect_columns[1].number_string = "ZT"  
 renoise.song().selected_pattern.tracks[get_master_track_index()].lines[1].effect_columns[1].amount_value = t.bpm  
 renoise.song().selected_pattern.tracks[get_master_track_index()].lines[1].effect_columns[2].number_string = "ZL"  
 renoise.song().selected_pattern.tracks[get_master_track_index()].lines[1].effect_columns[2].amount_value = t.lpb  
 end  
end  
  

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 rs=renoise.song()  
write_bpm()  
clonePTN()  
local nol=nil  
 nol=renoise.song().selected_pattern.number_of_lines+renoise.song().selected_pattern.number_of_lines  
 renoise.song().selected_pattern.number_of_lines=nol  
  
number=renoise.song().transport.lpb*2  
if number == 1 then number = 2 else end  
if number > 128 then number=128   
renoise.song().transport.lpb=number  
write_bpm()  
Deselect_All()  
MarkTrackMarkPattern()  
MarkTrackMarkPattern()  
ExpandSelection()  
Deselect_All()  
return  
else end  
renoise.song().transport.lpb=number  
write_bpm()  
Deselect_All()  
MarkTrackMarkPattern()  
MarkTrackMarkPattern()  
ExpandSelection()  
Deselect_All()  
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.