[Fixed 2.8] Trying To Access A No Longer Available Pattern_Line Note C

Hello

Here’s a little error that keep on bugging me. My code is long and requires some explanation, so I’m not posting it now, but of course I will if it’s necessary to get further.

I keep getting this error.

  
*** std::logic_error: 'trying to access a no longer available pattern_line note column.'  
*** stack traceback:  
*** [C]: ?  
*** [C]: in function '__index'  
*** [string "do..."]:12: in function   
*** main.lua:325: in function 'handle_note_button_press'  
*** main.lua:281: in function <258><br>```

<br>
<br>
It occurs randomly now and then, and after doing a lot of debug printing I have come to the conclusion that it's not a line in my code that is causing it.<br>
<br>
It has something to do with the usage of line notifier. <br>
<br>

```<br><br>
  local pattern = renoise.song().selected_pattern<br>
  if not (pattern:has_line_notifier(handle_line_notifier))<br>
  then<br>
    pattern:add_line_notifier(handle_line_notifier)<br>
  end<br>
<br>```

<br>
<br>
After my notifier function is called and it has carried out it's work and before anything else happens in my code this error shows up.<br>
<br>
Any clues?<br>
<br>
Thanks</258>

You are probably trying to access something that is no longer available once your routine is being given command.
Most of the notifiers are firing your routine before the action is taken (removed track or row in pattern or whatever) and your routine then enumerates then current content of the pattern contents and when your routine wants to provoke an action on it, the action that caused your notifier to fire your routine, has being executed meanwhile and removed a last track or line causing your routine perhaps attempting to access something that is no longer there.

You may need this solution:
http://www.renoise.c…335#entry251335

Vincent: This problem problem is not really related to the one you’ve linked to.

fredrik: Sorry, without more info, we can’t really help you here.

In other words, the error means that something is dereferencing/using a pattern line reference, which already got deleted.

Something like:

  
local line_ref = renoise.song().selected_pattern.tracks[1]:line(1)  
--- something deletes selected_pattern:line(1) here (can be your or some other script, the user - anything)  
line.note_columns[1].note_string="C-4" -> will fire an error  
  

Ok, thanks, I’ll give it a try to post some code. And please take the opportunity to correct other things im doing wrong.

This function is called when a certain midi message arrives. I want to remove the note if there is one or add one if there is none. (irrelevant parts are removed)

function handle_note_button_press(number)  
 current_note = number  
 local pattern_index = renoise.song().selected_pattern_index  
 local track_index = renoise.song().selected_track_index  
 local column_index = renoise.song().selected_note_column_index   
 local note_column = renoise.song().patterns[pattern_index].tracks[track_index].lines[current_step].note_columns[current_column]  
 if (note_column.note_value == current_note)  
 then  
 note_column.note_value = RENOISE_NOTE_EMPTY  
 else  
 note_column.note_value = current_note  
 note_column.instrument_value = current_instrument - 1  
 end  
end  
  

Then I have the line notifier that calls this function. So, the above function modifies the song making the line notifier to be called (irrelevant parts removed):

function handle_line_notifier(pos)  
 local pattern_index = renoise.song().selected_pattern_index  
 local track_index = renoise.song().selected_track_index  
 local note_column = renoise.song().patterns[pattern_index].tracks[track_index].lines[pos.line].note_columns[current_column]  
 local note_value = note_column.note_value  
  
 if (current_step == pos.line)  
 then  
 if not(note_value == RENOISE_NOTE_EMPTY)  
 then  
 send_midi(MIDI_NOTE_ON,note_value,127)  
 end   
 end  
  
end  
  

So, I have also other incoming midi commands that does other stuff. Now I’m thinking maybe one such command enters before the notifier is called/finished changing any of the variables?

Thanks for helping me out!

Ok, so I spent some time debugging and I finally managed to get rid of the error. I cannot see any fault in my code, but rather some kind of glitch in the scripting implementation.

The line that (sometimes, once every 50th time or so) gives the error is :

note_column.instrument_value = current_instrument - 1  

What happens before that line is:

note_column.note_value = current_note  

which triggers the line notifier.

If I don’t have the line notifier the error does not occur.

If i repeat this line before setting instrument:

local note_column = renoise.song().patterns[pattern_index].tracks[track_index].lines[current_step].note_columns[current_column]  

The error does not occur either…

I guess this part may then have been the real problem, your current note_column buffer may have been filled with old data by the time the notifier gets called.

Sorry for the late reply.

Found the problem now. The Lua garbage collector destroys the line references at a point where it should not. This actually has nothing to do with the pattern line notifier. It just makes the garbage collector run more often, because more stuff happens (more Lua objects are created).

This is also the reason why this error only pops up randomly: The garbage collector runs, when not called explicitly, every now and then, or not. Is not really predictable unless called explicitly.

Here is a way to replicate the problem every time:

  
local note_column = renoise.song().patterns[1].tracks[1].lines[1].note_columns[1]   
collectgarbage()  
note_column.instrument_value = 4 -- -> will fire an error  
  

Will need a bit of time to see how we can solve this. What happens internally here is that:
local note_column = renoise.song().patterns[1].tracks[1].lines[1].note_columns[1]
creates a temporary “line” object, which is no longer referenced anywhere, thus it is marked to be collected.
But the line object is still referenced internally by the “note_column” object. So as soon as the line gets collected, the column gets invalid too and will fire an error when accessed.

You can solve, hackaround, the problem for now via:

  
-- keep the line object referenced, avoid that it is being collected during the function call:  
local line = renoise.song().patterns[1].tracks[1].lines[1]   
local note_column = line .note_columns[1]   
note_column.note_value = math.random(48)  
collectgarbage()  
note_column.instrument_value = 4 -- -> should never fire an error now  
  

This has nothing to do with the error, but I wondered why you don’t use the “pos” in your “function handle_line_notifier(pos)”, but use the selected track and pattern there instead to query the changed line.
Lines do not necessarily change at the “selected” position in Renoise. You can clear a whole pattern, or undo/redo inserting, deleting them somewhere in the song. Aka, you can also edit notes that are !not! under the cursor.

To access the changed line in the notifier, instead of the line under the cursor, you can do this instead:

  
function handle_line_notifier(pos)  
 -- can also use the functions track(),pattern() instead of the table   
 -- accessors tracks[], patterns[] to speed up things. The tables create   
 -- tons of temporary objects we are not interested in  
 local line = renoise.song():pattern(pos.pattern):track(pos.track):line(pos.line)  
 print(("line at pos:%d,%d,%d changed to:"):format(pos.pattern, pos.track, pos.line))  
 print(line)  
end  
  

… and fixed the internal problem for the next release, so that:

  
local note_column = renoise.song().patterns[1].tracks[1].lines[1].note_columns[1]   
collectgarbage() -- or other stuff here  
note_column.instrument_value = 4  
  

will never fail.