Check If Track Device Has Been Deleted

If I do this:

>>>test=renoise.song().tracks[1].devices[2]  

And then delete device 2 on track 1 I get this:

>>>oprint(test==nil)  
false  
>>>oprint(renoise.song().tracks[1].devices[2]==nil)  
true  

The track device has disappeared but the variable test is still there. If i try to access any members of test I get an error.

Is there any test I can perform on the test variable to see if its still “valid”. If not is there a way to create a real pointer (something that would point to nil when the original object is deleted.)

I think the variable is waiting to get garbage collected, and therefore, you can’t rely on such indirect references as they’ll sometimes work, sometimes not.

Any particular reason you can’t just reference the index (2) ?

I want to be able to save instruments and tracks devices, and get the same ones back, even if I reorder the track devices in a track or the instrument numbers.

Trying to make a keyboard shortcut to toggle all open external editors on and off.

I messed around and could never garbage collect “test” so I’m not sure what’s going on. Test is a copy instead of a reference?

Another observation, didn’t want to start a new thread:

  
$ rprint(renoise.song().tracks[1].available_devices)  
[1] => Audio/Effects/ Native/Bus Compressor  
[2] => Audio/Effects/ Native/Cabinet Simulator  
[3] => Audio/Effects/ Native/Chorus  
[4] => Audio/Effects/ Native/Comb Filter  
[5] => Audio/Effects/ Native/Compressor  
[6] => Audio/Effects/ Native/DC Offset  
[7] => Audio/Effects/ Native/Delay  
...  
[119] => Audio/Effects/VST/TAL-Dub  
[120] => Audio/Effects/VST/TAL-Dub-2  
[121] => Audio/Effects/VST/TAL-Dub-3  
[122] => Audio/Effects/VST/TAL-Reverb-2  
[123] => Audio/Effects/VST/TRackS1.x  
[124] => Audio/Effects/VST/TRackS1.xClipper  
[125] => Audio/Effects/VST/TRackS1.xCompressor  
[126] => Audio/Effects/VST/TRackS1.xEqualizer  
[127] => Audio/Effects/VST/TRackS1.xLimiter  
[128] => Audio/Effects/VST/Trash  
  

What are those tabs doing in Native devices? The name requires a tab?

-=-=-

In fact, I remember Taktik saying the following:

> Source

Unfortunately its a bit more complicated. Those things are references, but they never will be garbage collected in Lua. They will stay valid in terms of being ~= nil, but are dead references which fire errors when using them.

I hoped to find a way to set such refs to nil from within Renoise, as soon as they are dying, but unfortunately found no way to do so until now.

And what I said in the quote, only applies to tables of basic types (strings, numbers, booleans) in the API.


Ideally, one should attach to the song, in order to get notified as soon as a track got removed. Often you have to do more than setting some temp value to nil, but for example also need to update your GUI or do other house keeping. For tracks, you can do so by attaching to renoise.song().tracks_observable:

  
local some_track_ref = renoise.song().tracks[2]  
  
renoise.song().tracks_observable:add_notifier(function(notification)   
 if (notification.type == "remove") then  
 -- a track got deleted. invalidate / update all track refs here  
 end  
end)  
  

But if you want to find out which object got deleted, this is right now very tedious, cause the tracks_observable notifier will be called AFTER the track already got removed. So you have no chance in finding out if “some_track_ref” is the one that got deleted. This would only work by making a copy of renoise.song().tracks and syncing it with ALL tracks_observable notifications (insert(remove/swapped). Then checking your track refs against the tracks table copy.

So right now, the only thing you can do is invalidating ALL your track refs as soon as got a “notification.type == “remove””.


To solve this, and make such tasks a bit more easy in general (its not only about track but also about everything else that’s in lists), I’ve got a patch laying around here, which allows testing if any object in the Renoise API is valid. Checks if some object is a valid reference:

my_track_ref.valid, my_parameter_ref.valid and so on.

With this, you could without attaching to tracks_observable (and others), simply check everywhere before using an object if its still alive:

  
if (my_track_ref and my_track_ref.valid) then  
 -- track is still there, do something  
else  
 -- track was deleted. do nothing or invalidate:  
 my_track_ref = nil  
end  
  

This “valid” property is a bit strange though. making it a global function, like:
valid_object(my_track_ref) – return false for nil or dead Renoise object references

might be a bit better, but conceptional its far from being obvious and pretty.


Another way to solve the problem with notifiers, is passing the currently deleted object to tracks_observable (and others).
This way you can at least quickly check if “your” objects got removed:

  
local some_track_ref = renoise.song().tracks[2]  
  
renoise.song().tracks_observable:add_notifier(function(notification)   
 if (notification.type == "remove") then  
 if (rawequal(some_track_ref, notification.object)) then  
 -- something deleted my 'some_track_ref'  
 end  
 end  
end)  
  

Cortex:

for now, you’ll have to do:

  
renoise.song().tracks_observable:add_notifier(function(notification)   
 if (notification.type == "remove") then  
 -- a track got deleted. invalidate / update ALL track refs here  
 end  
end)  
  

Need to think about the other ways of dealing with dead refs a bit before doing anything.

Ok, thanks for the explanation.

In the notifier for devices_observable there is no info about which track triggered the event. How can I get around this limitation? I think that in most situations where one want to keep track of changed devices, one would also need to know on which track they occurred.

One way would be to create a function for every track number but this gets a bit complicated when adding and deleting tracks.

Also is there any way to delete a notifier function without having a reference to it? (So you can remove a a notifier function that was added as an anonymous function).